Why don't flex items shrink past content size?
The Automatic Minimum Size of Flex Items
You're encountering a flexbox default setting.
A flex item cannot be smaller than the size of its content along the main axis.
The defaults are...
min-width: auto
min-height: auto
...for flex items in row-direction and column-direction, respectively.
You can override these defaults by setting flex items to:
min-width: 0
min-height: 0
overflow: hidden
(or any other value, exceptvisible
)
Flexbox Specification
4.5. Automatic Minimum Size of Flex
ItemsTo provide a more reasonable default minimum size for flex items, this
specification introduces a newauto
value as the initial value of
themin-width
andmin-height
properties defined in CSS 2.1.
With regard to the auto
value...
On a flex item whose
overflow
isvisible
in the main axis, when specified on the flex item’s main-axis min-size property, specifies an automatic minimum size. It otherwise computes to0
.
In other words:
- The
min-width: auto
andmin-height: auto
defaults apply only whenoverflow
isvisible
. - If the
overflow
value is notvisible
, the value of the min-size property is0
. - Hence,
overflow: hidden
can be a substitute formin-width: 0
andmin-height: 0
.
and...
- The minimum sizing algorithm applies only on the main axis.
- For example, a flex item in a row-direction container does not get
min-height: auto
by default. - For a more detailed explanation see this post:
- min-width rendering differently in flex-direction: row and flex-direction: column
You've applied min-width: 0 and the item still doesn't shrink?
Nested Flex Containers
If you're dealing with flex items on multiple levels of the HTML structure, it may be necessary to override the default min-width: auto
/ min-height: auto
on items at higher levels.
Basically, a higher level flex item with min-width: auto
can prevent shrinking on items nested below with min-width: 0
.
Examples:
- Flex item is not shrinking smaller than its content
- Fitting child into parent
- white-space css property is creating issues with flex
Browser Rendering Notes
Chrome vs. Firefox / Edge
Since at least 2017, it appears that Chrome is either (1) reverting back to the
min-width: 0
/min-height: 0
defaults, or (2) automatically applying the0
defaults in certain situations based on a mystery algorithm. (This could be what they call an intervention.) As a result, many people are seeing their layout (especially desired scrollbars) work as expected in Chrome, but not in Firefox / Edge. This issue is covered in more detail here: flex-shrink discrepancy between Firefox and ChromeIE11
As noted in the spec, the
auto
value for themin-width
andmin-height
properties is "new". This means that some browsers may still render a0
value by default, because they implemented flex layout before the value was updated and because0
is the initial value formin-width
andmin-height
in CSS 2.1. One such browser is IE11. Other browsers have updated to the newerauto
value as defined in the flexbox spec.
Revised Demo
.container { display: flex;}
.col { min-height: 200px; padding: 30px; word-break: break-word}
.col1 { flex: 1; background: orange; font-size: 80px; min-width: 0; /* NEW */}
.col2 { flex: 3; background: yellow}
.col3 { flex: 4; background: skyblue}
.col4 { flex: 4; background: red}
<div class="container"> <div class="col col1">Lorem ipsum dolor</div> <div class="col col2">Lorem ipsum dolor</div> <div class="col col3">Lorem ipsum dolor</div> <div class="col col4">Lorem ipsum dolor</div></div>
Flex item is not shrinking smaller than its content
Sometimes you need to look at all flex items (up and down the HTML structure), and check to see if they need the overflow
/ min-width
override.
In this case, there are flex items at higher levels that still default to min-width: auto
, preventing the reduction in size.
.mdc-list-item { flex-shrink: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;}.mdc-list { display: flex; flex-direction: column;}
/* RULES ADDED */.mdc-list { min-width: 0;}.mdc-list-item__text { overflow: hidden;}.mdc-list-item__text__secondary { text-overflow: ellipsis; overflow: hidden;}
<script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.js"></script><link href="https://unpkg.com/material-components-web@latest/dist/material-components-web.css" rel="stylesheet" /><div style="width: 100%; max-width: 800px; margin: 0 auto; display: flex;"> <ul class="mdc-list mdc-list--two-line mdc-elevation--z1" style="flex: 1;"> <li class="mdc-list-item" title="Test Item 1 Description" channel-id="1"> <img class="mdc-list-item__start-detail grey-bg" style="width: 40px; height: 40px;" src="https://material-components-web.appspot.com/images/animal3.svg" alt="Brown Bear">
<span class="mdc-list-item__text"> Test Item 1 <span class="mdc-list-item__text__secondary">Test Item 1 Description</span> </span>
<div class="mdc-list-item__end-detail"> <i class="mdc-icon-toggle material-icons color-primary-text-inv toggle-notifications-email" style="margin-top: -12px;" role="button"> X </i> </div> <div class="mdc-list-item__end-detail" style="margin-left: 64px;"> <i class="mdc-icon-toggle material-icons color-primary-text-inv toggle-notifications-notification" style="margin-top: -12px; margin-left: -24px;" role="button"> Y </i> </div> </li> <li role="separator" class="mdc-list-divider"></li> <li class="mdc-list-item" title="Here you can read the long description of Item 2 which refuses to shrink" channel-id="2"> <img class="mdc-list-item__start-detail grey-bg" style="width: 40px; height: 40px;" src="https://material-components-web.appspot.com/images/animal3.svg" alt="Brown Bear">
<span class="mdc-list-item__text"> Test Item 2 <span class="mdc-list-item__text__secondary">Here you can read the long description of Item 2 which refuses to shrink</span> </span>
<div class="mdc-list-item__end-detail"> <i class="mdc-icon-toggle material-icons color-primary-text-inv toggle-notifications-email" style="margin-top: -12px;" role="button"> X </i> </div> <div class="mdc-list-item__end-detail" style="margin-left: 64px;"> <i class="mdc-icon-toggle material-icons color-primary-text-inv toggle-notifications-notification" style="margin-top: -12px; margin-left: -24px;" role="button"> Y </i> </div> </li> </ul></div>
Why does width % on flex-container shrink past its contents, but flex-basis does not?
To understand this you need to consider two concepts: The "flex base size" and the "main size".
It's a bit tricky to explain but if you refer to the full algorithm in the specification You will notice that we first calculate the "flex base size" and later we calculate the "hypothetical main size" which is the final size.
For the "hypothetical main size":
The hypothetical main size is the item’s flex base size clamped according to its used min and max main sizes (and flooring the content box size at zero).
When you use width
you are affecting the "main sizes" that is used to define the final width (the "hypothetical main size"). In other words, it's not only the min-width
that is responsible of the non-shrinking effect but it's the "min max main sizes".
Here is another example to better understand:
.flex-container {
display: flex;
background-color: DodgerBlue;
}
.flex-container>div {
background-color: #f1f1f1;
margin: 2px;
padding: 2px;
font-size: 30px;
flex-basis: 20%;
width: 40px;
}
<div class="flex-container">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
Flex items not shrinking when window gets smaller
An initial setting on flex items is min-width: auto
. This means that a flex item cannot, by default, be smaller than its content.
You can override this setting with min-width: 0
or overflow
with any value other than visible
. Add this to your code:
.plot-col {
min-width: 0;
}
Revised Fiddle
More info: Why doesn't flex item shrink past content size?
flex items not expanding or shrinking with flex-grow
There are two pieces missing in this puzzle.
You have the column widths set to
flex-grow: 1
. This means thatflex-basis
is still at its default value,auto
(content-based). So the column is sized based on the image size. You can addflex-basis: 0
, or just useflex: 1
.Full explanation: Make flex-grow expand items based on their original size
Flex items, by default, cannot shrink below the size of their content. Their initial setting is
min-width: auto
. You need to override this default withmin-width: 0
.Full explanation: Why don't flex items shrink past content size?
.row {
display: flex;
height: 100vh;
}
.column {
min-width: 0; /* new */
flex: 1; /* adjustment */
border: 2px solid #000;
transition: all 300ms ease-in-out;
}
.column:hover {
flex-grow: 4.3;
}
body {
margin: 0;
}
<div class="row">
<div class="column">
<img src="https://images.pexels.com/photos/2194261/pexels-photo-2194261.jpeg">
</div>
<div class="column">
<img src="https://images.pexels.com/photos/1276553/pexels-photo-1276553.jpeg">
</div>
<div class="column">
<img src="https://images.pexels.com/photos/774731/pexels-photo-774731.jpeg">
</div>
</div>
Flex parent won't shrink past child content, even though child has `0` computed width
From all the answers so far, I understand there's no clean CSS way to reduce the size of the parent based on computed widths of all children, while the children are being animated, using flexbox.
Technically, this means flexbox props (-shrink
, -basis
, -grow
) can't be used to animate here and (max-)width
should be used instead. I must admit, I still find it hard to believe. I would have thought flexbox got this covered.
The problem with animating max-width
or width
is you can't animate from 0
to auto
without JavaScript.
Which leads to the following solution:
[...document.querySelectorAll('.flexer')].forEach(el => {
const item = el.querySelector('.extra');
if (item) {
el.onmouseenter = () => {
item.style.maxWidth = item.scrollWidth + 'px'
}
el.onmouseleave = () => {
item.style.maxWidth = '0'
}
}
})
.flexer {
display: inline-flex;
border: 1px solid red;
}
.extra {
transition: max-width .42s cubic-bezier(.4, 0, .2, 1);
overflow: hidden;
max-width: 0;
white-space: nowrap;
}
<div class="flexer">
<div>
test
</div>
<div class="extra">
extra
</div>
</div>
<div class="flexer">
<div>
test
</div>
<div class="extra">
I have a lot more content...
</div>
</div>
Related Topics
How to Playback Mkv Video in Web Browser
How to Reuse a Navigation Bar on Multiple Pages
How to Set Space Between Contained Divs
How to Hide an HTML Table Row <Tr> So That It Takes Up No Space
How to Remove Specific Text With CSS
How to Make Div Have 100% Height of Parent, Independent of Children'S Size? Complex Layout
Css Absolute Position With X Scrolling
Material Design - Stepper How to Remove/Disable Steps
Using HTML Anchor Link #Id in Angular 6
Chrome User Agent Stylesheet Overwriting My Site Style
Error Error: Formcontrolname Must Be Used With a Parent Formgroup Directive
How to Remove Indentation from an Unordered List Item
How to Detect When Cancel Is Clicked on File Input
How to Open Excel File in Browser, Not in Excel Application
Difference Between Id and Name Attributes in Html
≪Button≫ Vs. ≪Input Type="Button" /≫. Which to Use