max-width doesn't work in flexbox - html

I'm trying to get a two-column flexbox with some content on the left, and the remaining space taken up by an image. The image should be centred in the remaining space and shrink-to-fit. Here's what I've got:
* {
box-sizing: border-box;
}
.small_margin {
margin: 5px;
}
.small_padding {
padding: 5px;
}
.red {
background: #faa;
}
.blue {
background: #aaf;
}
.green {
background: #afa;
}
.small_container {
width: 500px;
display: flex;
flex-direction: row;
}
.large_container {
width: 900px;
display: flex;
flex-direction: row;
}
.image {
max-width: 100%; /* Why does this not work? If you change it to a fixed value (not a percentage) it works. */
max-height: 20em;
}
.image_holder {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
}
<div class="red large_container">
<div class="blue small_margin small_padding" style="width: 120px;">
<h1>This Works</h1>
<p>This is what I want when there is space for the full-size image (restricted to its max-height). It should be centred in the div to the right.</p>
<p>This is good.</p>
</div>
<div class="green small_margin image_holder">
<img class="image" src="http://www.gstatic.com/webp/gallery/1.jpg"/>
</div>
</div>
<br>
<div class="red small_container">
<div class="blue small_margin small_padding">
<h1>This Doesn't</h1>
<p>There is now no longer space for the image but instead of reducing its size to 100% of its parent div it just overflows.</p>
</div>
<div class="green small_margin image_holder">
<img class="image" src="http://www.gstatic.com/webp/gallery/1.jpg"/>
</div>
</div>
As you can see, the image overflows the flexbox and isn't shrunk-to-fit by the max-width: 100%. Presumably 100% doesn't actually mean "100% the width of the parent div"?
Anyway, is there any way to make this work?

The image has max-width: 100%. That means that it shouldn't be wider than its parent (the flex item). And this works.
Instead, the problem is that the flex item overflows the flex container. That happens because Flexbox introduces auto as the initial value of min-width. When overflow is visible, that auto forces the flex item to grow so that its content doesn't overflow.
Therefore, you can use min-width: 0.
.image_holder {
min-width: 0;
}
* {
box-sizing: border-box;
}
.small_margin {
margin: 5px;
}
.small_padding {
padding: 5px;
}
.red {
background: #faa;
}
.blue {
background: #aaf;
}
.green {
background: #afa;
}
.small_container {
width: 500px;
display: flex;
flex-direction: row;
}
.large_container {
width: 900px;
display: flex;
flex-direction: row;
}
.image {
max-width: 100%; /* Why does this not work? If you change it to a fixed value (not a percentage) it works. */
max-height: 20em;
}
.image_holder {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
min-width: 0;
}
<div class="red large_container">
<div class="blue small_margin small_padding" style="width: 120px;">
<h1>This Works</h1>
<p>This is what I want when there is space for the full-size image (restricted to its max-height). It should be centred in the div to the right.</p>
<p>This is good.</p>
</div>
<div class="green small_margin image_holder">
<img class="image" src="http://www.gstatic.com/webp/gallery/1.jpg"/>
</div>
</div>
<br>
<div class="red small_container">
<div class="blue small_margin small_padding">
<h1>This Doesn't</h1>
<p>There is now no longer space for the image but instead of reducing its size to 100% of its parent div it just overflows.</p>
</div>
<div class="green small_margin image_holder">
<img class="image" src="http://www.gstatic.com/webp/gallery/1.jpg"/>
</div>
</div>
Then the image won't overflow the flex container. However, it won't mantain its aspect ratio.
To fix that, you can use object-fit:
.image {
object-fit: contain;
}
* {
box-sizing: border-box;
}
.small_margin {
margin: 5px;
}
.small_padding {
padding: 5px;
}
.red {
background: #faa;
}
.blue {
background: #aaf;
}
.green {
background: #afa;
}
.small_container {
width: 500px;
display: flex;
flex-direction: row;
}
.large_container {
width: 900px;
display: flex;
flex-direction: row;
}
.image {
max-width: 100%; /* Why does this not work? If you change it to a fixed value (not a percentage) it works. */
max-height: 20em;
object-fit: contain;
}
.image_holder {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
min-width: 0;
}
<div class="red large_container">
<div class="blue small_margin small_padding" style="width: 120px;">
<h1>This Works</h1>
<p>This is what I want when there is space for the full-size image (restricted to its max-height). It should be centred in the div to the right.</p>
<p>This is good.</p>
</div>
<div class="green small_margin image_holder">
<img class="image" src="http://www.gstatic.com/webp/gallery/1.jpg"/>
</div>
</div>
<br>
<div class="red small_container">
<div class="blue small_margin small_padding">
<h1>This Doesn't</h1>
<p>There is now no longer space for the image but instead of reducing its size to 100% of its parent div it just overflows.</p>
</div>
<div class="green small_margin image_holder">
<img class="image" src="http://www.gstatic.com/webp/gallery/1.jpg"/>
</div>
</div>

Related

When using the flex property image does not scale with its parent div

So I am having an issue with my code. When using the "flex property" and setting it to 2 the image will not scale with the div it is in. I know I can alternatively just remove the image from the div set it to have a display of block and it will increase in size due to its given flex property.
However I want to understand what I am doing wrong here, the image is in a div which is a block level element so why is it that when setting the flex property the image will not scale with the div?
body {
background-color: #696969;
}
.container-1 {
display: flex;
flex-direction: row;
justify-content: center;
}
img {
width: 400px;
height: 300px;
}
.box-1 {
flex: 2;
background-color: blue;
}
<div class="container-1">
<div class="box-1">
<img src="https://picfiles.alphacoders.com/288/288017.jpg" class="wolf-1">
</div>
<div class="box-2">
<img src="https://picfiles.alphacoders.com/288/288017.jpg" class="wolf-2">
</div>
<div class="box-3">
<img src="https://picfiles.alphacoders.com/288/288017.jpg" class="wolf-3">
</div>
</div>
If you want to stratch the image and keep the height add
.box-1 img{
width: 100%;
}
If you want to keep a proper photo proportions add
.box-1 img{
width: 100%;
height: auto;
}
body {
background-color: #696969;
}
.container-1 {
display: flex;
flex-direction: row;
justify-content: center;
}
img {
width: 400px;
height: 300px;
}
.box-1 {
flex: 2;
background-color: blue;
}
.box-1 img{
width: 100%;
height: auto;
}
<div class="container-1">
<div class="box-1">
<img src="https://picfiles.alphacoders.com/288/288017.jpg" class="wolf-1">
</div>
<div class="box-2">
<img src="https://picfiles.alphacoders.com/288/288017.jpg" class="wolf-2">
</div>
<div class="box-3">
<img src="https://picfiles.alphacoders.com/288/288017.jpg" class="wolf-3">
</div>
</div>

Create a circle that fills up the remaining space in a flexbox cell

I have a 2-cell flexbox with a fixed-height (mobile screen), and one cell stacked on top of the other. I need all of the content of the top-cell to be displayed.. the bottom-cell should yield as much space as possible to allow this. This part was easy.
.main-container {
height: 400px;
width: 200px;
display: flex;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background-color: lightgrey;
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space"></div>
</div>
... with that the content-container will grow as needed (in this example it's 100px) and the rest is taken up by the remaining-space cell.
What I need to do is fill the remaining-space cell with a circle that is as big as it can be, but doesn't force the remaining-space cell to grow in height/width... and I need to do it with just html/css.
The only way I've seen to enforce a 1:1 ratio (square/circle) is by using the padding-bottom trick where the padding is calculated using the element's width. This doesn't work for me because remaining-space cell might have a larger width than it's height.. which will cause the cell to grow in height. This is especially difficult in that the container is responsive so the actual width in pixels is never known.
A simple gradient can do it:
.main-container {
height: 400px;
width: 200px;
display: inline-flex;
vertical-align: top;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background:
radial-gradient(circle closest-side, red 98%, transparent)
lightgrey;
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space"></div>
</div>
<div class="main-container" style="height:200px;">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space"></div>
</div>
Clip-path can also do it:
.main-container {
height: 400px;
width: 200px;
display: inline-flex;
vertical-align: top;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background: lightgrey;
}
.remaining-space>div {
height: 100%;
background: red;
clip-path: circle(closest-side)
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div></div>
</div>
</div>
<div class="main-container" style="height:200px;">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div></div>
</div>
</div>
Where you can also have content inside
.main-container {
height: 400px;
width: 200px;
display: inline-flex;
vertical-align: top;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background: lightgrey;
}
.remaining-space>div {
height: 100%;
background: red;
clip-path: circle(closest-side);
display:flex;
align-items:center;
justify-content:center;
font-size:30px;
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div> text </div>
</div>
</div>
<div class="main-container" style="height:200px;">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div> text </div>
</div>
</div>

Why doesn't flex direction column with align-items=center center image properly

I stumbled upon an issue with image centering within a flexbox with direction:column.
Imagine you have two elements within a flexbox, where the first one contains an image:
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
.image-container {
flex: 1;
align-self: center;
.img {
height: 100%;
}
}
.another-flex-child {
flex: none;
background-color: red;
}
}
I would expect the image to be center horizontally within the div, but it appears the left border of the image is exactly at the center of the div.
When I replace the image with another div which contains some text it is placed as expected.
Can anybody explain to me whats happening there?
Checkout this fiddle
Because your <div> that contains the image (and has align-self: center on it) is by default a block-level element, and has a width of 100% by default. As such, it is constrained in relation to the parent.
In order to have your image centered correctly, you'll want to add display: contents with:
container .image-container {
display: inline;
}
This can be seen in the following:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.container .image-container {
flex: 1;
align-self: center;
display: contents;
}
.container .image-container .img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
The issue is that you are using an SVG with no intrinsic dimension and only an intrinsic ratio so it's like your image has a width equal to 0 which make its centred container with a width equal to 0, too.
Here is before using height:100%
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
}
.img {
/*height: 100%;*/
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
After setting height:100% the image will fill all the space and will keep its ratio but you will have an overflow because the browser will not go back to calculate the width of the container again:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg" >
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
To avoid this give the image a width and make sure to add min-height:0 to the container to allow it to shrink
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
min-height:0;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg" width="250">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
If you were initially using an image with intrinsic dimension you won't have this issue and you don't need to define a width. You will only need to add min-height:0 to avoid the overflow:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
min-height:0;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://picsum.photos/id/1/400/400">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
Note that the above doesn't work the same way in Firefox and you will need to add text-aling:center to make sure it works the same everywhere:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
text-align:center;
min-height:0;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://picsum.photos/id/1/400/400">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
You will notice that the difference is related to the width calculation of the container which a bit complex due to the use of height:100%
Things may get worse if the size of the image is very small:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
text-align:center;
min-height:0;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://picsum.photos/id/1/50/50">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
In Firefox text-align:center will do nothing and you may need a nested flexbox container
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
justify-content:center;
border:2px solid blue;
display:flex;
min-height:0;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://picsum.photos/id/1/50/50">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
The below is almost the same issue you were having with the initial SVG that can fixed with this same code but it won't remove the overflow:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
display:flex;
justify-content:center;
border:2px solid blue;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg" >
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
Another intresting thing to note is that your initial code may work fine if you add height:100% to the container making the calculation of the nested height easier:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
box-sizing:border-box;
height:100%;
}
.img {
height: 100%;
display:block;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg" >
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
Add the justify-content like below:
.image-container {
flex: 1;
align-self: center;
justify-content:center;
}
it should works

Centering flex children without extra space

MWE:
https://jsfiddle.net/zjgc9dfx/
Suppose I've got this layout:
<div class="slider">
<span>button here</span>
<div class="slide">
<img src="https://loremflickr.com/1000/1000" alt="Bacn">
</div>
<span>button here</span>
</div>
The slider is a flex container. The two buttons are inline-block, and I want the slide img to be limited to the viewport's height without extra space.
How can I achieve this?
* {
margin: 0;
padding: 0;
}
.slider {
display: flex;
justify-content: center;
align-items: center;
background-color: red;
}
.slider .slide img {
width: 100%;
max-height: 100%;
}
<div class="slider">
<span>asd</span>
<div class="slide">
<img src="https://loremflickr.com/1000/1000" alt="Bacn">
</div>
<span>asd</span>
</div>
Maybe something like this will work:
.slider {
display: flex;
align-items: center;
height: 100vh;
background-color: red;
}
.slider>span {
flex-shrink: 0; /* disables shrinking feature */
}
.slider>.slide {
flex: 1; /* consume all free space */
height: 100%;
}
.slider .slide img {
width: 100%;
max-height: 100%;
object-fit: cover;
vertical-align: bottom; /* https://stackoverflow.com/a/31445364/3597276 */
}
* {
margin: 0;
padding: 0;
}
<div class="slider">
<span>button here</span>
<div class="slide">
<img src="https://loremflickr.com/1000/1000" alt="Bacn">
</div>
<span>button here</span>
</div>
jsFiddle demo

Horizontal centering of 3 flexbox items of the same width

I have been trying to horizontally center these 3 items using flexbox, yet without success. They all need to be of the same width.
HTML:
<div id="contact_flex_container">
<div id="fb">
<img src="img/contact/fb.png" class="contact_img">
<h3>Title1</h3>
</div>
<div id="yt">
<img src="img/contact/yt.png" class="contact_img">
<h3>Title2</h3>
</div>
<div id="mail">
<img src="img/contact/mail.png" class="contact_img">
<h3>Title3</h3>
</div>
</div>
CSS:
#contact_flex_container {
display: flex;
flex-flow: row wrap;
text-align: center;
background-color: red;
width: auto;
justify-content: space-around;
}
.contact_img {
width: 40px;
height: 40px;
}
#fb {
flex-basis: 0;
flex-grow: 1;
}
#yt {
flex-basis: 0;
flex-grow: 1;
}
#mail {
flex-basis: 0;
flex-grow: 1;
}
I have also tried setting margin-left and right to auto for each child, justify-content to center for the container, even combined with fixed width of the container in pixels, yet nothing seems to work. To be more specific, justify-content does not seem to work at all here, whatever value I put there. What am I missing or doing wrong?
The flex properties you are assigning to the flex-items make them all as large as they can be (in this case 33% of the container).
Just remove them, then change the parent to justify-content:center.
#contact_flex_container {
display: flex;
flex-flow: row wrap;
text-align: center;
background-color: red;
width: auto;
justify-content: center
}
.contact_img {
width: 40px;
height: 40px;
}
#fb {} #yt {} #mail {}
<div id="contact_flex_container">
<div id="fb">
<img src="http://lorempixel.com/image_output/abstract-q-c-50-50-5.jpg" class="contact_img">
<h3>Title1</h3>
</div>
<div id="yt">
<img src="http://lorempixel.com/image_output/abstract-q-c-50-50-5.jpg" class="contact_img">
<h3>Title2</h3>
</div>
<div id="mail">
<img src="http://lorempixel.com/image_output/abstract-q-c-50-50-5.jpg" class="contact_img">
<h3>Title3</h3>
</div>
</div>
Alternative, based on the expanded requirement.
An extra wrapper is required which should be inline-flex.
#contact_flex_container {
display: flex;
flex-flow: row wrap;
text-align: center;
background-color: red;
width: auto;
justify-content: center
}
.wrap {
display: inline-flex;
}
.wrap > div {
flex: 1;
border: 1px solid grey;
}
.contact_img {
width: 40px;
height: 40px;
}
<div id="contact_flex_container">
<div class="wrap">
<div id="fb">
<img src="http://lorempixel.com/image_output/abstract-q-c-50-50-5.jpg" class="contact_img">
<h3>Lorem ipsum dolor sit.</h3>
</div>
<div id="yt">
<img src="http://lorempixel.com/image_output/abstract-q-c-50-50-5.jpg" class="contact_img">
<h3>Lorem ipsum.</h3>
</div>
<div id="mail">
<img src="http://lorempixel.com/image_output/abstract-q-c-50-50-5.jpg" class="contact_img">
<h3>Lorem</h3>
</div>
</div>