Responsive Image with correct aspect ratio in Flex-box - html

I cannot seem to achieve a responsive image inside a flex-box item correctly. If the image is one of the flex-box item, it works well (Jsfiddle)
.parent {
display: flex;
width: 100%;
}
.parent input {
flex: 1;
}
.parent input:focus + img {
display: none;
}
<div class="parent">
<img src="https://png.icons8.com/metro/40/000000/graduation-cap.png">
<input />
<img src="https://png.icons8.com/metro/40/00000/user.png">
</div>
When the image is inside a flex item, it starts to misbehave.
Scenario 1: Image stretches distorting the aspect ratio (Jsfiddle)
.parent {
display: flex;
width: 100%;
height: 40px;
}
.parent input {
flex: 1;
}
.parent input:focus + div {
display: none;
}
.parent img {
height: 100%;
max-height: 100%;
width: auto;
}
.parent .funny {
display: flex;
}
<div class="parent">
<img src="https://png.icons8.com/metro/40/000000/graduation-cap.png">
<input />
<div class="funny">
<img src="https://lh3.googleusercontent.com/-OX10v8tUiCY/AAAAAAAAAAI/AAAAAAAADE8/QcezYUDPvxU/s96-c/photo.jpg">
</div>
</div>
Scenario 2: Image leaves empty space (Jsfiddle)
.parent {
display: flex;
width: 100%;
height: 40px;
background: red;
}
.parent input {
flex: 1;
}
.parent input:focus + div {
display: none;
}
.parent img {
height: 100%;
max-height: 100%;
width: auto;
}
.parent .funny {
display: flex;
}
<div class="parent">
<img src="https://png.icons8.com/metro/40/000000/graduation-cap.png">
<input />
<div class="funny">
<div>
<img src="https://lh3.googleusercontent.com/-OX10v8tUiCY/AAAAAAAAAAI/AAAAAAAADE8/QcezYUDPvxU/s96-c/photo.jpg">
</div>
</div>
</div>
Scenario 3: The layout is good until the input receives focus, then verything breaks: Jsfiddle
This happens in IE 11, Chrome (Version 67.0.3396.87 (Official Build) (64-bit)), but haven't tested in Firefox and Edge.
Is there something i haven't studied about Flex-box, or is it a bug?

The below code seems to be working fine for me.
I've just set the image height and width in your first example.
.parent {
display: flex;
width: 100%;
}
.parent input {
flex: 1;
}
.parent input:focus + img {
display: none;
}
img {
height: 40px;
width: auto;
}
<div class="parent">
<img src="https://png.icons8.com/metro/40/000000/graduation-cap.png">
<input />
<img src="https://lh3.googleusercontent.com/-OX10v8tUiCY/AAAAAAAAAAI/AAAAAAAADE8/QcezYUDPvxU/s96-c/photo.jpg">
</div>
For the second example that you shared, again just setting the img height to 40px instead of making it as 100% seems to be working for me. Check the fiddle
Same with scenario 3. Check the fiddle

You have added only one image in <div>.
Check out this fiddle

Related

How to make an image fill a flex item with flex-grow?

I've read through all existing solutions in which images could fill the containing divs but I haven't found a solution for filling a div without a static dimension, such as divs that only have been laid out by flex-grow.
Currently the image will destroy the flex-grow proportions I have set on the container. I want the img to just fill the div and not stretch the div out.
As much as possible I don't want to inline style.
Is there an existing polyfill or solution to this?
.container {
display: flex;
min-height: 300px;
width: 500px;
flex: 1;
}
.sub-container {
flex: 1;
display: flex;
flex-direction: row;
}
.sub-container > div {
flex-grow: 1;
}
.first-container {
background-color: blue;
}
.second-container {
background-color: yellow;
}
.second-container>img {
max-height: 100%;
max-width: 100%;
object-fit: scale-down;
}
<div class="container">
<div class="sub-container">
<div class="first-container">
A
</div>
<div class="second-container">
<img src="https://internationalbarcodes.net/wp-content/uploads/2017/04/QR%20code%20example.jpg" />
</div>
</div>
</div>
http://jsfiddle.net/jojonarte/tu3nbw4q/
You have this in your code:
.sub-container > div {
flex-grow: 1;
}
Okay, that defines flex-grow.
But you haven't defined flex-basis. As a result, flex-basis keeps its default value, which is: auto (i.e., content-defined).
That's what you're seeing your layout: A flex item that is being sized by the content.
In other words, because the natural dimensions of the image are so large (in comparison to the size of the container), the image is taking up all free space and flex-grow is having no effect (it has no free space to distribute).
As a solution, add this to the rule:
.sub-container > div {
flex-grow: 1;
flex-basis: 0; /* new */
}
or, more efficiently:
.sub-container > div {
flex: 1; /* fg:1, fs:1, fb:0 */
}
revised fiddle
.container {
display: flex;
min-height: 300px;
width: 500px;
}
.sub-container {
flex: 1;
display: flex;
flex-direction: row;
}
/* ADJUSTMENT HERE */
.sub-container > div {
flex: 1;
}
.first-container {
background-color: blue;
}
.second-container {
background-color: yellow;
}
.second-container>img {
max-height: 100%;
max-width: 100%;
object-fit: scale-down;
}
<div class="container">
<div class="sub-container">
<div class="first-container">A</div>
<div class="second-container">
<img src="https://internationalbarcodes.net/wp-content/uploads/2017/04/QR%20code%20example.jpg" />
</div>
</div>
</div>
More information:
To avoid the problem described in the question, as a general rule, use the flex property instead of flex-grow, flex-shrink and flex-basis individually.
From the flexbox specification:
§ 7.2.1. Components of
Flexibility
Authors are encouraged to control flexibility using the flex
shorthand rather than with its longhand properties directly, as the
shorthand correctly resets any unspecified components to accommodate
common uses.
Learn more about the difference between flex-basis: auto and flex-basis: 0
Use background-image instead use img tag and use background-size: 100% 100%;:
See fiddle
.container {
display: flex;
min-height: 300px;
width: 500px;
flex: 1;
}
.sub-container {
flex: 1;
display: flex;
flex-direction: row;
}
.sub-container>div {
flex-grow: 1;
}
.first-container {
background-color: blue;
}
.second-container {
background: url(https://internationalbarcodes.net/wp-content/uploads/2017/04/QR%20code%20example.jpg);
background-repeat: no-repeat;
background-size: 100% 100%;
}
<div class="container">
<div class="sub-container">
<div class="first-container">
A
</div>
<div class="second-container">
</div>
</div>
</div>

Height is not correct in flexbox items in Chrome [duplicate]

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>

Firefox stretching an element centered with Flexbox

I'm trying to center an element (im my case an image) with arbitrary size inside a box. Everything works fine in Webkit browsers, but Firefox stretches images that are longer than they are wide.
To illustrate the problem, I create 3 div as boxes, each of containing a differently sized image. The boxes are all set to a fixed width and height, and a couple of flexbox rules are applied to center the image both vertically and horizontally.
* {
box-sizing: border-box;
}
.box {
display: flex;
width: 100px;
height: 100px;
border: 1px solid black;
justify-content: center;
align-items: center;
float: left;
margin-right: 50px;
}
.box img {
max-width: 100%;
max-height: 100%;
}
<div class="box">
<img src="http://dummyimage.com/150x150/eeeeee.png">
</div>
<div class="box">
<img src="http://dummyimage.com/300x150/eeeeee.png">
</div>
<div class="box">
<img src="http://dummyimage.com/150x300/eeeeee.png">
</div>
The img should be shrunk such that they exactly fill the box (either horizontally or vertically, which ever side is longer), but preserving the aspect ratio. This is exactly what happens in Webkit browsers. However, Firefox just stretches the one image that is longer than high in vertical direction. How can I make Firefox behave the same way as all the Webkit browsers?
Using "object-fit: contain" for the images seems to do the trick :)
.box img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
http://jsfiddle.net/xjwguxs6/
Setting flex-basis: 100% fixes the issue as it sets the initial main size of the flex item. If the flex-direction is reversed i.e. column, you will need to use flex-basis: 100% on nth-child(3)
.box:nth-child(2) img {
flex-basis: 100%;
}
* {
box-sizing: border-box;
}
.box {
display: flex;
width: 100px;
height: 100px;
border: 1px solid black;
justify-content: center;
align-items: center;
float: left;
margin-right: 50px;
}
.box img {
max-width: 100%;
max-height: 100%;
}
.box:nth-child(2) img {
flex-basis: 100%;
}
<div class="box">
<img src="http://dummyimage.com/150x150/eeeeee.png">
</div>
<div class="box">
<img src="http://dummyimage.com/300x150/eeeeee.png">
</div>
<div class="box">
<img src="http://dummyimage.com/150x300/eeeeee.png">
</div>

Content ignoring max-width when within a Flexbox container in Firefox?

Wondering if anybody else is experiencing the following and either found a solution or may have suggestions.
The code below renders correctly on Chrome (35.0.1916.153), but it does not on Firefox (Firefox 29.0.1):
CSS:
.container {
display: flex;
align-items: center;
width: 200px;
height: 200px;
border: 2px solid red;
overflow: hidden;
}
.container img {
max-width: 100%;
}
HTML:
<div class="container">
<img src="https://g.twimg.com/business/page/image/11TwitterForSmallBusiness-300_1.png"/>
</div>
A runnable example can be found here:
http://jsfiddle.net/Jc3A3/16/
Add min-width: 1px; to the .container.
https://ntucker.true.io/ntucker/solution-firefox-34-ignoring-max-width-for-flexbox/
try separating the img from your .container
eg:
.container {
--your style here
}
img {
max-width:100%;
}

How to enforce the height of inner div to be equal to the height of the parent div, if the parent div has "min-height"?

Why in the following example the height of the inner div is not like wrapper's div ?
Live demo here.
HTML:
<div class="wrapper">
<div class="inner">Hello</div>
<div class="inner">Peace</div>
</div>
CSS:
.wrapper {
background-color: #000;
min-height: 100px;
}
.inner {
display: inline-block;
background-color: #777;
height: 100%;
}
If I change min-height: 100px; to height: 100px;, then it looks OK. But, in my case, I need min-height.
Some properties in CSS inherit the value of the parent automatically, some don't. Minimum height must be explicitly stated when you want it to inherit the parent's value:
min-height: inherit;
I believe this is the output you want: http://jsfiddle.net/xhp7x/
.wrapper {
display: table;
background-color: #000;
height: 100px;
width: 100%;
}
.wrapper2 {
height: 100%;
display: table-row
}
.inner {
height: 100%;
display: inline-block;
background-color: #777;
margin-right: 10px;
vertical-align: top;
}
Had to add a second DIV wrapper2.
Tested on chrome and firefox.
You want to specify both, CSS height is not the same as min-height. You want to specify both height and min-height.
height = When used as a %, this is a percent of the window height
min-height = as you drag the window smaller, the DIV with a % height will continue to reduce until it hits the min-height
max-height = as you drag the window larger, the DIV with a % height will continue to increase until it hits the max-height
http://jsfiddle.net/gpeKW/2/ I've added a sample here with borders.
Slight change to the answer from your comment, you are pretty much correct from your original CSS.
The below HTML will have a minimum div height of 100px. As the size of the inner DIV increases, the wrapper will automatically expand. I have demonstrated this by adding a style attribute to the first inner class.
<html>
<head>
<title>Untitled Page</title>
<style type="text/css">
.wrapper
{
background-color: #000;
min-height:100px;
}
.inner
{
display: inline-block;
background-color: #777;
height: 100%;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="inner" style="height:200px">test</div>
<div class="inner">Peace</div>
</div>
</body>
</html>
I know one way to set the div child height the same as its parent div height is to use relative for the parent and absolute position for the child.
.wrapper {
background-color: #000;
min-height: 100px;
position: relative;
}
.inner {
display: inline-block;
background-color: #777;
position: absolute;
height: 100%;
}
But this way will cause some problem, you have to adjust the child element so that it will be displayed properly
P/s: Why don't you set it to the same height as its parent height? I mean, 100% is not x%... just thinking..
Anyway, happy coding ;)
I certainly joined answers and the result using 'min-height' for the -main HTML tag- (class = "main-page-container"):
HTML:
<div id="divMainContent">
<!-- before or after you can use multiples divs or containers HTML elements-->
<div> </div>
<div> </div>
<main class="main-page-container">
<div class="wrapper">
1
<div class="wrapper2">
2
<div class="child">3</div>
</div>
</div>
</main>
<!-- before or after you can use multiples divs or containers HTML elements-->
<div class="footer-page-container bg-danger" > more relevant info</div>
</div>
CSS:
/*#region ---- app component containers ---- */
#divMainContent {
height: 100%;
display: flex;
flex-direction: column;
/*optional: max width for screens with high resolution*/
max-width: 1280px;
margin:0 auto;
}
.main-page-container {
display: inline-table;
height: 70%;
min-height: 70%;
width: 100%;
}
.footer-page-container{
flex:1; /* important in order to cover the rest of height */
/* this is just for your internal html tags
display: flex;
flex-direction: column;
justify-content: space-between; */
}
/*#endregion ---- app component containers ---- */
.wrapper {
background: blue;
max-width: 1280px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 100%;
}
.wrapper2 {
width: 90%;
margin: auto;
background: pink;
display: flex;
flex-wrap: wrap;
gap: 20px;
height: 90%;
}
.child {
min-height: 100px;
min-width: 300px;
background: orange;
position: relative;
width: 33%;
}