Why is height:auto not working for this image? - css

I have a flexbox container with two flex items in it. One is an image and the other a paragraph. I've been trying to resize the image proportionally by giving width:some-percentage and height:auto but it's not working. Please help me solve this.
.item{
display:flex;
}
img{
width: 25%; /* not working */
height: auto;
}
<div class="item">
<img
src=
"https://png.pngtree.com/element_origin_min_pic/16/10/16/105802ebe43fe0f.jpg"/>
<p>some paragraph</p>
</div>
JSFiddle link - https://jsfiddle.net/dizzyramen/xfot3Lwv/2/

A default setting on a flex container is align-items: flex-start.
In a row-direction container, this makes flex items, not having a defined height (e.g. height: auto), extend the full height of the container (full explanation).
In this particular case, however, the image is stretching to its fullest, and expanding the size of the container along with it.
The solution is to set a height limit on the container or override the default with align-items: flex-start on the container or align-self: flex-start on the item.
jsFiddle demo
.item {
display: flex;
}
img {
width: 25%;
align-self: start; /* new */
}
<div class="item">
<img src="https://png.pngtree.com/element_origin_min_pic/16/10/16/105802ebe43fe0f.jpg" />
<p>some paragraph</p>
</div>

here is another option:
wrap your img in a div <div class="image-wrapper"> and set manage the width in this node.
asign width: 100%; height: auto; to the img so it adjust proportionally to its parent.
Here you have it in a snippet. Hope it helps.
<div class="item">
<div class="image-wrapper">
<img
src=
"https://png.pngtree.com/element_origin_min_pic/16/10/16/105802ebe43fe0f.jpg"/>
</div>
<p>some paragraph</p>
</div>
<style>
.item{
display:flex;
}
.image-wrapper {
width: 25%; /* means 25% of .item */
}
img{
width: 100%; /* means 100% of its parent .image-wrapper */
height: auto;
}
</style>

It happens because, per default the tag <img>is inline. You need to change it to block or flex

Related

How can I fit images with varying sizes in a flex row?

My understanding of flex is that this;
<div class="flex-container">
<img src="image-1">
<img src="image-2">
...
<img src ="image-n">
</div>
<style>
.flex-container {
display: flex;
justify-content: space-between;
}
.flex-container img {
flex-shrink: 1;
}
</style>
with random number of random sized images should produce a block of images of width 100% of its parent with the images reduced in size proportionally to fit. I don't want to wrap the items.
The result of the above is either an overflow of the container or distorted images with varying results depending on setting max- or min-height styles on parent or children.
My understanding is obviously wrong. But why?
I have added the snippet below, in Chrome the images fit the box but are distorted, in Firefox they spill out of the box.
Setting the images to display: block is not sufficient. They need to be enclosed.
Thanks to Adriano for the comment suggestion.
<div class="flex-container">
<div>
<img src="image-1">
</div>
<div>
<img src="image-2">
</div>
...
<div>
<img src ="image-n">
</div>
</div>
<style>
.flex-container {
display: flex;
justify-content: space-between;
}
.flex-container div {
flex-shrink: 1;
}
.flex-container div img {
width: 100%;
height: auto;
}
</style>
If you want your image to keep ratio, add align-items: flex-start; to your container.
"The default for the css "align-items" property is "stretch" which is what is causing your images to be stretched to its full original height. Setting the css "align-items" property to "flex-start" fixes your issue."
Or you set each image into a container (with display:block;).
if you want your image to break and go to the next line just add flex-wrap:wrap; to your container.
.flex-container {
display: flex;
justify-content: space-between;
/* ADDED */
align-items: flex-start;
/*flex-wrap:wrap;*/
}
.flex-container img {
flex-shrink: 1;
}
<div class="flex-container">
<img src="https://dummyimage.com/600x400/000/fff">
<img src="https://dummyimage.com/200x600/e31da8/000">
...
<img src ="https://dummyimage.com/60x40/000/fff">
</div>

Scaling and aligning a simplistic website with image content

I am working on a simplistic website to show pictures in a single stream. To keep javascript to a minimum (just lazy loading), I only use a single relatively high-resolution version of each image and then rely on CSS to resize.
My question is how the rest of the website, at least the logo and the menu, can be best resized relative to the size of the images. After reading the CSS grid guide I decided to use a grid with grid-auto-flow: row.
The problem: I want the logo to flush left with the left of the top image and the menu to flush right with the right of the top image (all horizontal images have the same width).
My current code either aligns logo and menu to the corners of the page (as with the code below) or centers both (if I move the header into the grid as first item)
#main{
height: max-content;
display: grid;
grid-auto-flow: row;
grid-row-gap: 8em;
place-items: center center;
}
.photo_horizontal, .photo_vertical{
object-fit: contain;
height: auto;
}
.photo_horizontal{
width: 80vw;
max-height: 80vh;
}
.photo_vertical{
width: 60vw;
max-height: 90vh;
}
/* THE HEADER */
header{
display: grid;
grid-auto-flow: column;
}
#logo{
width: 15em;
justify-self: start;
}
header > div{
margin: auto 0 0 auto;
}
<header>
<img id="logo" src="https://via.placeholder.com/500x100/ff7f7f/333333?text=some%20website"/>
<div>
menu1
menu2
</div>
</header>
<div id="main">
<img class="photo_horizontal" src="https://picsum.photos/3000/2000"/>
<img class="photo_vertical" src="https://picsum.photos/2000/3000" />
<img class="photo_vertical" src="https://picsum.photos/2000/3000" />
<img class="photo_horizontal" src="https://picsum.photos/3000/2000" />
</div>
Is there an elegant way to resize images relative to the viewport but still align other content accordingly? I tried to pad logo and menu left/right but the necessary padding depends on the actual size of the image.
A pen can be found here.
To clarify, this is how it currently is and this is what I want.
The main problem is setting .photo_horizontal's .max-height: 80vh; causes it to not always honor the width: 80vw; which means the width of the .photo_horizontal is not easily calculated. That makes it difficult to make the <header> the same width.
You can do this:
header {
width: 80vw;
margin: auto;
}
But it only works if you also get rid of the max-height: 80vh rule for .photo_horizontal.
https://codepen.io/km0ser/pen/LYpqeYB
Why not include the header within #main
/* Nothing wrong with CSS grid, just Flexbox is simpler */
#main {
display: flex;
flex-direction: column;
align-items: center;
border: 1px solid;
}
/* height being auto will keep the aspect ratio */
/* horizontal photo take full width */
.photo_horizontal {
max-width: 100%;
}
/* horizontal photo take some portion of width */
.photo_vertical {
max-width: 80%;
}
header {
display: flex;
width: 100%;
}
#logo {
width: 15em;
}
header>div {
margin: auto 0 0 auto;
}
<div id="main">
<header>
<img id="logo" src="https://via.placeholder.com/500x100/ff7f7f/333333?text=some%20website" />
<div>
menu1
menu2
</div>
</header>
<img class="photo_horizontal" src="https://picsum.photos/3000/2000" />
<img class="photo_vertical" src="https://picsum.photos/2000/3000" />
<img class="photo_vertical" src="https://picsum.photos/2000/3000" />
<img class="photo_horizontal" src="https://picsum.photos/3000/2000" />
</div>
Thanks to the answers here I figured out a solution. There are three components:
As #Zohir Salak pointed out, much simpler CSS can be obtained using flexbox.
The header can be part of main even though this is not essential to the solution.
As #kmoser pointed out, the max-height constraint on images makes it hard to set a proper max-width constraint for the header, a problem that isn't solved by 1. and 2. yet. However, since all of my pictures are 3:2 ratio, a max-height constrained can be turned into a max-width constrained easily and then combined with a min via max-width: min(80vw, 3 / 2 * 80vh);.
/* Nothing wrong with CSS grid, just Flexbox is simpler */
#main {
display: flex;
flex-direction: column;
align-items: center;
border: 1px solid;
}
/* height being auto will keep the aspect ratio */
/* horizontal photo take full width */
.photo_horizontal {
max-width: min(80vw, 3 / 2 * 80vh);
}
/* horizontal photo take some portion of width */
.photo_vertical {
max-width: min(80vw, 2 / 3 * 80vh);
}
header {
display: flex;
width: 100vw;
max-width: min(80vw, 3 / 2 * 80vh);
}
#logo {
width: 15em;
}
header>div {
margin: auto 0 0 auto;
}
<div id="main">
<header>
<img id="logo" src="https://via.placeholder.com/500x100/ff7f7f/333333?text=some%20website"/>
<div>
menu1
menu2
</div>
</header>
<img class="photo_horizontal" src="https://picsum.photos/3000/2000"/>
<img class="photo_vertical" src="https://picsum.photos/2000/3000" />
<img class="photo_vertical" src="https://picsum.photos/2000/3000" />
<img class="photo_horizontal" src="https://picsum.photos/3000/2000" />
</div>
Alternatively, see the same code in a pen here.

Set width of child elements in flex container/parent div

Is it possible, using flex, to set the width of children elements in the style of the their parent div?
For example I want each element in a flex container to stretch 1/3 of the container, or 1/2, or 100% width. They would all have equal widths. The width is a dynamic value which can change.
This issue is, I can add dynamic style values only to the .flex-container div. I can't add anything dynamic to .element divs.
So I can't do this...
<div class="flex-container">
<div class="element" style="width: 33%"></div>
<div class="element" style="width: 33%"></div>
etc...
</div>
Only..
<div class="flex-container" style="some value that will set children divs to 1/3 width of container, or 1/2, etc)">
<div class="element"></div>
<div class="element"></div>
etc...
</div>
My CSS for the flex container:
.flex-container {
display: flex;
flex-wrap: wrap;
}
.element {
// I can't add dynamic styles to this like width
}
Yes you can dynamically set the width.
Then use media queries to change them depending on your window size.
html, body {
height: 100%;
}
.flex-container {
display: flex;
height: 50%;
}
.element {
width: 33.33%;
align-self: stretch;
}
.element:nth-of-type(1) {
align-self: flex-start;
background: red;
}
.element:nth-of-type(2) {
align-self: flex-end;
background: green;
}
.element:nth-of-type(3) {
align-self: stretch;
background: blue;
}
<div class="flex-container">
<div class="element">
Test Element 1
</div>
<div class="element">
Test Element 2
</div>
<div class="element">
Test Element 3
</div>
</div>

Using calc() with a dynamic value?

I am wondering if this is possible: I have a header that can contain a variable amount of text. Below that I have another element which I want to take up the remaining height of the page.
<div class="header row">
<div class="title column large-5">Potentially very long text</div>
<div class="menu column large-7">Menu items</div>
</div>
<div class="content">
</div>
<div class="footer">
</div>
Normally I would do this using calc, eg:
.content {
height: calc(100vh - 75px);
}
Where 75px is the set height of .header.
But in this example, the .header element is dynamic and does not have a set height. Only a padding and font-size are set.
To complicate things, this also uses the Foundation Grid layout, which makes me nervous about using display: table (.title and .menu sit side by side on desktop, but stacked on mobile) .
Is there anyway to get the height of the dynamic header element (without resorting to JQuery)?
You can use flexbox and set .content to flex-grow: 1 so that it will fill to grow the available space.
body {
display: flex;
flex-direction: column;
min-height: 100vh;
margin: 0;
}
.content {
flex-grow: 1;
background: #eee;
}
<div class="header row">
<div class="title column large-5">Potentially very long text</div>
<div class="menu column large-7">Menu items</div>
</div>
<div class="content">
</div>
<div class="footer">
</div>
I made a small pen to show the way to do this using flex box, it involved changing your markup a bit:
css:
.container {
display: flex;
flex-direction: column;
height: 250px; // whatever you want here
}
.header {
width: 100%;
background: red;
padding: 10px;
}
.content {
background: yellow;
width: 100%;
flex-grow: 1;
}
So the content will always take the available space inside the content div.
check the whole pen: http://codepen.io/anshul119/pen/yMYeLa
hope this helps.

CSS- Getting 100% width div to wrap under another [jsfiddle]

In a responsive layout, I have two columns. The left column is the sidebar and the right column is the content.
Using a media query, when the screen width is tiny, the columns turn to 100% width and stack on top of each other.
In this case, I want the sidebar (the first div) to appear beneath the content (the second div).
I tried using float: right on a small screen once it's at 100%, but at 100% width, the float apparently doesn't matter.
.left, .right {
width: 100%;
float: left;
background: green;
}
.left {
float: right;
background: red;
}
.half {
width: 50%;
}
.space {
width: 100%;
display: block;
height: 40px;
}
And on the page:
<div class="left half"> <!-- To mimic full screen size -->
Left
</div>
<div class="right half">
Right
</div>
<div class="space"></div>
<div class="left"> <!-- To mimic small screen size -->
Left
</div>
<div class="right"><!-- This should appear first -->
Right
</div>
Here is the fiddle: https://jsfiddle.net/ph09frvw/
I'm sure this is not the first time someone wanted to wrap the sidebar under the content, I just haven't been able to find a solution.
You can use display: flex and use the order property to change the order of the <div> elements. While floating can be helpful for horizontal alignment, it will be of little help for vertical alignment, Here is an example:
.flex {
display: flex;
flex-flow: row wrap;
}
.left {
order: 2;
flex: 1 0 50%;
background: red;
}
.right {
order: 1;
flex: 1 0 50%;
background: green;
}
.full {
margin-top: 20px;
}
.full > .left,
.full > .right {
flex: 1 0 100%;
}
<div class="flex">
<div class="left">
Left
</div>
<div class="right">
Right
</div>
</div>
<div class="flex full">
<div class="left">
Left
</div>
<div class="right">
Right
</div>
</div>
You could use the display:flex; property combined with flex-direction to reorder your divs. Ref: https://css-tricks.com/almanac/properties/f/flex-direction/
Remember to reference your related class-names in your HTML elements' class attribute.
Your CSS display:block should do the trick, else try something like:
float: left
When you use: display:block on a div element, you do not need to specify width:100% as it should automatically span across the width if it is not hindered by anything else.
Make sure the position of these elements are "relative", else it may not work as expected; it may be stated globally that some specific tags should be displayed "absolute" and that may break what you're trying to achieve.

Resources