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.
Related
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.
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?
alert("Wrong (red): " + document.getElementById("target").getBoundingClientRect().top);
alert("Correct (blue): " + document.getElementById("wrapper").getBoundingClientRect().top);
#target {
transform: translate(20px, -20px) rotateZ(20deg);
background: red;
width: 50px;
height: 50px;
}
#wrapper {
background: blue;
display: inline-block;
}
Text
<div id="wrapper">
<div id="target">
</div>
</div>
further text
In the example above, the blue square has the exact position, the red one would have, if it had no transform. It has also exactly the space and position that the red square consumes, as an in-flow element. The position I want to get in JavaScript is the position of the blue square. My only problem is, that in my original code, there is no #wrapper and I am not able to create one. So how do I get the in-flow position of an element that might or might not be on that position (due to transform, position: relative; or others - if there are)?
Plain JS or jQuery solutions are both welcome. But I search for a rather simple/short solution, not some 50+ lines monster.
My attempts:
jQuery('#target').offset(): Takes transform into account (returns some negative number in the above example).
document.getElementById('target').getBoundingClientRect(): Same as jQuery's offset
jQuery('#target').position() with traversing through offsetParent: Might currently work, but jQuery's behavior in this regard is considered a bug or at least subject to coming changes, according to this site (if I interpret that site correctly).
Use WebKitCSSMatrix
var node = document.getElementById("target");
var curTransform = new WebKitCSSMatrix(window.getComputedStyle(node).webkitTransform);
console.log(node.offsetLeft + curTransform.m41); //real offset left
console.log(node.offsetTop + curTransform.m42); //real offset top
Browser Compatibility :
Check this answer to know how to handle browsers that isn't support WebKitCSSMatrix
I have two divs nested inside of a div.
<div id='outter' class='one'>
<div id='inner'></div>
<div id='button' class='bttn'>Click me!</div>
</div>
The outter div's height is a percentage of the page. I'd like one of the inside div's height to be a fixed difference away the outter div (i.e. $('#inner').height($('#outter').height() - 35)), because the second inner div is essentially a button with fixed height (35). I'd like this to happen even when I change the height (through CSS triggers (:hover/adding a class/etc. so I can use Transitions) or otherwise).
I googled around a bit and saw Less might be an answer, but from what I can tell it compiles in to static values, but I still need to use percentages, since I want this app to work/feel the same on any screen size.
I have examples of what I'm currently doing/how I'm thinking about it in some jsfiddles.
Current 'solution': http://jsfiddle.net/L9NVj/5/ (End heights are what I want them to be, but the transition looks terrible)
Idealistic 'solution': http://jsfiddle.net/L9NVj/6/ (End heights are wrong, but the inner div hugs appropriately)
Potential solution: http://jsfiddle.net/L9NVj/7/ (This hides the inner div on click and then shows it again when the appropriate size has been reached)
Any help/thoughts/insights would be greatly appreciated!
Consider absolute-positioning the inner elements, since the outer's size isn't controlled by their size/position.
#inner {
position: absolute;
top: 2px;
left: 2px;
right: 2px;
bottom: 35px;
/* ... */
}
.bttn {
position: absolute;
bottom: 2px;
left: 2px;
/* ... */
}
Example: http://jsfiddle.net/L9NVj/9/
How about conflicting absolute positioning. To do it, you'd just need to set the top, bottom, left and right of the #inner element and then transition those. That will maintain the distances around the edges of the element, and allow other positioning as well.
Note that while you don't need to actually calculate the value in this case, in the future, calc() can be used to calculate a dynamic value in CSS. In that case, you could do something like height: calc(100% - 37px); to get the same effect.
CSS3's calc() is the answer you're looking for, in combination with a JavaScript fallback for browsers that don't support calc(). In your 'Idealistic solution' fiddle, change your CSS height definition to the following:
height: -webkit-calc(100% - 35px);
height: calc(100% - 35px);
While normally you should include all prefixes (and you still may need to, depending upon your level of browser support), according to Can I Use, the only browsers that currently need prefixing are -webkit browsers.
What I would do with this knowledge is the following: grab a feature detection script, I really like Modernizr and detect to see if calc() is available in the browser. Modernizr has a non-core detect for calc() that you can use. Use that CSS in your CSS file as the default, then using a resource loader such as yepnope (comes with Modernizr), load in a JS solution if calc() isn't available.
Of your JavaScript solutions, I'd probably suggest your "Potential Solution" option, but instead of jQuery's hide() and show(), set opacity to 0 and 1 and use a CSS3 transition to transition between the two. I'd also not rely upon a timeout, but rather use the transitionend JavaScript event.
I edited your first jsfiddle little bit i think that's what you wanted. Just added line.
$(window).resize(function(){$('#inner').height($('#outter').height() - 35)});
jsfiddle:http://jsfiddle.net/Qqb3g/
You may have to some workaround to make transition smooth when button the button is clicked.
you need to calculate the inner div in %, so it can resize belong outer div, change your js code to this :
//calculating inner div'x height in % of outer
$('#inner').height((100 - (33/$('#outter').height() * 100)) + '%');
$('#button').click(function () {
$('#outter').toggleClass('two');
});
give a try to DEMO
I am working on web application.
I wanted to apply auto height to textarea using CSS, dont want to use any script, jquery plugin and other stuff.
After applying class ( i.e. style property ) to textarea, it should automatically increase it's height not width as per content present it in.
In this case width should be fixed i.e. width: 98%; (In my case) only height needs to grow. So scroll bars should exist for text area.
I simply needed one CSS so that after applying to textarea, it should be auto grow like <DIV>.
Please folks do sugggest, is this possible using CSS. If this is not possible, then m okey if i get javascript statments to acheives my requirement.
Thanks,
Pravin
It's sort of semi-doable in html/CSS. There are, however, the usual caveats of browser support and, since it uses html5's contenteditable, it requires a fairly modern browser.
That said, the following works (in Chrome/Ubuntu 10.04):
<div id="wrap">
<div id="editThis" contenteditable>
</div>
</div>
With the following CSS:
div#editThis {
min-height: 4em;
height: auto;
width: 50%;
margin: 0 auto;
}
div#editThis:hover,
div#editThis:focus {
border: 1px solid #000;
}
Demo posted at jsbin
If you're only displaying text in a textarea and not using it to get more content input from the user then consider using a div and styling it to look like a textarea.
the other thing i have seen is an auto expanding textarea that grown in height as you type.
see here: http://james.padolsey.com/javascript/jquery-plugin-autoresize/
This is not possible with pure CSS, you will need to use JavaScript