window.getComputedStyle give the style's value in Chrome, but in firefox and Microsoft Edge it gives an empty string and in Internet Explorer, it say that it doesn't support that method. Here is my code.
Whenever the Upvote image is clicked it fires the upDownVote() function, passing two arguments. This is the HTML.
<div id="upvote" title="Click to UpVote" onClick="upDownVote('increment',<?php echo $id; ?>);"></div>
<div id="downvote" title="Click to DownVote" onClick="upDownVote('decrement',<?php echo $id; ?>);"></div>
I passed three variables to my php script through ajax; Id, type, applicable.
Type can store one value, either increment or decrement.
I wanted, even upvote button is clicked. Vote value is increase by 1 and background of button is changed. Same for the button downvote, but here is decrease in vote value. I handle this with type variable.
When upvote is clicked again (or double clicked by the user), then there must be decrement in vote value not increment. I handled this with a nested if condition inside the if condition (when type is increment). In that condition I checked if applicable is greater than one. If it is, I changed the type to decrement and applicable to 0, also the background to its original image.
But what if when user clicked the upvote button after the clicking the downvote button. In that condition applicable value is more than 1. And then must change the type to decrement. That should not happen. for this In my that nested if condition I add check the background of downvote button also. It must be the same as before when the page load.
when applicable value is more than 1 (when user clicked upvote before clicking the downvote). In my php script I increase the vote value by two.
Same logic for the downvote button.
and here is the JavaScript.
var applicable = 0; // determine applicable to vote or not.
var upvote = document.getElementById("upvote");
var downvote = document.getElementById("downvote");
var upvoteBlack = window.getComputedStyle(upvote).getPropertyValue("background");
var downvoteBlack = window.getComputedStyle(downvote).getPropertyValue("background");
function upDownVote(x, id) {
debugger;
var type = x; // determine the type(increment or decrement).
if (type === "increment") {
upvote.style.background = "url(img/image-sprite-1.jpg) 0px -40px";
applicable++; // increment in the applicable.
if (applicable > 1 && window.getComputedStyle(downvote).getPropertyValue("background") === downvoteBlack) {
type = "decrement";
applicable = 0;
upvote.style.background = "url(img/image-sprite-1.jpg) 0px 0px";
}
downvote.style.background = "url(img/image-sprite-1.jpg) -40px 0px";
} else {
downvote.style.background = "url(img/image-sprite-1.jpg) -40px -40px";
applicable++;
if(applicable > 1 && window.getComputedStyle(upvote).getPropertyValue("background") === upvoteBlack) {
type = "increment";
applicable = 0;
downvote.style.background = "url(img/image-sprite-1.jpg) -40px 0px";
}
upvote.style.background = "url(img/image-sprite-1.jpg) 0px 0px";
}
// Ajax started here.
}
CSS of upvote and downvote.
div#upvote {
width: 40px;
height: 40px;
background: url(../img/image-sprite-1.jpg);
background-position: 0px 0px;
margin: 0px auto;
margin-top: 10px;
cursor: pointer;
}
div#downvote {
width: 40px;
height: 40px;
background: url(../img/image-sprite-1.jpg) -40px 0px;
background-position: -40px 0px;
margin: 0px auto;
cursor: pointer;
}
Everything works fine but now I'm stuck. How to get the background value of buttons as window.getComputedStyle not working fine all the browsers.
I want to know is there any other property by which I can have the background property.
Also, I want to know how can I do the same thing with different logic. If I can't have the solution for window.getComputedStyle.
The shorthand property problem
background is a shorthand property, a combination of background related properties. When you set a background of pink, it is actually setting a number of background properties, just one of which is backgroundColor. For instance, it is probably actually doing the equivalent of rgb(255, 165, 0) none repeat scroll 0% 0% / auto padding-box border-box.
getComputedStyle will not return the value of shorthand properties, except in Chrome as you've discovered.
To get the computed style, look for the value of primitive properties such as backgroundColor, not that of shorthand properties such as background.
A different approach?
However, this is not really how you want to be doing things. Instead of setting styles on your elements directly, you're going to find your code to be much cleaner if you add and remove classes from your elements, and then define the rules for the classes. As you've found, setting styles directly on elements may require you to then go back and query the style, whereas with classes, you can easily query the existing class with elt.classList.has(), or toggle with .toggle(), or add, or remove.
More on getComputedStyle
getComputedStyle is a rather specialized API that should only be necessary in special situations.
For more on the issue of getComputedStyle and shorthand properties, see this question. A bug was reported against FF and you can find it here.
See this MDN page. It says that CSSStyleDeclaration (which is what is returned by getComputedStyle) has a getPropertyCSSValue method which
returns ... null for Shorthand properties.
Related
I'm trying to re-create an Instagram like sort of page with some jQuery included. This is for a course I'm taking, so I'm a student basically.
This particular part of the exercise is asking me to:
- Empty the content of a class div.
- iterate over the media that is given.
- create an empty div and assign two classes, background image and append to the "empty" class.
The code I have so far is the following:
function renderUserMedia (media) {
// The class that is being emptied.
$('.user-media').html('');
// iteration
media.forEach(function (mediaItem) {
// empty div to add to every iterated picture with whatever is needed
var div = $('<div>').addClass('user-media-item u-pull-left').css('background-image', mediaItem).appendTo('.user-media');
});
}
All media is fetched through an API which I have no idea how is being configured (school configuration and what not), and the media is from a "dummy" insta page I guess.
What's happening is that images are not happening on the browser, and I think it has something to do with the .css implementation of the images iterated. The property background-image does not exist in the css file, so there might be something going on.
I have also tried to append to '.user-media' with $('.user-media').append(div); on the next line, but it didn't produce the desired result, which is to have all pictures iterated from forEach with the '.user-media-item' class.
.user-media-item {
margin-right: 10px;
margin-bottom: 10px;
width: 230px;
height: 230px;
overflow: hidden;
background-repeat: no-repeat;
background-size: cover;
background-position: center;
}
Could someone please help me understand what am I doing wrong?
After having checked everything and not being able to retrieve images, the only needed thing was (thanks to #freedomn-m and #CBroe for directions) to include the actual key that holds the location of the file. In this case a local folder.
function renderUserMedia (media) {
$('.user-media').html('');
media.forEach(function (mediaItem) {
var div = $('<div>').addClass('user-media-item u-pull-left').css('background-image', 'url(' + mediaItem.media_url + ')').appendTo('.user-media');
});
}
In case of using the url key, then we should change to .css('background-image', 'url(' + mediaItem.permalink + ')') as it was showing in the object containing the info of the images.
I am experimenting (might be foolhardy) with reproducing in CSS what Douglas Crockford refers to as a bottom value.
What's a bottom value?
In Javascript, bottom values are undefined and null.
I can take a custom-data attribute:
data-my-custom-attribute=""
and I can give it a value of null (using Unicode U+2400):
data-my-custom-attribute="␀"
In CSS, I can then reference any custom-data attribute which is null:
[data-my-custom-attribute="␀"] {
[... CSS PROPERTIES HERE...]
}
Next up, I'd like to deploy an equivalent to this Javascript:
if (myCustomAttribute !== null) { ... }
But it seems I can't reference any custom-data which isn't null, because something like this:
[data-my-custom-attribute!="␀"] {
[... CSS PROPERTIES HERE...]
}
doesn't work and isn't valid.
Having established that:
[data-my-custom-attribute!="␀"]
doesn't work, it occurs to me that:
[data-my-custom-attribute]:not([data-my-custom-attribute="␀"])
actually does work (and if nothing else comes up, I'll stick with that).
Working Example:
div {
display: inline-block;
width: 100px;
height: 100px;
margin-right: 12px;
}
.rectangle {
display: block;
width: 450px;
height: 60px;
margin-top: 12px;
background-color: orange;
}
[data-my-custom-attribute="red"] {
background-color: red;
}
[data-my-custom-attribute="yellow"] {
background-color: yellow;
}
[data-my-custom-attribute="blue"] {
background-color: blue;
}
[data-my-custom-attribute="␀"] {
border-radius: 0;
background-color: black;
}
[data-my-custom-attribute]:not([data-my-custom-attribute="␀"]) {
border-radius: 50%;
}
<div data-my-custom-attribute="red"></div>
<div data-my-custom-attribute="yellow"></div>
<div data-my-custom-attribute="blue"></div>
<div data-my-custom-attribute="␀"></div>
<div class="rectangle"></div>
However,
[data-my-custom-attribute]:not([data-my-custom-attribute="␀"])
feels awkward and verbose. Is there really nothing better?
Right. Conclusions.
Just as there already exist in CSS the following attribute selectors:
[data-attribute="value"] // has data-attribute, the value of which is value
[data-attribute^="value"] // has data-attribute, the value of which begins with value
[data-attribute*="value"] // has data-attribute, the value of which contains value
[data-attribute$="value"] // has data-attribute, the value of which ends with value
I was hoping there might be something like:
[data-attribute!="value"] // has data-attribute, the value of which is not value
and then, by extension:
[data-attribute!^="value"] // has data-attribute and its value doesn't begin with value
[data-attribute!*="value"] // has data-attribute and its value doesn't contain value
[data-attribute!$="value"] // has data-attribute and its value doesn't end with value
But, instead we only have:
:not([data-attribute="value"]) // value is not value OR no data-attribute
:not([data-attribute^="value"]) // value doesn't start with value OR no data-attribute
:not([data-attribute*="value"]) // value doesn't contain value OR no data-attribute
:not([data-attribute$="value"]) // value doesn't end with value OR no data-attribute
So the only way to get rid of the alternative possibilities (ie. after logical OR) is:
[data-attribute]:not([data-attribute="value"]) // data-attribute value is not value
[data-attribute]:not([data-attribute^="value"]) // value doesn't begin with value
[data-attribute]:not([data-attribute*="value"]) // value doesn't contain value
[data-attribute]:not([data-attribute$="value"]) // value doesn't end with value
Unfortunately, there isn't a more concise way. Even jQuery's [att!=val] selector, which has remained exclusive to jQuery all these years, doesn't require that the attribute be present to match, so you'd still need to pair that with [att].
I understand this is an experiment with the bottom value concept, but for the sake of completeness I'll add that the closest things to a null attribute value in HTML (and by extension CSS) are either the empty string (the default value of custom data attributes), or the lack of the attribute entirely. The idiomatic way to achieve your desired result is to choose either the empty string or omission of the attribute altogether, and use a corresponding [data-my-custom-attribute=""] or :not([data-my-custom-attribute]) selector respectively in CSS, and if (myCustomAttribute === "") or if (("myCustomAttribute" in myDiv.dataset) === false) respectively in JS.
I have a sidebar, and I want to use javascript to check when it is 'active'. Here's my code:
#sidebar {
background: #202020;
color: #fff;
display:inline-block;
}
#sidebar.active {
margin-left: -250px;
}
//Check to see whether sidebar has class 'active'
var sideBar = document.getElementById('sidebar')
console.log(sideBar.className)
if (sideBar.className == ('active')){
console.log('active')
}
else (console.log('not active'))
However, this code is not console.logging anything, and so it's reading "not active" even when the sidebar is clearly activated. What am I doing wrong? Thanks.
The problem you are observing is probably because you compare sidebar.className == ('active') directly. The className attribute is a string object which contains the names of all of the classes applied to it. In many cases, there are extra classes automatically added (from various libraries), so checking if it's equal to a single class name often won't do what you want.
The classList attribute is a DOMTokenList and can more reliably be used for this kind of task. So, for this use case, you could try using sidebar.classList.contains('active').
i.e.
var sideBar = document.getElementById('sidebar');
console.log(sideBar.className)
if (sideBar.classList.contains('active')){
console.log('active')
}
else (console.log('not active'))
When loading page into browser everything looks fine and the background-image is correct. But when I click on the icon and the javascript changes the class of the icon to .icon-myapp-cow the css from [class^="icon-myapp"] is ignored. Only the css from icon-myapp-cow is applied. Tested in chrome and IE9
My css
[class^="icon-myapp"] {
background-image: url("../img/myapp-icons.png");
}
.icon-myapp-horse {
background-position: -1px -1px;
height: 15px;
width: 15px;
}
.icon-myapp-cow {
background-position: -51px -1px;
height: 15px;
width: 15px;
}
My html
<i class="icon-myapp-horse icon-clickable"></i>
My javascript
$(".icon-clickable").click(function() {
$(this).removeClass("icon-myapp-horse");
$(this).addClass("icon-myapp-cow");
});
You need to change [class^="icon-myapp"] to:
[class*="icon-myapp"]
See here for some more information, and here for a fiddle
[attr^=value]
Represents an element with an attribute name of attr and whose value is the (sic) prefixed by "value".
[attr*=value] Represents an element with an attribute name of attr and
whose value contains at least one occurrence of string "value" as
substring.
Change the ^ to *
When you remove the class icon-myapp-horse and then add icon-myapp-cow this newly added class is appended to the class names so the new set of classes look like icon-clickable icon-myapp-cow hence it does not start with icon-myapp
http://jsfiddle.net/Pj3d5/1/
So I am trying to figure out how to change the colour of the container div by using a javascript toggle button, but I think I am missing something obvious when trying to get the div to work in the statement. When I run the code and press the toggle button nothing happens. Thank you!
<!DOCTYPE html>
<head>
<style>
body {
}
#container {
height: 300px;
width: 500px;
background: lightblue;
position: absolute;
float: center;
text-align: center;
}
h1 {
font-size: 50px;
font-family: sans-serif;
}
#button {
font-size: 30px;
}
</style>
<script>
function toggleColour()
{
if (document.getElementById('container').style.background == ("lightblue"))
{
document.getElementById('container').style.background = ("orange");
}
else
{
document.getElementById('container').style.background = ("lightblue");
}
}
</script>
<body>
<div id="container">
<h1>Lets button this up!</h1>
<button type="button" id="button" onclick="toggleColour()">Toggle Colour</button>
</div>
</body>
Three things:
background is a shorthand CSS property that combines many background properties together (see the list here). If you set the background color using just background you still need to read the result from background-color (and you should use that in the CSS as well if it's the only background property you're setting).
lightblue and orange are also shorthands for RGB codes. Most browsers (if not all?) return the RGB values (e.g. rgb(173, 216, 230) for lightblue) even if the color is set using the color's name.
.style in JavaScript doesn't return styles applied by CSS, only those applied directly with the element's style attribute. You need to use window.getComputedStyle() instead.
In this case it'd be much simpler to just assume the background color's starting status and use a flag to keep track of it.
var bg = 'lightblue';
function toggleColour()
{
if( bg === "lightblue" )
{
bg = "orange";
}
else
{
bg = "lightblue";
}
document.getElementById('container').style.background = bg;
}
Note that you don't need parentheses around string literals and it's good form to use the strict === for comparison.
#Bergi is right. To get the resulting style for an element (come it from CSS or from inline style) you would use getComputedStyle with real browsers (Chrome, Firefox, Safari, Opera, and IE9) and currentStyle with IE prior to version 9.
Your problem is that the .style property only does reflect the style attribute of the element (which is empty), not all the styles that are applied on it via CSS. Therefore, on the first click the .style.background is empty, and will be set to an explicit "lightblue" (which you don't see). On the second click, it is set now and satisfies the if-condition so that it will be changed to "orange".
What you can do:
Use getComputedStyle to get the actual value. Yet, it initially would be rgb(173, 216, 230) not lightblue so a cross-browser solution is not easy.
Just swap the condition: If it is orange then set it to blue, else (if it is blue or nothing) set it to orange. (demo)
Set the style attribute to a start value in the HTML (demo)