Flexbox padding bottom fails in Firefox and Safari - css

When scrolling down the .parent div you should see its red background at the bottom due to the padding-bottom. This works in Chrome, but not in Safari and Firefox.
.container {
display: flex;
width: 200px;
height: 500px;
}
.parent {
display: flex;
flex-direction: column;
background: red;
padding-top: 20px;
padding-bottom: 20px;
overflow: auto;
flex: 1;
}
.child {
flex: 1 0 100px;
background: green;
border: 1px solid blue;
}
<div class="container">
<div class="parent">
<div class="child">
child
</div>
<div class="child">
child
</div>
<div class="child">
child
</div>
<div class="child">
child
</div>
<div class="child">
child
</div>
<div class="child">
child
</div>
<div class="child">
child
</div>
</div>
</div>
codepen: http://codepen.io/anon/pen/NpvJPY
Edit: This question is different from the proposed duplicate because it regards a problem with a fixed padding in pixels, as opposed to the percentage padding in the duplicate.

I'm not exactly sure why the padding-bottom fails in Firefox and Safari. It may have something to do with the container being over-constrained. But that's just a guess.
What I am more certain about, however, is a reliable, cross-browser solution. Pseudo-elements on a flex container are rendered as flex items. So instead of padding use ::before and ::after.
.container {
display: flex;
width: 200px;
height: 500px;
}
.parent {
display: flex;
flex-direction: column;
background: red;
/* padding-top: 20px; */
/* padding-bottom: 20px; */
overflow: auto;
flex: 1;
}
/* NEW */
.parent::before,
.parent::after {
flex: 0 0 20px;
content: '';
}
.child {
flex: 1 0 100px;
background: green;
border: 1px solid blue;
}
<div class="container">
<div class="parent">
<div class="child">child</div>
<div class="child">child</div>
<div class="child">child</div>
<div class="child">child</div>
<div class="child">child</div>
<div class="child">child</div>
<div class="child">child</div>
</div>
</div>
revised codepen

Related

flex-column: how to limit the height of grow part so it does not expand?

I'm sure this kind of question was asked before, but I really can't describe it exactly and concisely enough to let the search engine to understand me. So here we go:
To better explain my question I'm writing the code in tailwind style here. A stack snippet is also attached below:
<div class="root w-screen h-screen flex flex-col">
<div class="header h-[72px] w-full bg-red shrink-0"></div>
<div class="content grow">
<!-- a whole lot of content, very tall, height > 2000 px -->
</div>
</div>
In this example, I would like to limit the height of the entire div.root to 100vh. However, because div.content is very tall, it expands the body that it shows a vertical scrollbar.
Well this is fairly easy to overcome, I only need to add scroll-y-auto to div.content. So the body scrollbar disappears, and div.content shows a vertical scrollbar. Perfect.
However later on, I decided to split div.content into two columns: both column shall have its own vertical scrollbar. Intuitively I changed the code to:
<div class="root w-screen h-screen flex flex-col">
<div class="header h-[72px] w-full bg-red shrink-0"></div>
<div class="content grow">
<div class="left overflow-y-auto">
<!-- a whole lot of content, very tall, height > 2000 px -->
</div>
<div class="right overflow-y-auto">
<!-- a whole lot of content, very tall, height > 2000 px -->
</div>
</div>
</div>
But this does not work at all, as the attached snippet demonstrates. body got its scrollbar back, but not div.left or div.right.
I've explored several ways to solve this problem. In the end the best solution I got was to set the height of div.content to calc(100% - 72px). This works perfectly, but I understand it's only because I know the exact height of div.header is fixed at 72px.
Was I doing something wrong here? What's the most elegant way to solve this kind of problem?
body {
margin: 0;
}
.root {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
height: 72px;
width: 100%;
background-color: red;
flex-shrink: 0;
}
.content {
flex-grow: 1;
display: flex;
flex-direction: row;
}
.very-tall-content {
background-color: green;
height: 2400px
}
.left, .right {
flex-grow: 1;
margin: 0 4px;
overflow-y: auto;
}
<div class="root">
<div class="header"></div>
<div class="content">
<div class="left">
<p class="very-tall-content"></p>
</div>
<div class="right">
<p class="very-tall-content"></p>
</div>
</div>
</div>
Allright, try this one maybe it fixed your problem :)
instead of using flex for .root use grid. down here we have a
header with minimum height of 72px and if it's content overloads, the
header will auto-fit them
:root {
--header-min-height: 72px;
}
body {
margin: 0;
}
.root {
display: grid;
grid-template-rows: minmax(var(--header-min-height), auto) 1fr;
height: 100vh;
}
.header {
grid-row: 1;
background: darkcyan;
}
.content {
grid-row: 2;
display: flex;
background-color: palegreen;
overflow-y: hidden;
}
.content>div {
flex-grow: 1;
overflow-y: auto;
}
.white-space {
height: 3000px;
}
<div class="root">
<div class="header"></div>
<div class="content">
<div class="left">
Left Side
<div class="white-space"></div>
Left Side
</div>
<div class="right">
Right Side
<div class="white-space"></div>
Right Side
</div>
</div>
</div>
here's the example if it overloads.
:root {
--header-min-height: 72px;
}
body {
margin: 0;
}
.root {
display: grid;
grid-template-rows: minmax(var(--header-min-height), auto) 1fr;
height: 100vh;
}
.header {
grid-row: 1;
background: darkcyan;
}
.content {
grid-row: 2;
display: flex;
background-color: palegreen;
overflow-y: hidden;
}
.content>div {
flex-grow: 1;
overflow-y: auto;
}
.white-space {
height: 3000px;
}
.row {
display: flex;
flex-direction: row;
width: fit-content;
}
.item {
background: rgba(255, 255, 255, .5);
width: fit-content;
padding: 10px;
margin: 5px;
border-radius: 5px;
}
<div class="root">
<div class="header">
<div class="row">
<div class="item">test</div>
<div class="item">test</div>
<div class="item">test</div>
</div>
<div class="row">
<div class="item">test</div>
<div class="item">test</div>
<div class="item">test</div>
</div>
<div class="row">
<div class="item">test</div>
<div class="item">test</div>
<div class="item">test</div>
</div>
</div>
<div class="content">
<div class="left">
Left Side
<div class="white-space"></div>
Left Side
</div>
<div class="right">
Right Side
<div class="white-space"></div>
Right Side
</div>
</div>
</div>

Balancing column width in flexbox and grid

I've got two columns in a parent container of 600px width. The children’s character length dictates the column width (weighted split). However, as both columns become increasingly similar in their width, a balanced (50/50 split) layout should be preferred, illustrated below.
Is it possible to achieve this kind of layout in flexbox or grid, without javascript? I imagine determining string length and switching css properties according to a threshold would be an option that I don't want to go down.
My intention isn't to create a single type of split but rather to make the layout respect both splits conditionally.
.container {
outline: 1px solid red;
width: 100%;
height: 60px;
display: flex;
}
.child {
padding: 0.5px;
outline: 1px solid black;
display: grid;
place-content: center;
}
.grow {
flex-grow: 1; /* flexible split */
}
.balanced {
width: 100%; /* 50-50 split */
}
<div class="container">
<div class="child grow">
asdasdasdasd
</div>
<div class="child grow">
asdaassdasdasdsdasdasd
</div>
</div>
<div class="container">
<div class="child balanced">
asdasdasdasd
</div>
<div class="child balanced">
asdaassdasdasdsdasdasd
</div>
</div>
Just add a maximum width?
.container {
outline: 1px solid red;
width: 100%;
height: 60px;
display: flex;
}
.child {
padding: 0.5px;
outline: 1px solid black;
display: grid;
place-content: center;
}
.grow {
flex-grow: 1;
max-width:50%;
}
.balanced {
width: 100%;
/* 50-50 split */
}
<div class="container">
<div class="child grow">
asdasdasdasd
</div>
<div class="child grow">
asdaassdasdasdsdasdasd
</div>
</div>
<div class="container">
<div class="child balanced">
asdasdasdasd
</div>
<div class="child balanced">
asdaassdasdasdsdasdasd
</div>
</div>
Isn't flex-grow alone solving directly your problem?
See the snippet:
.container {
outline: 1px solid red;
width: 100%;
height: 60px;
display: flex;
}
.child {
padding: 0.5px;
outline: 1px solid black;
display: grid;
flex-grow: 1; /* flexible split */
place-content: center;
}
<div class="container">
<div class="child">
asdasd
</div>
<div class="child">
asdaassdasdasdsdasdasd
</div>
</div>
<div class="container">
<div class="child">
asdasdasdasd
</div>
<div class="child">
asdaassdasdasdsdasdasd
</div>
</div>
<div class="container">
<div class="child">
asdaassdasdasdsdasdasd
</div>
<div class="child">
asdaassdasdasdsdasdasd
</div>
</div>
In the meantime I found the answer.
Setting flex-basis enforces a 50/50 split when column width is similar. The unequal split is respected by setting flex-grow and flex-shrink.
.parent {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 50%;
padding-right: 1em;
padding-left: 1em;
}

Flexbox item does not shrink when only one item [duplicate]

This question already has answers here:
Why don't flex items shrink past content size?
(5 answers)
Closed 3 years ago.
In flexbox, if you set flex-flow: column nowrap and the elements inside have non-zero value of flex shrink, they should shrink down to all fit inside the flex container.
I have found that if you have only one item in this container and it has content bigger than the flex-container then it will not shrink down. But if other elements are included in the container (if it is not the only item) then it will shrink down.
Best visualized in this CodePen.
Here is the same code from the CodePen.
.container {
padding: 10px;
height: 100px;
width: 100px;
background: red;
margin: 5px 20px;
display: flex;
flex-flow: column nowrap;
align-items: center;
}
.item {
width: 80px;
height: 40px;
background: blue;
margin: 5px;
/* same as
flex: 1 1 40px;
*/
}
.super.item {
height: 200px;
}
.item div {
width: 10px;
height: 150px;
background: black;
}
body {
margin: 0;
display: flex;
}
<div class='container'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'>
</div>
</div>
<div class='container'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'>
<div></div>
</div>
</div>
<div class='container'>
<div class='item super'>
</div>
</div>
<div class='container'>
<div class='item super'>
<div></div>
</div>
</div>
Is there an explanation on why that last div does not shrink to fit the flex container?
What about making the height of those contents inherit their parent's one?
.super.item {
height: inherit;
}
.item div {
width: 10px;
height: inherit;
background: black;
}
Snippet below, is that what you're trying to achieve? :
.container {
padding: 10px;
height: 100px;
width: 100px;
background: red;
margin: 5px 20px;
display: flex;
flex-flow: column nowrap;
align-items: center;
}
.item {
width: 80px;
height: 40px;
background: blue;
margin: 5px;
/* same as
flex: 1 1 40px;
*/
}
.super.item {
height: inherit;
}
.item div {
width: 10px;
height: inherit;
background: black;
}
body {
margin: 0;
display: flex;
}
<div class='container'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'>
</div>
</div>
<div class='container'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'>
<div></div>
</div>
</div>
<div class='container'>
<div class='item super'>
</div>
</div>
<div class='container'>
<div class='item super'>
<div></div>
</div>
</div>
I don't know if you are talking about it or not.
Your div is taking width and height as item.
so whenever you add another div it will add height of 150px.
.item div{
width: 10px;
height: 150px;
background: black;
}
Very simple rule for items of a flexbox:
Items grow value is 0 and shrink is 1 and the base-case is auto.
flex: 0 1 auto
So
.item{
width: 80px;
height: 40px; # will be used as base-case
background: blue;
margin: 5px;
/* same as
flex: 1 1 40px;
*/
}
Why does second container's item shrink? Easy. base-case is 40px or on the other hand it dose not have the class .super. Add .super and see what happens.
<div class='container'>
<div class='item'></div>
<div class='item'></div>
<div class='item'></div>
<div class='item'> # flex's item height: 40px;
<div></div> # regular div
</div>
</div>
Why the third container that has the class .super does shrink? while height: 200px and it should overflow? Easy. it is the same as: flex: 0 1 200px (this is not quite right, see the comment below, what #TemaniAfif has pointed out)
try it:
.super.item{
/* height: 200px; */
flex: 0 1 200px; # equal to height: 200px
}
now try this:
.super.item{
/* height: 200px; */
flex: 0 0 200px; # turn off auto grow / shrink
}
Why the fourth overflows?. Easy. the item has a child that is a regular div
<div class='container'>
<div class='item super'> # flex's item
<div></div> # regular div
</div>
</div>
and the height of this div is 150px
.item div{
width: 10px;
height: 150px; # remove this one, it shrinks
background: black;
}

Flexbox not working properly on chrome

I'm using the following code to display 5 images (without the use of background) distributed evenly across a container and with an equal height equivalent to the tallest image (although I wonder if it would be possible to do this with the shortest one). Applying flex: 1; on the image-container gives me the desired effect under firefox, but under chrome the 5 images appear vertically stretched and oversized. The desired effect is to keep every container filled under a given width while minimizing loss of aspect ratio.
Edit: I've loaded this page under both browsers and I do get the effect I wanted although they are rendered differently. Now I need to find what's wrong with my version compared to the one I posted here.
body {
width: 300px;
}
.container {
display: flex;
flex-wrap: wrap;
height: 100%;
width: 100%;
background-color: black;
}
.row1 {
display: flex;
width: 100%;
background-color: blue;
}
.column {
height: 100%;
width: 20%;
display: flex;
flex-flow: column;
position: relative;
background-color: red;
}
.image-container {
overflow: hidden;
display: flex;
flex: 1;
background-color: yellow;
}
img {
width: 100%;
height: auto;
}
.image-label {
width: 100%;
height: 35px;
display: flex;
background-color: green;
justify-content: center;
}
.row2 {
display: flex;
width: 100%;
flex-flow: row wrap;
background-color: cyan;
height: 20px;
}
<div class="container">
<div class="row1">
<div class="column">
<div class="image-container">
<img src="http://www.koka.ac.jp/admission/wp-content/themes/admission/assets/img/common/floating-btn-internet.gif">
</div>
<div class="image-label">img1</div>
</div>
<div class="column">
<div class="image-container">
<img src="http://www.moglix.com/themes/et_poostyle/img/offer.jpg">
</div>
<div class="image-label">img2</div>
</div>
<div class="column">
<div class="image-container">
<img src="http://i.imgur.com/slhFy4T.png">
</div>
<div class="image-label">img3</div>
</div>
<div class="column">
<div class="image-container">
<img src="http://alma-sys.com/images/SLIDE%20MENU%20IMG/WEB%20D%20-%20Copy.jpg">
</div>
<div class="image-label">img4</div>
</div>
<div class="column">
<div class="image-container">
<img src="http://amerpages.com/app/webroot/img/items/121/16716/pds/19682_s.jpg">
</div>
<div class="image-label">img5</div>
</div>
</div>
<div class="row2"></div>
</div>

Reorder columns in reverse order

I have a list of flex items within a flexbox. The order of the items matter, and for accessibility purposes, the items need to show up in the correct order in the dom.
[[itema][itemb][itemc]]
When the flexbox shrinks I would like to have the items wrap in reverse order, e.g. itema wraps first, etc. Is there any way to have the itema wrap first? Thanks!
Edit:
Here is the code
<div class="flex">
<div class="container">
<div class="item">item1</div>
<div class="item orange">item2</div>
<div class="item blue">item3</div>
</div>
<div class="last-item green">menu</div>
</div>
.flex {
display: flex;
background-color: yellow;
height: 80px;
overflow: hidden;
color: #fff;
}
.container {
display: flex;
flex: 1 1 auto;
flex-wrap: wrap;
}
.item {
flex: 0 0 auto;
background-color: red;
height: 80px;
padding: 0 40px;
}
.last-item {
width: 40px;
flex: 0 0 auto;
height: 80px;
}
JSFiddle
All the behavior is as desired except I want the first item to wrap first. Any ideas? Thanks!
You can use the flex-direction: column-reverse to get your solution.
#media (max-width: 768px) {
.flex-box {
display: flex;
flex-direction: column-reverse;
}
}
.first,
.second,
.third {
display: inline-block;
}
<div class="flex-box">
<div class="first">
<p>First Box</p>
<img src="http://placehold.it/300x300" />
</div>
<div class="second">
<p>Second Box</p>
<img src="http://placehold.it/300x300" />
</div>
<div class="third">
<p>Third Box</p>
<img src="http://placehold.it/300x300" />
</div>
</div>
JSfiddle Demo
To make item1 wrap first, you can use flex-wrap: wrap-reverse on your flex container.
Try this simplified version of you code:
<div class="container">
<div class="item">item1</div>
<div class="item orange">item2</div>
<div class="item blue">item3</div>
</div>
.container {
display: flex;
flex: 0 1 auto;
flex-wrap: wrap-reverse;
}
.item {
background-color: red;
height: 80px;
padding: 0 40px;
}
.orange {
background-color: orange;
}
.blue {
background-color: blue
}
See the MDN reference for browser support.

Resources