JavaScript NaN error when trying to detect CSS property "left"? - javascript

This question piggy backs off of a question I asked yesterday. That question was:
"if" statement parameters not functioning as intended. JavaScript
But now i'm Getting a NaN error when I implement the following code:
var targetBoxLeft = parseFloat(document.getElementById("targetBox").style.left);
bulletOne.style.left = bulletOneLeft;
if (bulletOneLeft > targetBoxLeft){
document.getElementById("targetBox").style.opacity = "0";
};
Yesterday I didn't use "parseFloat", however my question is, if i'm specifically describing the parameter of targetBoxLeft as a CSS style.left property; why wouldn't that be a specific number? and why wouldn't it take on the number of left: 310px; as specified by the elements properties itself?
#targetBox{
position: absolute;
background-color: green;
height: 20px;
width: 20px;
top: 30px;
left: 310px;
opacity: 1;
}
Logically should the following 2 lines of code detect ACTUAL numbers?;
var bulletOneLeft = bulletOne.style.left;
var targetBoxLeft = targetBox.style.left;
And then once the above variables are detected as actual numbers, should the following if statement code be able to compare them depending on their values at any given time if movement(bulletOneLeft++;) is involved?:
if (bulletOneLeft > targetBoxLeft){
document.getElementById("targetBox").style.opacity = "0";
};
Im not exactly sure whats happening but since i'm getting a NaN error for when targetBox.style.left is read by the code i'm guessing that maybe a CSS property needs additional code to be converted into an actual number/variable before I run the if statement with corresponding VAR's?

You are querying the .style.left property, which is not the same as computed style. .style property of element references style attribute value. parseFloat("") returns NaN. Use window.getComputedStyle()
var div = document.querySelector("div");
console.log(div.style.left, parseFloat(div.style.left));
console.log(parseFloat(window.getComputedStyle(div).getPropertyValue("left")));
div {
position: relative;
left:310px;
}
<div>div</div>

Related

Get element's resolved height CSS property value; recognize 100%

The values returned by getComputedStyle are resolved values. These are usually the same as CSS 2.1’s computed values, but for some older properties like width, height, or padding, they are instead the same as used values.
-- MDN: window.getComputedStyle() notes
So is it currently possible to get the resolved value of height as it was specified in stylesheet?
I.e. know that some element's computed ..px (= used) height was specified as height: 100%; in style sheet? (100% being the resolved value in question.)
Is there some new specification regarding this problem in consideration?
Edit 2020-08-17: see very similar question and excellent answer from 2012: Is there a cross-browser method of getting the used css values of all properties of all elements?
(Sadly, noting seem to ave changed since then.)
No, there is no specification or functionality that supports or enables this method. There are plenty of ways to go the other direction, including...
getBoundingClientRect()
offsetHeight
getComputedStyle
... but none that will retrieve the exact percentage specified in the CSS, unfortunately.
You can try, as I've done below.
RegEx
If your height is specified as an inline style, you could RegEx it out of the attribute like so1:
let elem = document.getElementsByTagName("div")[0];
let re = /(?<=\height:\s+?)[^\;]+/i;
console.log(re.exec(elem.getAttribute("style"))[0]);
<div style="color: black; height: 100%; background: white;"></div>
This is terrible practice, though, and could be janky if there are multiple width declarations (which should never happen, but we're already in "bad code land", so why not?). Of course, this ignores the fact that inline styles should generally be avoided in the first place, so this probably won't apply to you.
Bounding calculations
It's also possible to calculate the value yourself by comparing the height of the element with the height of its parent.
let elem = document.getElementById("inner");
let pare = elem.parentElement;
let hrat = `${100*(elem.offsetHeight / pare.offsetHeight)}%`;
console.log(hrat);
#container {
height: 300px;
width: 400px;
background: repeating-linear-gradient(45deg, rgba(255,0,0,0.35), rgba(255,0,0,0.35) 10px, rgba(255,0,0,0.1) 10px, rgba(255,0,0,0.1) 20px), linear-gradient(white, white);
}
#inner {
height: 200px;
width: 400px;
background: darkgreen;
mix-blend-mode: hue;
}
<div id="container">
<div id="inner"></div>
</div>
If you add borders, margin, or padding, or the element adapts to the size of its content, though, this calculation will be incorrect.
Conclusion
In conclusion, everything is jank.
In my opinion, you'd be better off not fighting with CSS and JavaScript to coerce the value from the available information, and working out a way to do without the value. I've tried to do this kind of thing many times, so be forewarned: this way lies madness.
1RegEx lookbehinds are not even remotely close to being fully supported, so shouldn't be used in production.
You could read the stylesheet rule itself. If you know the selector that sets an elements width/height you can do this:
.box {
width: 12vw;
background: red;
}
<div class="box">red</div>
var sheet = document.styleSheets[0];
var rules = sheet.rules;
for (var i = 0; i < rules.length; i++) {
if (rules[i].selectorText == '.box') {
console.log(rules[i].style.width);
}
}
This will give you the 12vw you're looking for.
Depending on how your elements are defined, you could in theory create a helper function that gets these values for you by looping through the elements classList.

How to get computed style and the source of this rule? [duplicate]

This question already has answers here:
Find all CSS rules that apply to an element
(10 answers)
Closed 5 years ago.
I want to get the element computed style and the css (file and line) that applies that rule. Similar to what Chrome Dev Tools does when the "Computed" tab is used and you click on that arrow beside the value.
In short, I want to be able to, using javascript, find out these two things:
What is the CSS value that is actually being applied to that element (computed style)
Once I found the computed style, I want to know where it comes from (like file name and line number)
I know this can be done manually using devtools, but I need this done by a script.
Thanks
You can use Window.getComputedStyle(). An example of usage:
<style>
#elem-container{
position: absolute;
left: 100px;
top: 200px;
height: 100px;
}
</style>
<div id="elem-container">dummy</div>
<div id="output"></div>
<script>
function getTheStyle(){
var elem = document.getElementById("elem-container");
var theCSSprop = window.getComputedStyle(elem,null).getPropertyValue("height");
document.getElementById("output").innerHTML = theCSSprop;
}
getTheStyle();
</script>
See MDN Documentation to learn more how to use this feature and it's compatibility with different browsers.
Unfortunately, this approach will not give you the location of where this value comes from.

CSS styles are applied and displayed but JS doesn't recognize the CSS applied

Something weird is going on and I'm not sure what it is. I created a bunch of elements and I want to get the width of my progress bar so I can work with it in my JS code.
In my JS I do:
var bar = document.getElementById('progressBar');
console.log(bar.style.width); //empty string
however in my CSS I have
#progressBar{
width: 600px;
border: 2px solid black;
}
and I can clearly see the 600px container and the border around it in the browser, but for some reason, JS doens't know about these CSS settings.
Any ideas what the problem might be?
EDIT: This is different from the suggested duplicate - the problem is not that I don't know how to the get the value, the problem is that the style.value doesn't get me what I expect.
That is correct behaviour.
The style property of a DOMElement is responsible for inline styles, not the actual computed values. To get the width, use getClientRects or getBoundingClientRect.
e.g.
var bar = document.querySelector('.bar');
console.log(bar.style.width); // empty string
console.log(bar.getBoundingClientRect().width); // 100px
.bar {
width: 100px;
height: 20px;
background: blue;
}
<div class='bar'></div>
You may also be interested in:
How do I get a computed style?

Get font css property shorthand from an element [duplicate]

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.

jQuery .height() and .outerHeight() returning zero

I'm trying to write a small jQuery plugin that will vertically center a div based on it's height,
Basically in my css I have top: 50%, but since the height is variable I need to calculate this.
The HTML for this looks like
<div class="button-wrapper js-center" data-center="vertical" style="margin-top: 0px;"
<span class="sub-text">Multiline text with two lines</span>
Shop_
</div>
In my plugin I tried logging the height, but it keeps on returning zero:
console.log($el);
console.log("$el.outerHeight(): " + $el.outerHeight());
console.log("$el[0].scrollHeight: " + $el[0].scrollHeight);
// output:
$el.outerHeight(): 0
$el[0].scrollHeight: 0
When I use dev tools to check, it looks like this:
So I'm wondering what potentially could go wrong, for reference, this is the plugin I'm (trying) to write: http://pastebin.com/Qz7BgkcG
EDIT:
This is the main CSS that is used on the .button-wrapper
.button-wrapper {
width: 250px;
left: 50%;
top: 50%;
margin-left: -125px;
position: absolute;
z-index: 100;
}
EDIT 2:
Recreated with all css, but I'm not getting the same issue here: http://jsfiddle.net/8Etex/
I wonder if the issue is because jQuery's .height() method returns the element's computed height rather than the actual box model (ref: API documentation).
If I look at the element you've created in the jsFiddle above, you'll see Firefox doesn't recognise a computed height for your absolute-positioned element. This means it will just return zero. If I force a height attribute on the element in CSS for example, the computed dimensions would be updated and I can retrieve a value.

Categories