Reputation: 174
I've run into what seems to be a rendering issue in webkit when using overflow: hidden; on a child div and then increasing the height of a parent div using javascript. I've boiled my issue down to the following sample code.
Create a page from this source and then render in a WebKit browser (Safari, Chrome). Click on the "Expand" button and you will see that the divs that have overflow: hidden; set and should now be displayed based on the expanded parent div height don't show up. In Gecko (Firefox) and Trident (ID) browsers this works fine.
Any ideas or suggestions for work arounds? Basically, I want to hand build a table of divs that contain text within a parent div and I don't want the text to wrap or extend beyond the div boundaries. I need to be able to adjust the height of the parent div based on other things happening on the page.
Thanks! Bart
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Language" content="en-us" />
<style type="text/css">
#test_container {
width: 540px;
}
.column_allow_overflow {
float: left;
width: 100px;
height: 16px;
margin-left: 4px;
padding: 3px;
}
.column_no_overflow {
float: left;
width: 100px;
height: 16px;
margin-left: 4px;
padding: 3px;
overflow: hidden;
}
.background {
background-color: #444444;
color: #e5e5e5;
}
.data_row {
height: 22px;
width: 100%;
padding-bottom: 22px;
background-color: #cccccc;
}
#expand_container {
overflow:scroll;
overflow-x: hidden;
-ms-overflow-x: hidden;
height: 100px;
width: 100%;
background-color: #cccccc;
}
</style>
</head>
<body>
<div id="test_container">
<div class="data_row background">
<button type="button" id="expand_button" onclick="expand();">Expand</button>
</div>
<div id="expand_container">
<div class="data_row background">
<div class="column_allow_overflow background">
Overflow allowed
</div>
<div class="column_no_overflow background">
Overflow NOT allowed
</div>
<div class="column_allow_overflow background">
Overflow allowed
</div>
<div class="column_no_overflow background">
Overflow NOT allowed
</div>
</div>
<div class="data_row background">
<div class="column_allow_overflow background">
Overflow allowed
</div>
<div class="column_no_overflow background">
Overflow NOT allowed
</div>
<div class="column_allow_overflow background">
Overflow allowed
</div>
<div class="column_no_overflow background">
Overflow NOT allowed
</div>
</div>
<div class="data_row background">
<div class="column_allow_overflow background">
Overflow allowed
</div>
<div class="column_no_overflow background">
Overflow NOT allowed
</div>
<div class="column_allow_overflow background">
Overflow allowed
</div>
<div class="column_no_overflow background">
Overflow NOT allowed
</div>
</div>
<div class="data_row background">
<div class="column_allow_overflow background">
Overflow allowed
</div>
<div class="column_no_overflow background">
Overflow NOT allowed
</div>
<div class="column_allow_overflow background">
Overflow allowed
</div>
<div class="column_no_overflow background">
Overflow NOT allowed
</div>
</div>
<div class="data_row background">
<div class="column_allow_overflow background">
Overflow allowed
</div>
<div class="column_no_overflow background">
Overflow NOT allowed
</div>
<div class="column_allow_overflow background">
Overflow allowed
</div>
<div class="column_no_overflow background">
Overflow NOT allowed
</div>
</div>
</div>
</div>
<script>
var expand = function (e) {
var button = document.getElementById('expand_button');
var expand_container = document.getElementById('expand_container');
button.onclick = contract;
expand_container.style.height = '160px';
button.innerHTML = "Contract";
};
var contract = function (e) {
var button = document.getElementById('expand_button');
var expand_container = document.getElementById('expand_container');
button.onclick = expand;
expand_container.style.height = '100px';
button.innerHTML = "Expand";
};
</script>
</body>
</html>
Upvotes: 2
Views: 3562
Reputation: 10119
I managed to find a slightly ugly workaround that fixes it (note: might as well skip to the bottom....I came up with a better solution). Inside the expand_container element, I added another div, that contains the other elements. In the expand and contract functions, I remove that element from its parent (the expand_container), size the expand_container, and then add that div back. The issue no longer happens.
<div id="expand_container" >
<div id="inner_container" style="margin:0; padding:0"> <!-- new element! -->
<div class="data_row background">
<div class="column_allow_overflow background">
...
then...
var expand = function (e) {
var button = document.getElementById('expand_button');
var expand_container = document.getElementById('expand_container');
var inner_container = document.getElementById('inner_container'); // new
expand_container.removeChild(inner_container); // new
button.onclick = contract;
expand_container.style.height = '160px';
expand_container.appendChild(inner_container); // new
button.innerHTML = "Contract";
};
etc...
Edit:
FYI, if you don't want to change your dom structure by adding that inner element, instead you can yank all the children of expand_container, then add them all back after sizing it. For instance:
var len = expand_container.childNodes.length, i, a = [];
for (i=len-1; i>=0; i--)
a.push(expand_container.removeChild(
expand_container.childNodes.item(i)));
button.onclick = contract;
expand_container.style.height = '160px';
for (i=len-1; i>=0; i--)
expand_container.appendChild(a[i]);
Possibly slow if you've got a zillion elements, but on your example it works like a charm.
Edit 2: ok, just thought of something that works even better....remove expand_container and add it back in the same place. Again, works fine (even if nextSibling is null):
var next = expand_container.nextSibling;
var parent = expand_container.parentNode;
parent.removeChild(expand_container);
button.onclick = contract;
expand_container.style.height = '160px';
parent.insertBefore (expand_container, next);
Upvotes: 0
Reputation: 35031
I'm too close to crashing out to copy-paste-test your code at this time of night (well, it's night where I am), but assuming that your problem is that the descendant elements of a given containing element don't reflow correctly when you change the relevant style, try also adding:
expand_container.className = expand_container.className;
immediately after the style change. It looks like it shouldn't do anything, but in every browser I've tested it causes the browser to reflow the container and all its contents, which should fix things.
You might also want to report this as a bug at http://bugs.webkit.org/ if it isn't a known bug.
Upvotes: 0
Reputation: 11256
Edit: Now that I had a bit of time to think about this again, I realized that the stuff I was saying in the original answer is true and all, but this is a reflow issue in the nutshell, since it's only showing up when you increase the height. And since it's a reflow issue, the solution is very simple, add position: relative:
.data_row {
position: relative;
height: 22px;
width: 100%;
padding-bottom: 22px;
background-color: #cccccc;
}
Verified that this works now just fine. I'm going to leave the original answer in tacked for educational purposes.
I don't really have a good solution for you, but I think your issue is about more than just overflow: hidden. This is a combination of float + overflow: hidden. If you remove floats and, for example, position elements absolutely on the page, your script works fine in WebKit browsers. No issues with overflow. I'm not sure if that's something you want to do though. The problem is that overflow actually, doesn't only control whether your content is going to show if the container is too small, but in conjunction with floats, it also can set the sizes of the containers themselves.
Here's a very simple example of it:
<div style="width: 500px; overflow: hidden;">
<div style="width: 200px; float: left; height: 100%; background-color: red;"></div>
<div style="width: 200px; float: right; height: 100%; background-color: orange;"></div>
<div style="background-color: green; overflow: hidden;">aaa</div>
<div>
Setting overflow, strangely enough, is working as float clearing. It doesn’t clear the float at the element, it self-clears. This means that the element with overflow applied (auto or hidden), will extend as large as it needs to encompass child elements inside that are floated (instead of collapsing), assuming that the height isn’t declared.
I think because of that, you are having issues with your design.
I suggest you use display: table-cell, if all of the items are supposed to be equal height, table layout if you are not div purist, or absolute positioning.
P.S. Sorry, it probably should've been a comment instead of the answer, since I don't really provide a good solution, but it was too long for a comment.
Upvotes: 1