Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent absolutely positioned element in { overflow-y: auto } div from triggering scrollbar

Tags:

html

css

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.

overflow-y problem demonstration

Here is a codepen showing the issue:

http://codepen.io/isaksky/pen/zxedXe

like image 426
Isak Avatar asked Mar 24 '15 22:03

Isak


People also ask

How would you absolutely positioned element?

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.)

What is overflowx?

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.


1 Answers

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:

  • Why does CSS2.1 define overflow values other than "visible" to establish a new block formatting context?

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>
like image 150
Hashem Qolami Avatar answered Oct 13 '22 00:10

Hashem Qolami