Hiding DIV with absolute positioning causes reflow - javascript

I'm curious if it expected behavior to do reflow when hiding absolutely positioned element?
Consider example code below:
<html>
<head>
<style>
.float {
position: absolute;
background-color: #E0E0E0;
padding: 5;
left: 100px;
top: 100px;
}
</style>
<script>
function toggle() {
var float = document.getElementById("float");
var style = float.style;
if (style.display == "none") {
style.display = "block";
} else
style.display = "none";
}
</script>
</head>
<body>
Click to toggle!
<div id="float" class="float" style="display:none">Floating div</div>
</body>
</html>
When I check Timeline tab in Chrome Dev Tools I see the following:
Line 23 corresponds to style.display = "none"; and my expectation is that no reflow is required.
Am I wrong? Or did I misinterpret Timeline results? Is there a better way of doing this?
Thank you!

There is a reflow. When you change the display of an element, the browser needs to perform layout operations. Maybe you're confusing the idea of a layout pass, with a layout pass that affects the whole document. In your case, I think the layout affects only the .float element. You can see it clicking in the layout bar. It'll tell you the scope of the layout.
Contrary to what it may seem, hiding an absolute positioned element can cause a reflow of the whole page. This can happen, for example, if the positioned element is higher or wider than the browser viewport. In this case, hiding it could cause the scrollbars to disappear, and, as a result, a reflow of the whole document.
Each browser has its own methods to determinate whehter a whole document reflow is needed or not, so what works in a browser may not work in another. You have a good article here: Introducing layout boundaries
EDIT: As #xotic750 said, you can avoid the reflow setting visibility: hidden. This causes the browser to avoid painting, but to the layout engine, it'll be there. This way it won't be a reflow when you show/hide it. The downside? Every time there is a reflow for another reason, the contents of your invisible div will be part of the layout process. If the div's DOM tree is simple, maybe playing with visibility is better. But if the div contains lots of objects, specially tables, I think you should use display: none. It'll also depend, of course, on the time the div is supposed to be visible or hidden.

Related

Can I detect the width of a dynamicaly filled div box without rendering it on the web page?

Can I detect the width of a dynamicaly filled div box without rendering it on the web page?
<div>{{some.data.from.some.model}}</div>
If I render it, I know it's width is 260px (in every modern browser).
Can I detect it, before it is rendered on the web page? Are there tools, mechanisms, libraries to do that?
My Imagination is:
That is the div box width this class (margin, padding, whatever)
This is the content (text, font, fontsize, whatever..)
Tell me it's width
Don't show it on the homepage yet, I'll decide afterwards
You can't get the size of an element that doesn't exist (hasn't been rendered). Any solution you find to calculating an element's size without it being rendered is probably not going to be cross-browser.
So, the best you can do is render said element out of view, be it via "visibility: hidden", or pushing it out of view with "display: fixed". Once you have an actual element, you can check it's size for the current browser via JS and proceed accordingly.
I have created a simple fiddle here: http://jsfiddle.net/5wq8o02q/.
HTML
<div id="playground" class="block">
some content
</div>
<span id="width"> </span>
CSS
.block {
/* width: 100px; */
height: 100px;
}
JQUERY:
$(function(){
//$('#playground').css('visibility','hidden');
$('#playground').css('display','none');
$('#width').html($('#playground').css('width'));
});
It helps to use display: none and it won't use screen real estate as visibility: hidden. It still gives the width you are looking for (I think). Let me know me it helps ...

Fixed div as background on mobile devices

I want to use a div as a background for a website.
If I use position:fixed and set the width & size to the viewport size the design breaks on mobile devices/tablets as they do not support the fixed position.
What's the best way to set a div as a static background, so that it works on mobile devices too?
I'm not entirely sure how you intend to use the background, but I created a loose way to do this here. The tacky background is applied to a div the size of the screen, and it will not move (as long as you're careful with what you put inside it). However, the same effect could be done just by direct styles on the body - I'm not sure what exactly you need the div for, so I can't guarantee this technique will work for your use case.
How it Works
With disclaimers out of the way, here are a few details on how it works. All content will have to appear within two divs: one outer one that has the background, and an inner one to hold all of the content. The outer one is set to the size of the page and can have the background applied to it. The inner one then is set to the size of the parent, and all overflow is set to scroll. Since the outer one has no scrollbar, any interior content that exceeds the size of the background tag will cause a scrollbar to appear as though it were on the whole page, not just on a section of it. In effect, this then recreates what the body is on the average web page within the "content" div.
If you have any specific question on the styles, let me know and I'll flesh out the mechanics in more detail.
With jQuery
I suppose there's still one remaining option: use similar style rules, but absent the ability to nest everything within the background, instead prepend it, and change it's position whenever the user scrolls, like so.
Then, just inject this code:
<style>
#bg {
width: 100%;
height: 100%;
position: absolute;
top: 0px;
background-image: url(http://cdn6.staztic.com/cdn/logos/comsanzenpattern-2.png:w48h48);
margin: 0px;
padding: 0px;
overflow: hidden;
}
</style>
<script>
$("body").prepend("<div id='bg'></div>");
$(document).on("scroll", function () {
$("#bg").css("top", $(document).scrollTop())
.css("left", $(document).scrollLeft());
});
</script>
modifying the style rules for the background div accordingly, and you should be good. It will not have a good framerate since this will always appear after the scroll paint, but you're running low on options if you have so little control over the rest of the document structure and style.
You don't have to use jquery. I was able to get this effect with just CSS.
You set the div just below the initial tag. Then apply the image to the html within the div. Give the div and id attribute as well (#background_wrap in this case).
...I tried this without applying the actual image link within the html and it never worked properly because you still have to use "background-image:" attribute when applying the image to the background within css. The trick to getting this to work on the mobile device is not using any background image settings. These values were specific for my project but it worked perfectly for my fixed background image to remain centered and responsive for mobile as well as larger computer viewports. Might have to tweak the values a bit for your specific project, but its worth a try! I hope this helps.
<body>
<div id="background_wrap"><img src="~/images/yourimage.png"/></div>
</body>
Then apply these settings in the CSS.
#background_wrap {
margin-left: auto;
margin-right: auto;
}
#background_wrap img {
z-index: -1;
position: fixed;
padding-top: 4.7em;
padding-left: 10%;
width: 90%;
}

Scrollbars on overflow div do not appear when content is added to div using Javascript

I have an HTML Document that looks a bit like this, only is far more complex and harder to control:
<body>
<div id="title">This div does not do anything, just stays at the top.</div>
<div id="container">
<div id="navigation">Some navigation</div>
<div id="content">Most of the content</div>
</div>
</body>
Then I have a stylesheet that includes the following:
#container
{
height: auto !important;
overflow: visible !important;
overflow-x: auto;
overflow-y: scroll;
position: relative;
width: auto !important;
}
This all works absolutely perfectly. The title section stays at the top of the page, the container div becomes scrollable if the content is long enough to need to scroll, otherwise it doesn't.
The problem is, that I am then using Javascript to add a whole lot more stuff to the content div. This means that the content div is getting longer than the page after it has loaded and this seems to mean, in IE8 at least, that the scrollbars on the container never get activated, so once the Javascript added content falls off the bottom of the page it becomes inaccessible.
It doesn't help that the minute I start tinkering with the IE developer tools, the scrollbars vanish altogether and I can't make them reappear, so it becomes somewhat hard to test.
I know IE8 has some issues with overflow-y.
You should try with this maybe.
-ms-overflow-y: scroll;
Hope that helps.
Hard to say if this will work without seeing more code, but why not remove the styles from your css and add them with javascript, once the content has loaded.
The solution that has worked was a simple hackaround of resizing the element with JavaScript to match the size it actually is once I have added the extra data to it, like this:
document.all['container'].style.height = document.documentElement.clientHeight+"px";
Of course, this doesn't entirely circumvent the problem- for that we need a new function:
function resizeResults()
{
var resultPanel=document.all["container"];
var topPanel=document.all["title"];
var newHeight= document.documentElement.clientHeight;
newHeight -= topPanel.clientHeight;
resultPanel.style.height=newHeight;
}
Then we can use window.attachEvent("onresize", resizeResults); to ensure that we don't lose the scrollbar or have it otherwise messed around when the user changes the window size.
Just remove the styles you have given for the element to make it scroll before loading ajax content to it.After loading ajax content then add those attributes again.

How to disable scrolling the document body?

I have a HTML which has lot of content and a vertical scrollbar appears as soon as the HTML is loaded. Now from this HTML a full screen IFRAME is loaded. The problem is when the IFRAME is loaded, the parent scrollbar still persists, I want to disable the scrollbar when the Iframe is loaded.
I tried:
document.body.scroll = "no", it did not work with FF and chrome.
document.style.overflow = "hidden"; after this I was still able to scroll, and the whole iframe would scroll up revealing the parent HTML.
My requirement is, when the IFRAME is loaded, we should never be able to scroll the entire IFRAME if the parent HTML has a scrollbar.
Any ideas?
If you want to use the iframe's scrollbar and not the parent's use this:
document.body.style.overflow = 'hidden';
If you want to use the parent's scrollbar and not the iframe's then you need to use:
document.getElementById('your_iframes_id').scrolling = 'no';
or set the scrolling="no" attribute in your iframe's tag: <iframe src="some_url" scrolling="no">.
with css
body, html {
overflow: hidden
}
The following JavaScript could work:
var page = $doc.getElementsByTagName('body')[0];
To disable Scroll use:
page.classList.add('noscroll');
To enable Scroll use:
page.classList.remove('noscroll');
In the CSS file, add:
.noscroll {
position: fixed!important
}
add this css
body.disable-scroll {
overflow: hidden;
}
and when to disable run this code
$("body").addClass("disable-scroll");
and when to enabled run this code
$("body").removeClass("disable-scroll")
I know this is an ancient question, but I just thought that I'd weigh in.
I'm using disableScroll. Simple and it works like in a dream.
I have had some trouble disabling scroll on body, but allowing it on child elements (like a modal or a sidebar). It looks like that something can be done using disableScroll.on([element], [options]);, but I haven't gotten that to work just yet.
The reason that this is prefered compared to overflow: hidden; on body is that the overflow-hidden can get nasty, since some things might add overflow: hidden; like this:
... This is good for preloaders and such, since that is rendered before the CSS is finished loading.
But it gives problems, when an open navigation should add a class to the body-tag (like <body class="body__nav-open">). And then it turns into one big tug-of-war with overflow: hidden; !important and all kinds of crap.
Answer :
document.body.scroll = 'no';

Fluid Elements and Overflow Question

So here's a stump I've hit.
I'm designing a... Thing. It sizes itself to the browser window, with some controls at the top and a rather large list near the bottom. Anyways, it's basically a table cell that sizes with the browser window, whos size is the document size - 130px in height, and document size - 50px in width. What I want it to do, is when the list of stuff inside that cell is bigger then the cell, it to become scrolly using css's overflow: auto.
The problem, is that I can't get it to do that, only make the entire document scrolly. Currently, the cell has no properties aside from valign:top, and it has a single div in it (to which the list elements are written), and it's set to overflow:auto. However, it's just scales up the entire document when the list becomes to long.
I don't want to give it a static size since it sizes with the page.
Any ideas?
Thanks!
-Dave
I'm not sure I understand correctly, but here's a try that may give you ideas.
<head>
<title>Test</title>
<style>
div.outer {
background-color: red;
position: absolute;
top: 40px;
bottom: 40px;
left: 40px;
right: 40px;
}
div.inner {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: auto;
background-color: aqua;
}
</style>
</head>
<body>
<div class="outer">
<div class="inner">
On the Insert tab, the galleries include items that are designed to coordinate with the overall look of your document. You can use these galleries to insert tables, headers, footers, lists, cover pages, and other document building blocks. When you create pictures, charts, or diagrams, they also coordinate with your current document look.
You can easily change the formatting of selected text in the document text by choosing a look for the selected text from the Quick Styles gallery on the Home tab. You can also format text directly by using the other controls on the Home tab. Most controls offer a choice of using the look from the current theme or using a format that you specify directly.
To change the overall look of your document, choose new Theme elements on the Page Layout tab. To change the looks available in the Quick Style gallery, use the Change Current Quick Style Set command. Both the Themes gallery and the Quick Styles gallery provide reset commands so that you can always restore the look of your document to the original contained in your current template.
</div>
</div>
</body>
The solution of buti-oxa is very nice, but doesn't work in Internet Explorer.
For a cross-browser solution, you need to assign a fixed height to the div that contains the list. You can't do it using only css, because the height to assign depends from the height of the browser window.
But you can use a simple javascript function to dinamically assign the height to the div.
Here is an example, using jQuery:
function resizeDiv(){
var h = $(window).height(); //maybe the window height minus the header and footer height...
$("#yourDivId").css("height", h + "px");
}
You should call this function when the page is loaded and when the user resizes the window:
$(document).ready(function(){
resizeDiv();
$(window).resize(function(){
resizeDiv();
});
});
You can see this in action in this demo page I posted (resize window to test):
http://www.meiaweb.com/test/BMS_DM_NI/
if I m not wrong and your content is only text you can add wrap property although this dosen't work in firefox u can add wbr to your text
I think you should consider fluid layout design patterns.
Couple of tips:
MediaQueries
Use % instead of fixed values like px
I think an iFrame would help. Put your 'thing' into a base URL, and then use another page with an iFrame to load it. As the 'thing' goes crazy in size, the scroll bars appear, but your outer page is not effected.
An old fashion frame should work too, but iFrames are just more fun ....

Categories