I have a column flex container, with one flex child containing an image
<div class="flex">
<p> Test </p>
<div class="flex-item">
<img class="img" src="https://i.imgur.com/E4Os1Fh.png">
</div>
</div>
All elements are given width 100% height 100% along the chain.
html, body {
height: 100%;
}
.flex {
display: flex;
width: 100%;
height: 100%;
flex-direction: column;
}
.flex-item {
flex: 1;
}
.img {
width: 100%;
height: 100%;
}
How come the image is not respecting the height properties and is taking up more space than the height of its parent element?
JSFiddle: https://jsfiddle.net/ohewn35k/4/
(You need to resize the window to be smaller than the natural image size to see the problem in action)
EDIT: The example in this question seems to be working fine, but it doesn't not work in my actual code. I have stripped my code down in developer tools and uploaded a zip file
https://www.mediafire.com/file/v32z4xrxnstyd3d/reproduce.7z/file
If you extract the file and open reproduce.html you'll see that the image element has a scrollbar as it's expanding passed its available space for some reason.
Once I fix this problem, I intend to add object-fit: contain to the image so it contains nicely within its available space.
Since you're using flexbox.
Your .flex-item becomes this:
.flex-item {
flex: 1;
}
Essentially you're are telling the flex item to use the maximum space available.
You can read about the flex property on MDN
Your CSS '.img' selector should just be 'img'
Try this
<div class="flex">
<div class="flex-item">
<img src="https://i.imgur.com/E4Os1Fh.png">
</div>
</div>
html, body {
height: 100%;
}
.flex {
display: flex;
width: 100%;
height: 100%;
flex-direction: column;
}
.flex-item {
width: 100%;
height: 100%;
}
img {
width: 100%;
height: 100%;
}
Related
I have an image in a flex container (let's call it child).
The container itself has flex: 1 because it also belongs to a flex parent with flex-direction: column and child behaves as expected (takes 100% height of parent) before introducing the image situation.
On adding an image to child, the image extends child to accommodate its height, effectively child pushing parent.
Using object-fit: cover on the image could not help in this situation!
Looks like this is normal behaviour in Chrome, Firefox, and Safari.
Here's the weird part tho: adding a height property to child fixes the issue on Chrome and Safari but not Firefox. This height's value doesn't matter much as long as it's not greater than the computed height of child - child is contained to 100% height of parent together with the image - even if the height value of child is set to 1px. Surprisingly height: 100% on child doesn't produce the same behaviour.
Any ideas around this will be much appreciated. My goal is to make the image always take up 100% of child - regardless of the width of the viewport.
Here's some code for illustration
#parent {
height: 100vh;
display: flex;
flex-direction: column;
}
#child {
flex: 1;
height: 1px;
/* the weird hack for chrome and safari - ff ignores it */
}
#child img {
width: 100%;
height: 100%;
object-fit: cover;
}
<div id="parent">
<div id="child">
<img src="https://i.picsum.photos/id/1005/400/1000.jpg" />
</div>
</div>
I also added some images for more context. These are crops of the entire page. The first image is from a smaller viewport (width shared with devtools) and the second from the entire page (devtools hidden). The second image shows that the image has extended child to eventually push the container with a green background beyond the fold - causing a scrollbar to appear.
child is the image wrapper, and parent is the component with a white background and some padding. You realize parent has a sibling (green background) and their parent (container with a green border and border radius) has a display: grid and grid-template-rows: 1fr auto;.
It should also be noted that the most top-level element has a height of 100vh and all its children are rendered within that. Essentially there should not be a scrollbar.
I hope you get the idea.
Is this what you are looking to do?
You can also see it here: https://codepen.io/teanbiscuits/pen/GRJmPgo
#parent {
height: 100vh;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr auto;
border:2px solid green;
border-radius:20px;
overflow:hidden;
}
#child {
position:relative;
}
#child img {
position:absolute;
width: 100%;
height: 100%;
object-fit: contain;
}
#text {
background-color:green;
}
<div id="parent">
<div id="child">
<img src="https://i.picsum.photos/id/1005/400/1000.jpg" />
</div>
<div id="text">
<h2>some title here</h2>
<p>Some description here</p>
</div>
</div>
Please try this. Just select preferred object-fit.
html, body{
height: 100%;
margin: 0;
padding: 0;
}
#parent {
height: calc(100vh - 20px);
display: flex;
padding: 10px;
flex-direction: column;
}
#child {
flex: 1;
text-align: center;
overflow: hidden;
}
#child img {
width: 100%;
height: 100%;
object-fit: contain;
}
<div id="parent">
<div id="child">
<img src="https://i.picsum.photos/id/1005/400/1000.jpg" />
</div>
<div id="text">
<h2>Some title here</h2>
<p>Some description here</p>
</div>
</div>
I'm trying to set up wide flex elements that contain two children (see image at bottom).
The green child element should fill the remaining width of the parent element.
The blue child element should maintain a certain aspect ratio (1 to 0.75, for instance), but ultimately it should fill the height of the parent element.
Here's how I've tried setting this up:
.parent-outer {
display: flex;
flex-direction: row;
height: 250px;
}
.parent-inner {
display: flex;
flex-direction: column;
height: 100%;
}
.blue-child {
height: 100%;
width: 75vh;
background: blue;
}
.green-child {
height: 100%;
flex-grow: 1;
background: green;
}
<div class="parent-outer">
<div class="parent-inner">
<div class="blue-child"></div>
<div class="green-child"></div>
</div>
</div>
This does not seem to be working.
edit: refactor based on Temani Afif's comment -- remove .parent-inner. Looks like that inner parent div wasn't necessary, but can't seem to get the blue child to fill it's container's height and allow its width to adjust accordingly:
.parent {
display: flex;
flex-direction: row;
height: 250px;
}
.blue-child {
height: 100%;
width: 75vh;
background: blue;
}
.green-child {
height: 100%;
flex-grow: 1;
background: green;
}
<div class="parent">
<div class="blue-child"></div>
<div class="green-child"></div>
</div>
I try to have a html5 video that fills the remaining space in a flexbox div.
However, it overflows rather than doing what I want:
.wrapper {
padding: 10px;
display: flex;
flex-direction: column;
max-height: 300px;
background-color: green;
}
.content {
width: 100%;
background-color: red;
}
video {
width: 100%;
height: 100%;
}
.footer {
width: 100%;
background-color: orange;
}
<div class="wrapper">
<div class="content">
<video src="http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4" />
</div>
<div class="footer">footer</div>
</div>
https://jsfiddle.net/pwhwL29p/
You have a video and a footer inside the .wrapper element. The height: 100% on the video may or may not work, depending on the browser (more details below).
Since you don't have a height defined on the .content element, which holds the video, the results are unpredictable and unreliable. Again, browser behavior varies.
Here's a method that is more efficient and reliable across browsers:
.wrapper {
padding: 10px;
display: flex;
flex-direction: column;
max-height: 300px;
background-color: green;
}
.content {
display: flex; /* NEW */
width: 100%;
background-color: red;
}
video {
width: 100%;
/* height: 100%; <-- REMOVE; not necessary */
}
.footer {
width: 100%;
background-color: orange;
}
<div class="wrapper">
<div class="content">
<video src="http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4" />
</div>
<div class="footer">footer </div>
</div>
revised fiddle
Here's how it works:
Turn the .content flex item, which contains the video, into a flex container.
This activates align-items: stretch, a default setting, which makes the video consume all available space in the cross-axis (in this case, height).
Remove height: 100%. Flex layout handles height dynamically.
More details:
Working with the CSS height property and percentage values
Chrome / Safari not filling 100% height of flex parent
UPDATE
From the comments:
Thank you. it works great for the standard video tag. Unfortunately it breaks with video.js
The video script adds a container to the HTML structure:
As a result, the function of the .content flex container no longer works.
You'll need to make adjustments to the CSS. Add this:
#video {
display: flex;
height: auto;
width: 100%;
}
revised fiddle
This question already has answers here:
Chrome / Safari not filling 100% height of flex parent
(5 answers)
Closed 6 years ago.
I've got a delicate problem for any CSS guru out there.
My green div has a flexible height, taking up the remaining.
And now I want to put a div inside that div which should be the half of the green div. But it seems like if Chrome treats it like half of the whole page rather than the flex item.
http://jsfiddle.net/unh5rw9t/1/
HTML
<body>
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
</body>
CSS
html,body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
background-color: green;
}
#half_of_content {
height: 50%;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
#Michael_B explained why Chrome behaves like this:
You gave the body a height: 100%. Then gave its child (.wrapper)
a height: 100%. Then gave its child (.content) a height: 100%.
So they're all equal height. Giving the next child (#half_of_content) a height: 50% would naturally be a 50% height
of body.
However, Firefox disagrees because, in fact, that height: 100% of .content is ignored and its height is calculated according to flex: 1.
That is, Chrome resolves the percentage with respect to the value of parent's height property. Firefox does it with respect to the resolved flexible height of the parent.
The right behavior is the Firefox's one. According to Definite and Indefinite Sizes,
If a percentage is going to be resolved against a flex item’s
main size, and the flex item has a definite flex
basis, and the flex container has a definite main
size, the flex item’s main size must be treated as
definite for the purpose of resolving the percentage, and the
percentage must resolve against the flexed main size of the
flex item (that is, after the layout algorithm below has been
completed for the flex item’s flex container, and the flex
item has acquired its final size).
Here is a workaround for Chrome:
#content {
display: flex;
flex-direction: column;
}
#content::after {
content: '';
flex: 1;
}
#half_of_content {
flex: 1;
height: auto;
}
This way the available space in #content will be distributed equally among #half_of_content and the ::after pseudo-element.
Assuming #content doesn't have other content, #half_of_content will be 50%. In your example you have a 2 in there, so it will be a bit less that 50%.
html,
body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
background-color: green;
display: flex;
flex-direction: column;
}
#content::after {
content: '';
flex: 1;
}
#half_of_content {
flex: 1;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
You could absolutely position div id="half_of_content".
#content {
flex: 1;
height: 100%;
background-color: green;
position: relative; /* new */
}
#half_of_content {
height: 50%;
background-color: yellow;
position: absolute; /* new */
width: 100%; /* new */
}
DEMO
With regard to your statement:
But it seems like if Chrome treats it like half of the whole page
rather than the flex item.
You gave the body a height: 100%. Then gave its child (.wrapper) a height: 100%. Then gave its child (.content) a height: 100%. So they're all equal height. Giving the next child (#half_of_content) a height: 50% would naturally be 50% height of body.
With absolute positioning, however, you don't need to specify parent heights.
Nesting flexboxes is a little buggy. I reworked your markup a little by adding an inner wrapper with display: flex; which seems to do the job. Here is the fiddle (also using class names instead of ids).
<div class="content">
<div class="wrapper-inner">
2
<div class="half">
2.1
</div>
</div>
</div>
.wrapper-inner {
position: absolute;
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
Fix:
on #content set
display: flex;
flex-flow: column nowrap;
justify-content: flex-end
on #half_of_content set flex: 0 0 50%;
Caveat: you need to add an extra div as a child of #content.
Here's the full example:
html,body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
display:flex;
flex-flow: column nowrap;
justify-content: flex-end;
background-color: green;
}
#half_of_content {
flex: 0 0 50%;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
<body>
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
</body>
I'm trying to center a div on a webpage using flexbox. I'm setting the following CSS properties. I see that it's being centered horizontally, but not vertically.
.flex-container {
display: flex;
align-items: center;
justify-content: center;
}
Here's the fiddle: JSFIDDLE
Can you explain what I'm doing wrong?
A <div> element without an explicit height defaults to the height of it's contents, as all block elements do. You'd probably want to set it to 100% of it's parent, the <body>, but that's not enough, since that is also a block element. So again, you need to set that to 100% height, to match it's parent, the <html>. And yet again, 100% is still required.
But once all that is done, you get that annoying vertical scroll bar. That's a result of the default margin the body has, and the way the box model is defined. You have several ways you can combat that, but the easiest is to set your margins to 0.
See corrected fiddle.
html, body {
height: 100%;
margin: 0px;
}
.flex-container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.item {
background-color: blue;
height: 50px;
width: 50px;
}
<div class="flex-container">
<div class="item">
</div>
</div>
You just need to set html, body, and your flex container to height: 100%. The reason it wasn't working is that your flex container didn't have an explicit height set, so it defaulted to the height of its contents.
Live Demo:
html, body {
height: 100%;
}
.flex-container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.item {
background-color: blue;
height: 50px;
width: 50px;
}
<div class="flex-container">
<div class="item">
</div>
</div>
JSFiddle Version: http://jsfiddle.net/d4vkq3s7/3/