Is there a way to prevent an absolutely positioned element from triggering a scrollbar when overflow-y
is set? I was under the impression it would not, because absolutely positioned element normally do not affect the width/height of parent elements. For some reason this does not seem to matter for determining whether to show a scrollbar when overflow-y: auto is set. Is there a way to work around this without putting the dropdown contents in a completely different place in the DOM?
I would like only the things that would normally make an element grow be able to trigger a scrollbar.
Here is a codepen showing the issue:
http://codepen.io/isaksky/pen/zxedXe
An absolutely positioned element is an element whose computed position value is absolute or fixed . The top , right , bottom , and left properties specify offsets from the edges of the element's containing block. (The containing block is the ancestor relative to which the element is positioned.)
Definition and Usage The overflow-x property specifies whether to clip the content, add a scroll bar, or display overflow content of a block-level element, when it overflows at the left and right edges.
IMO user agents render absolutely positioned elements within wrappers with overflow
other than visible
this way due to performance issues.
Because they have to redraw (and change the position of) the absolutely positioned elements with the respect to their containing block during scrolling.
The same thing happens in the presence of floats — See:
One possible option could be to let the absolutely positioned element position relative to the initial containing block (where the <html>
element lives) instead.
In order to achieve that, we can remove position: relative
from the #dialog-1
, so the containing block of the absolutely positioned element would be the initial containing block. And also it gets scrolled along with the page.
Example Here
function forAllNodes(nodes, fn) {
Array.prototype.forEach.call(
nodes,
function(node) {
fn.call(node);
}
);
}
var layoutGate = function() {
forAllNodes(
document.querySelectorAll('.dropdown-contents'),
function() {
if (this.classList) this.classList.toggle('hide');
}
);
};
var intervalId = setInterval(layoutGate, 1000);
forAllNodes(
document.querySelectorAll('.toggle-dropdown-btn'),
function() {
var elm = this;
elm.addEventListener('click', function() {
if (intervalId) {
clearInterval(intervalId);
intervalId = null;
}
layoutGate();
}, false);
}
);
.wrapper {
padding-left: 20px;
}
p {
line-height: 1.3em;
}
#dialog-1 {
padding: 10px;
border: 3px solid black;
width: 400px;
min-height: 100px;
max-height: 150px;
overflow-y: auto;
}
.dropdown-control {
/* position: relative; */
margin: 0;
padding: 0;
}
.toggle-dropdown-btn {
padding: 0;
margin: 0;
}
.dropdown-contents {
list-style-type: none;
position: absolute;
/* min-width: 100%; */
width: 400px;
background-color: #81d4fa;
margin: 0;
padding: 0;
border: 1px solid green;
/* top: 100%; */
/* left: 0; */
}
#dialog-2 {
padding: 10px;
border: 3px solid black;
width: 400px;
min-height: 100px;
max-height: 150px;
}
.hide {
display: none;
}
<div class="wrapper">
<h1>Div with overflow-y:</h1>
<div id="dialog-1">
<p>Stuff in Dialog blah blah</p>
<div class="dropdown-control">
<button type="button" class="toggle-dropdown-btn">Toggle Dropdown</button>
<ul class="dropdown-contents">
<li>why</li>
<li>do i </li>
<li>trigger </li>
<li>scroll</li>
</ul>
</div>
</div>
<h1>Normal div, no overflow-y</h1>
<div id="dialog-2">
<p>Stuff in Dialog blah blah</p>
<div class="dropdown-control">
<button type="button" class="toggle-dropdown-btn">Toggle Dropdown</button>
<ul class="dropdown-contents">
<li>this</li>
<li>does not </li>
<li>grow </li>
<li>the div</li>
</ul>
</div>
</div>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With