Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flex items overlapping in Chrome and IE11

Tags:

html

css

flexbox

I'm trying to create a flexbox layout of fixed height which scrolls the inner content when the inner content is too large.

Additionally if the content doesn't cause scrolling I want to fix a div with buttons to the bottom of the container.

I have a layout which works perfectly in Firefox but in Chrome it causes the bottom button div to clip on top of the content when it's large enough to cause scrolling.

This is the layout rendering properly in Firefox:

Firefox proper rendering

This is how it renders improperly in Chrome:

Chrome improper rendering

Additionally, this is how it should behave if there's not enough inner content to cause scrolling:

Small content rendering

.container {
  height: 150px;
  width: 300px;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  border: 1px solid #000;
  padding: 4px;
}

.options {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
}

.spacer {
  flex: 1 1 auto;
}

.buttons {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}
<div class="container">

  <div class="options">
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
  </div>

  <div class="spacer"></div>

  <div class="buttons">
    <input type="button" value="Cancel">
    <input type="button" value="Save">
  </div>

</div>

https://jsfiddle.net/tdghqyuu/1/

like image 615
jesse.rohland Avatar asked Jan 17 '18 05:01

jesse.rohland


2 Answers

Solution

Add this to your code:

.container > * {
  flex-shrink: 0; 
}

Explanation

An initial setting on flex items, according to the flexbox specification, should be flex-shrink: 1. This means that flex items are permitted to shrink in order to avoid overflowing the container.

Chrome and IE11 appear to be adhering to this guideline.

Other browsers, such as Firefox, Edge and Safari, seem to have flex-shrink set to 0 by default.

On the other hand, this may have little or nothing to do with flex-shrink. The problem may relate to the default min-height and min-width settings on flex items. (See here: Why don't flex items shrink past content size?)

Or maybe it's a combination of both. It really depends on the browser.

The fact is, browser implementations vary. That's why you have to test.

Spec initial settings are not entirely reliable because

  1. browsers represent independent entities that can do whatever they want, and
  2. the use of "interventions".

Interventions

An intervention is when a user agent decides to deviate slightly from a standardized behavior in order to provide a greatly enhanced user experience.

In other words, a browser takes it upon itself to provide settings that it feels are best for its users, regardless of spec guidelines.

Chrome seems to do this a lot. Here are some examples:

  • Why don't flex items shrink past content size? (see browser rendering notes)
  • pseudo element not aligning at top left corner
  • Google Chrome viewport-anchored expand direction with flexbox
  • How to make images stay within the rows of a css grid container?
  • Why are percentage heights working on children when the parent has no height defined?

One thing appears certain: If you disable flex-shrink, your layout then works across all browsers. Add this to your code:

.container > * {
  flex-shrink: 0; 
}

.container>* {
  flex-shrink: 0;
}

.container {
  height: 150px;
  width: 300px;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  border: 1px solid #000;
  padding: 4px;
}

.options {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
}

.buttons {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  margin-top: 10px;
  /* new; for demo only */
}
<div class="container">

  <div class="options">
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
  </div>

  <div class="buttons">
    <input type="button" value="Cancel">
    <input type="button" value="Save">
  </div>

</div>

You may also want to consider moving the scrollbar to the options box only, then you've truly fixed the buttons to the bottom of the screen. Make this adjustment to your code:

.container {
  height: 150px;
  width: 300px;
  display: flex;
  flex-direction: column;
  /* overflow-y: auto; */
  border: 1px solid #000;
  padding: 4px;
}

.options {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  overflow-y: auto; /* NEW */
  flex: 1;          /* NEW; may be necessary for overflow to work in some browsers */

}

.container > * {
  flex-shrink: 0;
}

.container {
  height: 150px;
  width: 300px;
  display: flex;
  flex-direction: column;
  /* overflow-y: auto; */
  border: 1px solid #000;
  padding: 4px;
}

.options {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  overflow-y: auto; /* NEW */
  flex: 1;          /* NEW; may be necessary for overflow to work in some browsers */
}

.buttons {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  margin-top: 10px; /* new; for demo only */
}
<div class="container">

  <div class="options">
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
    <div class="option">
      <input type="checkbox"> Option
    </div>
  </div>

  <div class="buttons">
    <input type="button" value="Cancel">
    <input type="button" value="Save">
  </div>

</div>

Also, I removed the spacer element you had. It doesn't seem necessary when there are a multitude of clean ways to create space between items in a flex container.

like image 152
Michael Benjamin Avatar answered Nov 07 '22 02:11

Michael Benjamin


.container doesn't need to be "flex", a min-height property for .options may be enough:

        .container {
            height: 150px;
            width: 300px;
            /*display: flex;*/
            flex-direction: column;
            overflow-y: auto;
            border: 1px solid #000;
            padding: 4px;
        }

        .options {
            display: flex;
            flex-direction: row;
            flex-wrap: wrap;
            min-height: 125px;
        }

        .options > div
        {
            display: inline-block;
        }

        .spacer {
            flex: 1 1 auto;
        }

        .buttons {
            display: flex;
            flex-direction: row;
            justify-content: space-between;
        }
<div class="container">

        <div class="options">
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
            <div class="option">
                <input type="checkbox"> Option
            </div>
        </div>

        <div class="spacer"></div>

        <div class="buttons">
            <input type="button" value="Cancel">
            <input type="button" value="Save">
        </div>

    </div>
like image 26
Bob Dust Avatar answered Nov 07 '22 03:11

Bob Dust