How can I trigger CSS layout recalculation after Javascript DOM updates? - javascript

I often find that if I create or reparent DOM nodes in javascript, the CSS engine doesn't recalculate the sizes of the parent containers. This happens in Firefox and Chrome.
For example, the body might stay the same size while new content overflows the bottom. If I resize the window the body grows, but it doesn't "lock in" to its correct size until the window is sized to be at least as big as the body should be.
Is there a way to trigger a full layout recomputation in Javascript?

I can able to trigger CSS Engine via:
document.body.style.zoom = 1.0000001;
setTimeout(function(){document.body.style.zoom = 1;},50); //allow some time to flush the css buffer.
For every time after resizing the window use the following:
$(window).resize(function() {
if(this.resizeTO) clearTimeout(this.resizeTO);
this.resizeTO = setTimeout(function() {
$(this).trigger('resizeEnd');
}, 500);
});
$(window).bind('resizeEnd', function() {
document.body.style.zoom = 1.0000001;
setTimeout(function(){document.body.style.zoom = 1;},50);
});

You can trigger a repaint from JavaScript by setting a CSS style to an innocuous value, e.g.
document.body.style.zIndex = 1;

Yes. I tend to put a random className on the <html> element, using:
document.documentElement.className = 'reflow_' + (new Date()).getTime();
which creates:
<html class="reflow_1483757400611">
Tried and tested on everything from Android Browser 4 to Smart TV's via camposat.tv

The browser does recompute the geometry of all elements after DOM manipulation. One likely reason you might see an element "stuck" at a certain height even after its content has changed is this CSS rule:
body { height: 100% };
It tells the browser, make the body element as large in height as the viewport regardless of its content.
Try changing it to:
body { min-height: 100% };
This will tell the browser to make body at least as large in height as the viewport or larger if there is more content.

Related

Font size relative to container

i am designing a site that adjusts itself to the window size, and i need to make the text size relative to it's container (a div). I searched about doing it with css, and found out that it is not possible. So i am trying with JavaScript, but i am not a JavaScript programmer. So i searched each piece of the code i needed and compiled it to this:
<script type="text/javascript">
$(document).ready(function() {
while(true) {
document.getElementById("text").style.fontSize = $("container").height();
}
});
</script>
(the "while" is to re-size it constantly, considering that the user might re-size the window)
I put the script in the "head" tag, and it doesn't work. I don't know if the script is wrong, or if it is not running. What am i doing wrong?
Also i want to put a delay in the end of the script, to avoid it running like crazy, but i don't know how to do that.
Thanks in advance,
Luca
Thanks to the answers, but nothing working.
I guess that the script is not running, what can be wrong??? Please help!
http://jsfiddle.net/AyRMC/
You can use viewport units:
.vw{
font-size:3vw;
color:red;
}
.vh{
font-size:3vh;
color:green;
}
.vmin{
font-size:3vmin;
color:blue;
}
Doesn't have full support quite yet, but IE10, Chrome, Firefox, and Safari all support it.
One downside (or possible upside) is that, at least in chrome, the text doesn't scale as the viewport is resized.
Compatibility: http://caniuse.com/viewport-units
You should try something like this instead (if I understand correctly what you want to do):
$(".container").each(function(){ //if container is a class
$('.text', $(this)).css({'font-size': $(this).height()+"px"}); //you should only have 1 #text in your document, instead, use class
});
or something more like this
$(window).resize(function(){
$('.text').css({'font-size': $('#container').height()+"px"});
});
If you mean that you are making a responsive site, then you can change the font-size based on document.documentElement.clientWidth inside of the window resize handler.
Also, you can use em units instead of pixels which are scalable and mobile-friendly.
CSS3 also has a new interesting "root em" unit :
CSS3 introduces a few new units, including the rem unit, which stands
for "root em". If this hasn't put you to sleep yet, then let's look at
how rem works.
The em unit is relative to the font-size of the parent, which causes
the compounding issue. The rem unit is relative to the root—or the
html—element. That means that we can define a single font size on the
html element and define all rem units to be a percentage of that.
http://snook.ca/archives/html_and_css/font-size-with-rem
Try this:
<script type="text/javascript">
$(document).ready(function() {
$(window).resize(function() {
document.getElementById("text").style.fontSize = $(".container").height();
// let container is a class
});
});
</script>
You can use the .resize() event handler which will only fire when the window is resized
var constant = [Some magic number]
$(window).resize(function() {
var fontSize = $(this).height()*$(this).width()*constant;
$(html).css("font-size",fontSize)
}
Using a constant to calculate the font size based on the new width/height

How do I get a div to change the max-height upon window resize?

code: http://jsfiddle.net/MDnrk/7/
for those too lazy to click the link:
$j(function(){
// need to fix some things that CSS doesn't seem to be able to fix (esp cross browser)
fix_drawer_height()
$j(window).resize(function() {
fix_drawer_height()
});
})
function fix_drawer_height(){
var new_height = document.body.offsetHeight - $j(".redline_info_scrollable").offset().top;
$j(".redline_info_scrollable").css({
'max-height': new_height + 'px;'
});
}
now, in my app, fix_drawer_height() gets called on DOM ready, but it doesn't seem to be called in teh JS fiddle.. so I'm not sure if that is the correct medium to show this problem.
Still not sure what would couse the window resize listener to not set the max-height appropriately. =\
The goal is to have the scrollable div always stretch to the height of the window.
Normally I'd just use height: 100% in the CSS, but that isn't really cross browser, and won't work with how the div is positioned in my actual app.
thanks!
You can use this:
function fix_drawer_height() {
$('.redline_info_scrollable').height($(document).height());
}
and add it in your onload or onresize;
working code: http://jsfiddle.net/MDnrk/13/

Using Javascript to resize a div to screen height causes flickering when shrinking the browser window

The Background:
I tried to solve the StackOverflow question yet another HTML/CSS layout challenge - full height sidebar with sticky footer on my own using jQuery. Because the sidebar in my case may be longer than the main content it matches the case of comment 8128008. That makes it impossible to have a sidebar longer than the main content and having a sticky footer without getting problems when shrinking the browser window.
The status quo:
I have a html page with a div, which is automatically stretched to fill the screen. So if there is empty space below the element, I stretch it downwards:
But if the browser viewport is smaller than the div itself, no stretching is done but the scrollbar shows up:
I've attached jQuery to the window's resize event to resize the div, if the browser window is not to small and remove any resizing in the other case. This is done by checking if the viewport is higher or smaller than the document. If the viewport is smaller than the document, it seems like the content is larger than the browser window, why no resizing is done; in the other case we resize the div to fill the page.
if ($(document).height() > $(window).height()) {
// Scrolling needed, page content extends browser window
// --> No need to resize the div
// --> Custom height is removed
// [...]
} else {
// Window is larger than the page content
// --> Div is resized using jQuery:
$('#div').height($(window).height());
}
The Problem:
Up to now, everything runs well. But if I shrink the browser window, there are cases, where the div should be resized but the document is larger than the window's height, why my script assumes, that no resizing is needed and the div's resizing is removed.
The point is actually, that if I check the document's height using Firebug after the bug appeared, the height has just the value is was meant to have. So I thought, the document's height is set with a little delay. I tried to run the resize code delayed a bit but it did not help.
I have set up a demonstration on jsFiddle. Just shrink the browser window slowly and you'll see the div "flickering". Also you can watch the console.log() output and you will notice, that in the case of "flickering" the document's height and the window's height are different instead of being equal.
I've noticed this behavior in Firefox 7, IE 9, Chrome 10 and Safari 5.1. Can you confirm it?
Do you know if there is a fix? Or is the approach totally wrong? Please help me.
Ok -- wiping my old answer and replacing...
Here's your problem:
You are taking and comparing window and document height, without first taking into consideration the order of events here..
Window loads
Div grows to window height
Window shrinks
Document height remains at div height
Window height is less than div height
At this point, the previously set height of the div is keeping document height greater than the window height, and this logic is misinterpreted:
"Scrolling needed, no need to extend the sidebar" fires, erroneously
Hence the twitch.
To prevent it, just resize your div along with the window before making the comparison:
(function () {
var resizeContentWrapper = function () {
console.group('resizing');
var target = {
content: $('#resizeme')
};
//resize target content to window size, assuming that last time around it was set to document height, and might be pushing document height beyond window after resize
//TODO: for performance, insert flags to only do this if the window is shrinking, and the div has already been resized
target.content.css('height', $(window).height());
var height = {
document: $(document).height(),
window: $(window).height()
};
console.log('height: ', height);
if (height.document > height.window) {
// Scrolling needed, no need to externd the sidebar
target.content.css('height', '');
console.info('custom height removed');
} else {
// Set the new content height
height['content'] = height.window;
target.content.css('height', height['content']);
console.log('new height: ', height);
}
console.groupEnd();
}
resizeContentWrapper();
$(window).bind('resize orientationchange', resizeContentWrapper);
})(jQuery);
Per pmvdb's comment, i renamed your $$ to "target"
$(window).bind('resize',function(){
$("#resizeme").css("height","");
if($("#resizeme").outerHeight() < $(window).height()){
$("#resizeme").height($(window).height());
$("body").css("overflow-y","hidden");
}else{
$("body").css("overflow-y","scroll");
}
});
Maybe I am misunderstanding the problem, but why are you using Javascript? This seems like a layout (CSS) issue. My solution without JS: http://jsfiddle.net/2yKgQ/27/

iframe dynamic height resizing

Hi I currently have 2 pages (index.html and iframe_contents.html). Both are on the same domain.
I am currently trying to get the iframe to dynamically resize based on the contents size.
I was using this to assist me http://benalman.com/code/projects/jquery-resize/examples/resize/ and it works if the iframe_contents body tag gets larger or smaller on Firefox and IE 7/8/9 but for webkit it only can grow and can never shrink
I've narrowed it down to the body tag in iframe_contents.html not shrinking when content height changes but only in the iframe. When iframe_contents.html is not in a iframe if I shrink / enlarge elements the bodies overall height changes.
Is this a webkit specific issue?
After reading lots of answers here they all had the same issue with not resizing smaller when needed. I think most people are just doing a one-off resizing after the frame loads, so maybe don't care. I need to resize again anytime the window size changes. So for me, if they made the window narrow the iframe would get very tall, then when they make the window larger it should get shorter again. This wasn't happening on some browsers because the scrollHeight, clientHeight, jquery height() and any other height I could find with DOM inspectors (FireBug/Chrome Dev Tools) did not report the body or html height as being shorter after the iframe was made wider. Like the body had min-height 100% set or something.
For me the solution was to make the iframe 0 height, then check the scrollHeight, then set to that value. To avoid the scrollbar on my page jumping around, I set the height of the parent (that contains the iframe) to the iframe height to keep the total page size fixed while doing this.
I wish I had a cleaner sample, but here is the code I have:
$(element).parent().height($(element).height());
$(element).height(0);
$(element).height($(element).contents().height());
$(element).parent().height("");
element is my iframe.
The iframe has width: 100% style set and is inside a div with default styles (block).
Code is jquery, and sets the div height to the iframe height, then sets iframe to 0 height, then sets iframe to the contents height. If I remove the line that sets the iframe to 0 height, the iframe will get larger when needed, but never smaller.
This may not help you much but here is a function we have in what would be your iframe_contents.html page. It will attempt to resize the iframe in which it is loaded in a sort of self-resizing, cross-browserish, pure-JavaScript kind of way:
function makeMeFit() {
if (top.location == document.location) return; // if we're not in an iframe then don't do anything
if (!window.opera && !document.mimeType && document.all && document.getElementById) {
parent.document.getElementById('youriframeid').style.height = (this.document.body.offsetHeight + 30) + "px";
} else if (document.getElementById) {
parent.document.getElementById('youriframeid').style.height = (this.document.body.scrollHeight + 30) + "px"
}
}
You could put calls to it in a resize() event or following an event that changes the height of your page. The feature-testing in that method should separate out WebKit browsers and pick the correct height property.

Detect iframe content height change

There are plenty of examples showing how to dynamically set an iframe's height to its content. This works perfect for me. The problem I'm now having is that the content can change size without triggering onload (think hidden/expandable divs).
Is there any way to detect when the size of the iframe content has changed? This is on the same domain and no jQuery, please.
I would do this by polling regularly (maybe every 200 milliseconds, perhaps more often) using setInterval. You could then compare the size of the content to what it was last time.
var iframe = document.getElementById('myIframe'),
lastheight;
setInterval(function(){
if (iframe.document.body.scrollheight != lastheight) {
// adjust the iframe's size
lastheight = iframe.document.body.scrollheight;
}
}, 200);
For non-webkit browsers, there are a few domMutation-Events, that fire when an attribute of an element (e.g. the body element) change. See DOMSubtreeModified and more importantly DOMAttrModified.
The internet explorer does fire the onresize event even on non-windows elements.
Opera honors the domMutation Events.
Webkit on the other discarded these events as a compromise to rendering speed and javascript-performance. Thee is no other way than to check via timeout/interval the effective size of an element.
ResizeObserver worked for me:
const iframe = document.getElementById('myIframe')
const observer = new ResizeObserver(() => {
setHeight(iframe.document.body.scrollHeight);
})
observer.observe(iframe.document.body);

Categories