Roman Roman
Roman Roman

Reputation: 927

Why flex-shrink behaves this way in my example?

Could you give me an explanation of what is going here? (If it's possible attach links to the CSS spec)

When I set flex-shrink to 0 on #grid-container (flex: 1 0 auto), there appears a scroll bar for the whole page

But when I set flex-shrink to 1 on #grid-container (flex: 1 1 auto), the bar scroll bar appears only for the #grid-container

In the code snippet below flex-shrink on #grid-container is set to to 0 (flex: 1 0 auto). Change it to 1(flex: 1 1 auto) to see the difference

html {
  height: 100%;
}

body {
  display: flex;
  flex-direction: column;
  height: 100%;
  margin: 0;
}

#header {
  background-color: brown;
  flex: 0 0 100px;
}

#grid-container {
  flex: 1 1 auto;
  display: grid;
  overflow: hidden;
  grid-template-rows: 1fr;
  grid-template-columns: 1fr; 
}

#grid-item {
  grid-column: 1/2;
  grid-row: 1/2;
  overflow: auto;
}

#list {
  overflow: auto;
}

#list-item {
  font-size: 140px;
}
<html>
<head>
  <meta charset="utf-8">
  <title>Page Title</title>
</head>
<body>
  <div id="header"></div>
  <div id="grid-container">
    <div id="grid-item">
      <div id="list">
        <div id="list-item">1</div>
        <div id="list-item">2</div>
        <div id="list-item">3</div>
        <div id="list-item">4</div>
        <div id="list-item">5</div>
        <div id="list-item">6</div>
      </div>
  </div>
  </div>
</body>
</html>

Upvotes: 5

Views: 89

Answers (1)

Temani Afif
Temani Afif

Reputation: 274384

By setting flex-shrink:1 (the default value) you allow your element to shrink inside its flex container and since you set the body (the flex container) to be height:100% it will shrink to fit inside it creating the scroll bar only on the container because its content is overflowing. Te be more accurate the scroll bar is on #grid-item and not the container which is logical since this one is having overflow:auto.

Add border to better see this:

html {
  height: 100%;
  background:#fff;
}

body {
  display: flex;
  flex-direction: column;
  height: 100%;
  margin: 0;
  background:red;
}

#header {
  background-color: brown;
  flex: 0 0 100px;
}

#grid-container {
  flex: 1 1 auto;
  display: grid;
  overflow: hidden;
  grid-template-rows: 1fr;
  grid-template-columns: 1fr; 
  border:5px solid green;
}

#grid-item {
  grid-column: 1/2;
  grid-row: 1/2;
  overflow: auto;  
  border:5px solid blue;
}

#list {
 /* overflow: auto;  not needed*/
  border:5px solid yellow;
}

#list-item {
  font-size: 140px;
}
<html>
<head>
  <meta charset="utf-8">
  <title>Page Title</title>
</head>
<body>
  <div id="header"></div>
  <div id="grid-container">
    <div id="grid-item">
      <div id="list">
        <div id="list-item">1</div>
        <div id="list-item">2</div>
        <div id="list-item">3</div>
        <div id="list-item">4</div>
        <div id="list-item">5</div>
        <div id="list-item">6</div>
      </div>
  </div>
  </div>
</body>
</html>

You can also set overflow:auto to the container and you will have the scroll on the container and almost the same result

html {
  height: 100%;
  background:#fff;
}

body {
  display: flex;
  flex-direction: column;
  height: 100%;
  margin: 0;
  background:red;
}

#header {
  background-color: brown;
  flex: 0 0 100px;
}

#grid-container {
  flex: 1 1 auto;
  display: grid;
  overflow: auto;
  grid-template-rows: 1fr;
  grid-template-columns: 1fr; 
  border:5px solid green;
}

#grid-item {
  grid-column: 1/2;
  grid-row: 1/2; 
  border:5px solid blue;
}

#list {
 /* overflow: auto;  not needed*/
  border:5px solid yellow;
}

#list-item {
  font-size: 140px;
}
<html>
<head>
  <meta charset="utf-8">
  <title>Page Title</title>
</head>
<body>
  <div id="header"></div>
  <div id="grid-container">
    <div id="grid-item">
      <div id="list">
        <div id="list-item">1</div>
        <div id="list-item">2</div>
        <div id="list-item">3</div>
        <div id="list-item">4</div>
        <div id="list-item">5</div>
        <div id="list-item">6</div>
      </div>
  </div>
  </div>
</body>
</html>


By disabling the shrink, the element and its content will overflow outside the body and also the html which will create a scroll bar on the viewport to be able to see the overflowing content. Adding overflow:auto is useless in this case since the parent height is the same as the content height.

Add background to body/html elements to better see the overflow when disabling the shrink

html {
  height: 100%;
  background:#fff; /*to stop the propagation of the red color*/
  border:5px dotted purple;
}

body {
  display: flex;
  flex-direction: column;
  height: 100%;
  margin: 0;
  background:red;
}

#header {
  background-color: brown;
  flex: 0 0 100px;
}

#grid-container {
  flex: 1 0 auto;
  display: grid;
  overflow: hidden;
  grid-template-rows: 1fr;
  grid-template-columns: 1fr; 
  border:5px solid green;
}

#grid-item {
  grid-column: 1/2;
  grid-row: 1/2;
  overflow: auto;  
  border:5px solid blue;
}

#list {
 /* overflow: auto;  not needed*/
}

#list-item {
  font-size: 140px;
}
<html>
<head>
  <meta charset="utf-8">
  <title>Page Title</title>
</head>
<body>
  <div id="header"></div>
  <div id="grid-container">
    <div id="grid-item">
      <div id="list">
        <div id="list-item">1</div>
        <div id="list-item">2</div>
        <div id="list-item">3</div>
        <div id="list-item">4</div>
        <div id="list-item">5</div>
        <div id="list-item">6</div>
      </div>
  </div>
  </div>
</body>
</html>

Related: Why is a flex-child limited to parent size?


As a side note, if you remove overflow:hidden from the container the result will be the same for both cases:

html {
  height: 100%;
  background:#fff;
}

body {
  display: flex;
  flex-direction: column;
  height: 100%;
  margin: 0;
  background:red;
}

#header {
  background-color: brown;
  flex: 0 0 100px;
}

#grid-container {
  flex: 1 1 auto;
  display: grid;
  grid-template-rows: 1fr;
  grid-template-columns: 1fr; 
  border:5px solid green;
}

#grid-item {
  grid-column: 1/2;
  grid-row: 1/2;
  overflow: auto;   /*will do nothing*/
  border:5px solid blue;
}

#list {
 /* overflow: auto;  not needed*/
  border:5px solid yellow;
}

#list-item {
  font-size: 140px;
}
<html>
<head>
  <meta charset="utf-8">
  <title>Page Title</title>
</head>
<body>
  <div id="header"></div>
  <div id="grid-container">
    <div id="grid-item">
      <div id="list">
        <div id="list-item">1</div>
        <div id="list-item">2</div>
        <div id="list-item">3</div>
        <div id="list-item">4</div>
        <div id="list-item">5</div>
        <div id="list-item">6</div>
      </div>
  </div>
  </div>
</body>
</html>

This is due to The Automatic Minimum Size of Flex Items that will prevent the shrink effect.

Upvotes: 2

Related Questions