flex-basis: 0 not respecting parent height in safari - html

below is the code which works on chrome and firefox in which the img respects the parent height and fits into it but in safari, the image overflows.
I can fix this by adding overflow: hidden or removing the flex-basis.
can someone share info on it?
also, it's 2023 and flexbox is almost stable. Is this bug in safari?
.parent {
display: flex;
flex-direction: column;
height: 200px;
overflow: hidden;
border: 1px solid red;
}
.child {
display: flex;
flex-basis: 0;
height: 100%;
}
.innerChild {
height: 100%;
}
img {
max-height: 100%;
}
<div class="parent">
<div class="child">
<div class="innerChild">
<img src="https://picsum.photos/id/237/200/600"/>
</div>
</div>
</div>
safari snapshot
chrome snapshot

You can add the prop object-fit to your img so it can covers the entire width of its parent container:
img {
max-height: 100%;
width: 100%;
object-fit: cover;
}

Related

Why does using flex wrap break the height of an item containing large images?

I have set up a simple page using a container with Flexbox enabled and 2 child divs.
Sizes are set using view width and view height for the container.
Child divs are set to a 600px and 400px width using css flex shorthand.
A large image has been added to child one and resized to 100%.
This works perfectly until flex-wrap: wrap is enabled on the container.
Then the height of the children are suddenly to big.
Is there a way to fix this behaviour?
Below is my code.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.flex-container {
width: 100vw;
height: 100vh;
display: flex;
flex-wrap: wrap;
}
.flex-item1 {
flex: 1 1 600px;
padding: 20px;
background-color: coral;
}
.flex-item2 {
flex: 1 1 400px;
padding: 20px;
background-color: cornflowerblue;
}
.image {
height: 100%;
width: 100%;
object-fit: contain;
}
<div class="flex-container">
<div class="flex-item1">
<img src="https://picsum.photos/1000/2000" class="image" alt="image" />
</div>
<div class="flex-item2">
<h1>Header 1</h1>
</div>
Just add this to your code:
.flex-item1 {
height: 100%;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.flex-container {
width: 100vw;
height: 100vh;
display: flex;
flex-wrap: wrap;
}
.flex-item1 {
flex: 1 1 600px;
padding: 20px;
background-color: coral;
height: 100%; /* new */
}
.flex-item2 {
flex: 1 1 400px;
padding: 20px;
background-color: cornflowerblue;
}
.image {
height: 100%;
width: 100%;
object-fit: contain;
}
<div class="flex-container">
<div class="flex-item1">
<img src="https://picsum.photos/1000/2000" class="image" alt="image" />
</div>
<div class="flex-item2">
<h1>Header 1</h1>
</div>
With a single line flex container (flex-wrap: nowrap), the height: 100% on the container is recognized by the height: 100% on the image (2 levels down).
With a multi-line flex container (flex-wrap: wrap), the height: 100% on the container isn't inherited by the image. The percentage height chain breaks. So you need to add height: 100% to the middle link (the flex item), for the layout to work in both cases.
Not exactly sure why this happens. Would have to research it.

how to stop images within a flexbox container ignoring the heigth set by parent?

For the past couple of days, I thought the issue I've been having was with the API that i was using but after stumbling upon this article talking about flex:1 issues I've discovered it's not.
The article addresses the issue but not for images what's the fix?
HTML
<div className="App">
<div className="box1">
<img src={image} />
</div>
<div className="box2" />
<div className="box3" />
</div>
Scss
.App {
height: 100vh;
width: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
.box1{
flex: 1;
background: blue;
display: flex;
flex-direction: column;
img{
margin: auto;
width: auto;
height: auto;
max-width: 100%;
max-height: 300px;
//try max height 100% breakesit
//max-height: 100%
object-fit: cover;
background-repeat: no-repeat;
}
}
.box2{
background: purple;
height:200px;
}
.box3{
background: green;
height: 250px;
}
}
Sandbox
I would the like the image to take up 100% of the parent divs height is this possible?
I finally found a reasonable fix not using a background image but playing further with flex box! here's my solution:
HTML
<div className="App">
<div className="box1">
<img src={image} />
</div>
<div className="box2" />
<div className="box3" />
</div>
It turns out as far as I can understand images have there own unique
flex-basis property based on there actual size which is different from
every other element and they use this as there default flex property
which they grow or shrink from, so setting this value to
0(flex-basis:0) makes it behave the same way as a regular element.
The only issue with this on its own is the height of the image will
stay at 0px no matter the percentage set this can simply be fixed by
adding the flex-grow:1 property
Sass
.App {
height: 100vh;
width: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
.box1{
display: flex;
width: 100%;
height: 100%;
flex-grow: 1;
flex-basis: 0;
background: blue;
overflow: hidden;
img{
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
object-fit: cover;
background-repeat: no-repeat;
margin: auto;
}
}
.box2{
background: purple;
height:200px;
}
.box3{
background: green;
height: 250px;
}
}
Here's a code sandbox demonstrating for you to play around with as this seems to be a largely unanswered question hope it helps some people who were struggling as much as I was!
You can use your image as a background of the div
.box1{
background-repeat: no-repeat;
background-size: 100% 100%;
}
<div className="box1" style={{background: `url(${image})`}}>

Display images in flexbox at 100% height without scrollbar

I'm trying to display an app bar and three images in a column, that uses 100% of the height of the screen. The images are supposed to use the whole width of the column with the rest being cut off. I can get it working with just divs, but I'm having trouble when using images.
Here is a version to illustrate how it should look like. This has an app bar of height 50 and three "images" that fill the rest of the space:
https://codepen.io/Meerpohl/pen/zYxRKRV
And here is what I get with images. The images stretch the heights of my divs and ultimately of everything else, resulting in that scrollbar. Instead I need thin slices of the images.
html, body {
height: 100%;
margin: 0;
}
.root {
height: 100%;
display: flex;
flex-direction: column;
}
.appbar {
height: 50px;
text-align: center;
background-color: coral;
}
.container {
flex: 1;
}
.item {
height:33.33%;
overflow:hidden;
}
img {
width: 100%;
object-fit: cover;
}
<div class="root">
<div class="appbar">
This is a nice app bar
</div>
<div class="container">
<div class="item">
<img src="http://www.kleines-meerwasseraquarium.de/wp-content/uploads/2016/02/Zitronengrundel.jpg">
</div>
<div class="item">
<img src="http://www.kleines-meerwasseraquarium.de/wp-content/uploads/2016/02/Zitronengrundel.jpg">
</div>
<div class="item">
<img src="http://www.kleines-meerwasseraquarium.de/wp-content/uploads/2016/02/Zitronengrundel.jpg">
</div>
</div>
</div>
https://codepen.io/Meerpohl/pen/eYmVdro
The code is the same in both cases. One just uses text instead images.
.item {
position: relative;
height:33%;
overflow:hidden;
}
img {
position: absolute;
transform: translateY(-50%);
width: 100%;
object-fit: cover;
}
this should work i think!
i'm on the train right now, so I can't give you a pen.
You can position the image absolute in the parent div (this should be relative) and translateY so it is centered.
Hope this is what you want to do ;)
use this!
img {width: 100%; object-fit: cover; max-height: 33.33vh; }
Try this:
html, body {
height: 100%;
margin: 0;
}
.root {
height: 100%;
display: flex;
flex-direction: column;
}
.appbar {
height: 50px;
background-color: coral;
display: flex;
justify-content: center;
align-items: center;
}
.container {
height: calc(100vh - 50px);
display: flex;
flex-direction: column;
}
.item {
overflow: hidden;
display: flex;
flex: 1;
}
img {
width: 100%;
object-fit: cover;
}
added calc to .container and display:flex on .item, removed some unused properties.
Codepen: https://codepen.io/Liveindream/pen/NWPygpx

Keep image's ratio in a flex container on height resize

I have a problem with image in a flex container. I want it to keep ratio when the container/window height is decreased/resized down.
Sample fiddle
html,
body {
height: 100%;
}
.wrapper {
display: flex;
width: 100%;
height: 60%;
border: 1px solid red;
}
.image-container {
display: flex;
align-items: center;
max-width: 30%;
height: 100%;
background: green;
}
img {
max-width: 100%;
max-height: 100%;
}
.content {
display: flex;
justify-content: center;
align-items: center;
flex: 1;
width: 100%;
height: 100%;
background: yellow;
}
<div class="wrapper">
<div class="image-container">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/Clouds_over_the_Atlantic_Ocean.jpg/1200px-Clouds_over_the_Atlantic_Ocean.jpg" alt="">
</div>
<div class="content">
<span>Some content</span>
</div>
</div>
When you try to do it you can see that only image's height changes but width stays the same and the image is kind of stretched.
When I delete 'display: flex' from the image container, an image resizes well. I made it flex because i wanted it to be centered.
Is there a way to keep the ratio and fluidly resize image and the rest of containers?
Just add object-fit: cover; on img tag:
img {
width: 100%;
height: 100%;
object-fit: cover;
}
JSFiddle

max-width of overflow:scroll element to match flex-grow parent elements width

I have a container #container with a fixed width which has three children .item. Each have a flex-basis of 100px but the middle one .item-grow should grow so that all width of #container is used. This works like expected.
The .item-grow element has another children #too-big which could be wider than the available parent's width so its wrapped inside a #scroll container with overflow: scroll and max-width: 100%.
The problem is, that #scroll ignores max-width: 100% and forces the parent .item-grow to grow which foces the container #container to grow.
If I set max-width: 296px instead of max-width: 100% it works but I am looking for a dynamic (and CSS only) solution.
In the embedded code you can find a slider which changes the size of #too-big, you can clearly see that its growing the parents and not using the scrollbars.
function setSize (newValue) {
let elem = document.getElementById("too-big");
elem.setAttribute("style",`width:${newValue}px; height:${newValue}px`);
}
#container {
background-color: red;
display: flex;
width: 500px;
height: 200px;
}
.item {
display: flex;
flex-grow: 0;
flex-shrink: 0;
flex-basis: 100px;
border: solid black 1px;
background-color: gray;
}
.item-grow {
flex-grow: 1;
align-items: center;
}
.center-wrapper {
margin: auto;
display: table-cell;
}
.scroll {
overflow: scroll;
max-width: 100%; /* I want this respect the current parents width */
/* max-width: 296px; */
max-height: 100%; /* I want this respect the current parents height */
/* max-height: 200px; */
}
#too-big {
background-color: green;
width: 100px;
height: 100px;
}
<input type="range" min=100 max=500 value=100 oninput="setSize(this.value)" onchange="setSize(this.value)">
<div id="container">
<div class="item"></div>
<div class="item item-grow">
<div class="center-wrapper">
<div class="scroll">
<div id="too-big"></div>
</div>
</div>
</div>
<div class="item"></div>
</div>
To make that work you can drop the center-wrapper and set margin: auto on the scroll.
Then the item need min-width: 0 to allow it to be smaller than its content.
And for the max-height: 100% to work (cross browser), the item-grow need a height.
Fiddle demo (with overflow: auto instead)
Stack snippet
function setSize (newValue) {
let elem = document.getElementById("too-big");
elem.setAttribute("style",`width:${newValue}px; height:${newValue}px`);
}
#container {
background-color: red;
display: flex;
width: 500px;
height: 200px;
}
.item {
display: flex;
flex-basis: 100px;
border: solid black 1px;
background-color: gray;
box-sizing: border-box; /* added */
min-width: 0; /* added */
}
.item-grow {
flex-grow: 1;
align-items: center;
height: 100%; /* added */
}
.scroll {
margin: auto; /* added */
overflow: scroll;
max-width: 100%;
max-height: 100%;
}
#too-big {
background-color: green;
width: 100px;
height: 100px;
}
<input type="range" min=100 max=500 value=100 oninput="setSize(this.value)" onchange="setSize(this.value)">
<div id="container">
<div class="item"></div>
<div class="item item-grow">
<div class="scroll">
<div id="too-big"></div>
</div>
</div>
<div class="item"></div>
</div>