Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Chrome viewport-anchored expand direction with flexbox

There is an issue in Google Chrome where elements expand/collapse in different directions relative to the viewport when placed inside a flexbox container with an adjacent flex item having space-between or center justified content.

This is not a problem in Firefox, IE11, Edge, or Safari as the elements always expand downward.

I'm curious:

  • Does Chrome's behavior here follow some spec? If so, which one?
  • If not, then why was this done in Chrome? (IMHO, it is horrible UX for the click trigger to disappear offscreen randomly.)
  • Can Chrome's behavior be modified or disabled in someway? Eg. through CSS or meta-tag?

Update 1: I've filed issue #739860 on chromium bug tracker seeking insight/explanation from Chromium devs, if possible.


Here are two examples inserted below. The full test suite describing the problem can be found in this pen: https://codepen.io/jameswilson/full/xrpRPg/ I've chosen to use slideToggle in this example so that the expand/collapse motion is animated and visible to the eye. The same behavior happens with the details tag, but cross-browser support is not there yet, and the expand/collapse is too janky.

Ex 1: Chrome's expand/collapse behavior for space-between justified flexbox

chrome's expand/collapse behavior for space-between justified

$('button').click(function() {
  $(this).next().slideToggle();
})
body {
  margin: 30px;
  font-family: sans-serif;
}
aside,
aside div,
summary,
main,
button,
details p,
button + p {
  background: rgba(0,0,0,.09);
  border: none;
  padding: 20px;
  margin: 0;
}

.flexcontainer {
  display: flex;
}
aside {
  flex: 1;
  position: relative;
  max-width: 25%;
  background: mintcream;

  display: flex;
  flex-direction: column;
  position: relative;
}
aside.space-between {
  justify-content: space-between;
}
aside.center {
  justify-content: center;
}

main {
  flex: 3;
  position: relative;
  max-width: 75%;
  background: aliceblue;
  vertical-align: top;
  height: 100%;
}
main > * + * {
  margin-top: 20px;
}

button + p {
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<section class="flexcontainer">
  <aside class="space-between">
    <div>Top Sidebar</div>
    <div>Bottom Sidebar</div>
  </aside>
  <main>
    <div>
      <button>slideToggle</button>
      <p>Other browsers: always expands downward.<br>
        Chrome: Should always expand downward because Top Sidebar is always visible.</p>
    </div>

    <div>
      <button>slideToggle (usually expands down)</button>
      <p>Other browsers: always expands downward.<br>
        Chrome: Should expand downward while Bottom Sidebar and Top Sidebar are both visible. But will expand upward if you scroll down far enough so that Top Sidebar is off-screen.</p>
    </div>
    
    <div>
      <button>slideToggle (usually expands down)</button>
      <p>Other browsers: always expands downward.<br>
        Chrome: Should expand downward while Bottom Sidebar and Top Sidebar are both visible. But will expand upward if you scroll down far enough so that Top Sidebar is off-screen.</p>
    </div>
  </main>
</section>

Ex 2: Chrome's expand/collapse behavior for center justified flexbox

Chrome's expand/collapse behavior for center justified flexbox

$('button').click(function() {
  $(this).next().slideToggle();
})
body {
  margin: 30px;
  font-family: sans-serif;
}
aside,
aside div,
summary,
main,
button,
details p,
button + p {
  background: rgba(0,0,0,.09);
  border: none;
  padding: 20px;
  margin: 0;
}

.flexcontainer {
  display: flex;
}
aside {
  flex: 1;
  position: relative;
  max-width: 25%;
  background: mintcream;

  display: flex;
  flex-direction: column;
  position: relative;
}
aside.space-between {
  justify-content: space-between;
}
aside.center {
  justify-content: center;
}

main {
  flex: 3;
  position: relative;
  max-width: 75%;
  background: aliceblue;
  vertical-align: top;
  height: 100%;
}
main > * + * {
  margin-top: 20px;
}

button + p {
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="flexcontainer">
  <aside class="center">
    <div>Center Sidebar</div>
  </aside>
  <main>

    <div>
      <button>slideToggle (usually expands downwards)</button>
      <p>Other browsers: always expands downward.<br>
        Chrome: Usually expands downwards. Expands in both directions when the top-edge of the container scrolls out of the viewport.</p>
    </div>

    <div>
      <button>slideToggle</button>
      <p>Other browsers: always expands downward.<br>
        Chrome: Usually expands downwards. Expands in both directions when the top-edge of the container scrolls out of the viewport.</p>
    </div>

    <div>
      <button>slideToggle (usually expands downwards)</button>
      <p>Other browsers: always expands downward.<br>
        Chrome: Usually expands downwards. Expands in both directions when the top-edge of the container scrolls out of the viewport, but then resumes expanding downwards again when Center Sidebar scrolls out of view.</p>
    </div>
  </main>
</section>
like image 211
JamesWilson Avatar asked Jun 29 '17 13:06

JamesWilson


People also ask

How do I adjust the viewport in Google web designer?

Google Web Designer lets you adjust the viewport so that the styles you specified for that size and orientation apply to your document on the stage. If Master rules is selected in the Responsive panel, only universal styles apply. To activate styles that depend on the viewport: In the Responsive panel, select Media rules on the Media queries tab.

How do I change the viewport size when creating a responsive layout?

When you're creating a responsive layout, it's helpful to see how your document looks in different viewport sizes while you're working on it. This method will let you see changes in percentage-based elements, but not style rules. Select Edit base document in the Responsive panel. A border appears around the viewport.

What is the Flexbox layout module?

The Flexible Box Layout Module, makes it easier to design flexible responsive layout structure without using float or positioning. The flexbox properties are supported in all modern browsers. To start using the Flexbox model, you need to first define a flex container.

Is Flexbox supported in all browsers?

The flexbox properties are supported in all modern browsers. To start using the Flexbox model, you need to first define a flex container. The element above represents a flex container (the blue area) with three flex items. You will learn more about flex containers and flex items in the next chapters.


1 Answers

Add this code to your flex container:

  • overflow-anchor: none

This will disable a feature in Chrome known as "scroll anchoring", which is causing the upward expansion of boxes (revised codepen).


In Chrome, the upward / downward direction of expanding boxes is governed by the scroll position in the viewport, not the layout itself.

Chrome takes a unique approach to this behavior for the purpose of improving the user experience.

Basically, they bind a DOM element to the current scroll position. The movement of this particular ("anchor") element on the screen will determine an adjustment, if any, to the scroll position.

They call this approach "Scroll Anchoring". The algorithm is explained on this page: https://github.com/WICG/ScrollAnchoring/blob/master/explainer.md

This behavior is currently unique to Chrome, but Google is pushing for standardization.

In accordance with the Scroll Anchoring documentation, applying overflow-anchor: none to the appropriate element(s) will disable scroll anchoring adjustments.

More information:

  • https://github.com/WICG/ScrollAnchoring/blob/master/explainer.md
  • https://bugs.chromium.org/p/chromium/issues/detail?id=739860
  • https://hacks.mozilla.org/2019/03/scroll-anchoring-in-firefox-66/
  • Changing CSS flex order causes scrolling
like image 192
Michael Benjamin Avatar answered Sep 18 '22 09:09

Michael Benjamin