How to achieve equal height image columns that shrinks - html

I want to achieve a grid-like layout where every column in a row has the same height. Each column contains a picture so it must also keep the proportions of the image.
The current solution is to set the flex-grow property to the ratio of the image. This works but can result in very large images which is not desired in my case.
I would like the images to shrink to fit on one row in the case of negative space left.
The flex-shrink property works similar to the flow-grow property. The negative space will be distributed between the items based on the flex-shrink property.
However there is a caveat in the flex-shrink behaviour: the item will never shrink to a size less than the content of it. In my case that means the column will never shrink to a size less than the images it contains.
I can work around the problem by setting the flex-basis property to a smaller value. I've played around with this but either messed up the wrapping or the equal heights.
What I would like to happen:
Consider the following markup:
.container {
display: flex;
flex-wrap: wrap;
width: 600px;
}
.img-container {
padding: 5px;
box-sizing: border-box;
flex-basis: auto;
}
.img {
width: 100%;
height: auto;
}
<div class="container">
<div style="flex-grow: 1; flex-shrink: 1;" class="img-container">
<img class="img" src="https://via.placeholder.com/200x200/" alt="">
</div>
<div style="flex-grow: 1; flex-shrink: 1;" class="img-container">
<img class="img" src="https://via.placeholder.com/200x200/" alt="">
</div>
<div style="flex-grow: 2; flex-shrink: 2;" class="img-container">
<img class="img" src="https://via.placeholder.com/400x200/" alt="">
</div>
</div>
The sum of the width is 200+200+400=800px which means there is 800-600=200px negative space. The flex-shrink values dictates that item one and two gets 1 part of the negative space and that item three gets 2 parts.
Calculating this gives us:
Width to remove from item one: 1/4*200=50
Width to remove from item two: 1/4*200=50
Width to remove from item three: 2/4*200=100
These widths are correct and would keep the correct ratios but as I mentioned earlier this cannot be achieved since the flex-basis is the natural width of the image elements.
Do you guys have any suggestions on how to solve this problem?

If you set the width of your .container and the height of your .img-container it should work.
Now you only have to decide how you want to space your images. .container { justify-content: space-evenly/space-between/space-around}
.container {
display: flex;
flex-wrap: wrap;
width: 600px;
justify-content: space-evenly;
}
.img-container {
padding: 5px;
box-sizing: border-box;
flex-basis: auto;
height: 150px;
}
.img {
width: auto;
height: 100%;
}
<div class="container">
<div class="img-container">
<img class="img" src="https://via.placeholder.com/200x200/" alt="">
</div>
<div class="img-container">
<img class="img" src="https://via.placeholder.com/200x200/" alt="">
</div>
<div class="img-container">
<img class="img" src="https://via.placeholder.com/400x200/" alt="">
</div>
<div class="img-container">
<img class="img" src="https://via.placeholder.com/400x200/" alt="">
</div>
<div class="img-container">
<img class="img" src="https://via.placeholder.com/400x200/" alt="">
</div>
<div class="img-container">
<img class="img" src="https://via.placeholder.com/200x200/" alt="">
</div>
<div class="img-container">
<img class="img" src="https://via.placeholder.com/200x200/" alt="">
</div>
<div class="img-container">
<img class="img" src="https://via.placeholder.com/200x200/" alt="">
</div>
<div class="img-container">
<img class="img" src="https://via.placeholder.com/200x200/" alt="">
</div>
</div>

Related

Is there a way to have different justify-content values for different rows inside a flexbox-container?

Is there a way to have different justify-content values for different rows inside a flexbox-container?
Here is my html:
<div class="wrapper flex-container">
<div class="flex-item">
<h2>Text</h2>
<p>Text</p>
</div>
<div class="flex-item">
<h2>Text</h2>
<p>Text</p>
</div>
<figure class="flex-item"><img src="materiale/junckers.png" alt="junckers"></figure>
<figure class="flex-item"><img src="materiale/byg-garanti.png" alt="byg-garanti"></figure>
<figure class="flex-item"><img src="materiale/gulvbranchen.png" alt="gulvbranchen"></figure>
</div>
I want the first two flex-items (the two div's) to fill one row and to be aligned in accordance with justify-content: space-between;
And I want the three last flex-items (the three figure's) to fill the next row and to be aligned in accordance with justify-content: space-evenly;
Is that possible in the same flex-container?
The answer is no.
In grid, there is the justify-self property in which this would be true. However, in flex there is no support for this style as of May 2022.
flex does support align-self for aligning flex item's on the y-axis (align-items), but not for the x-axis (justify-content).
The good news.
You can still replicate these styles in your stylesheet but they will have to be done manually. You can target the first and second flex-item and use width: calc(100%/2) for the first two flex items that you want to each take 50%. Then you can add flex-wrap: wrap on to your flex-container so the image flex-items wrap onto a new row. Then you can replicate justify-content: space-between; by adding margin: auto; to those respective flex-items.
See below:
.flex-container {
display: flex;
flex-wrap: wrap;
}
.flex-item:first-child,
.flex-item:nth-child(2) {
width: calc(100%/2);
outline: dotted 1px black;
}
.flex-item:nth-child(3),
.flex-item:nth-child(4),
.flex-item:nth-child(5) {
outline: solid 1px;
background: orange;
padding: 10px;
}
<div class="wrapper flex-container">
<div class="flex-item">
<h2>Text</h2>
<p>Text</p>
</div>
<div class="flex-item">
<h2>Text</h2>
<p>Text</p>
</div>
<figure class="flex-item" style="margin-right: auto;"><img src="https://dummyimage.com/100/000/fff" alt="junckers"></figure>
<figure class="flex-item" style="margin: auto;"><img src="https://dummyimage.com/100/000/fff" alt="byg-garanti"></figure>
<figure class="flex-item" style="margin-left: auto;"><img src="https://dummyimage.com/100/000/fff" alt="gulvbranchen"></figure>
</div>

Div elements do not wrap on the next line

I defined flexbox properties of container display: flex; flex-wrap: wrap; justify-content: center; but there are always 3 divs on the first row and 2 divs on the second. How to make it wrap divs when the browser resizes?
I tried almost everything (changed the width and height of parent container, changed width to min-width/max-width, set margin of parent container margin: 0 auto;).
<!-- HTML -->
<div class="parent">
<div class="headline">
<h2>Tea of the Month</h2>
<h4>What's Stepping at The Tea Cozy?</h4>
</div>
<div class="container">
<img src="..." class="image">
<p>Fall Berry Blitz Tea</p>
</div>
</div>
<div class="container">
<img src="..." class="image">
<p>Spiced Rum Tea</p>
</div>
</div>
<div class="container">
<img src="..." class="image">
<p>Seasonal Donuts</p>
</div>
</div>
<div class="container">
<img src="..." class="image">
<p>Myrtle Ave Tea</p>
</div>
</div>
<div class="container">
<img src="..." class="image">
<p>Bedford Bizarre Tea</p>
</div>
</div>
<!-- URL of images is correct -->
/* CSS */
.parent {
display: flex;
flex-wrap: wrap;
justify-content: center;
width: 1000px;
margin: 0 auto;
}
.headline {
display: block;
width: 100%;
}
.container {
margin: 0px 10px;
}
.image {
width: 300px;
height: 200px;
}
I expect the divs would wrap on next line. But there always are 3 divs on first and 2 divs on second line.
Your HTML contained some invalid closure tags, please validate your HTML you can check out: https://validator.w3.org/
Also removed the fixed width of 1000px, you want to have a fluid parent so it sizes acording to the device or browser width.
/* CSS */
.parent {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin: 0 auto;
/* changed */
width: 100%;
}
.headline {
display: block;
width: 100%;
}
.container {
margin: 0px 10px;
}
.image {
width: 300px;
height: 200px;
}
<!-- HTML -->
<div class="parent">
<div class="headline">
<h2>Tea of the Month</h2>
<h4>What's Stepping at The Tea Cozy?</h4>
</div>
<div class="container">
<img src="https://placehold.it/300x300" class="image">
<p>Fall Berry Blitz Tea</p>
</div>
<!-- </div> REMOVED -->
<div class="container">
<img src="https://placehold.it/300x300" class="image">
<p>Spiced Rum Tea</p>
</div>
<!-- </div> REMOVED -->
<div class="container">
<img src="https://placehold.it/300x300" class="image">
<p>Seasonal Donuts</p>
</div>
<!-- </div> REMOVED -->
<div class="container">
<img src="https://placehold.it/300x300" class="image">
<p>Myrtle Ave Tea</p>
</div>
<!-- </div> REMOVED -->
<div class="container">
<img src="https://placehold.it/300x300" class="image">
<p>Bedford Bizarre Tea</p>
</div>
<div class="container">
<img src="https://placehold.it/300x300" class="image">
<p>Bedford Bizarre Tea</p>
</div>
<div class="container">
<img src="https://placehold.it/300x300" class="image">
<p>Bedford Bizarre Tea</p>
</div>
</div>
It happens because you set width:1000px on your .parent. This means that no matter the device size the parent will always be 1000px and there will always be 3 elements on the first row.
To solve this, set .parent {width: 100%; max-width: 1000px;}
cheers

Specific columns

I've been doing some stuff with HTML and I need to have a few columns. I know how to make them and the basics of how they work. However, there is a certain problem that I have. I need to have 3 columns that have an image on top, then text on bottom. However, the text on bottom can't flow into the next column if the browser is resized - it just needs to go up or down. What I have so far:
body {
background-color: white;
font-family: times, serif;
color: black;
}
div {
display: flex;
margin: 50px;
flex-wrap: wrap;
}
<div>
<div class="first">
<img src="Images/australia_flag.jpg" alt="Australian Flag" title="Australian Flag" height="200" width="300"> text as well </div>
<div class="second">
<img src="Images/brazil_flag.jpg" alt="Brazilian Flag" title="Brazilian Flag"> even more text </div>
<div class="third">
<img src="Images/china_flag.jpg" alt="Chinese Flag" title="Chinese Flag" height="200" width="300"> text again
</div>
</div>
not entirely sure if you mean columns or rows? Based on your code, it looks like rows. If that's the case, I'm not sure what you mean by "flow into the next column"? You might check out the relative and absolute values for CSS position.
If, in fact, you do actually mean columns, I'd strongly advise using Bootstrap's Grid System. This is great for creating responsive columns.
Please take a look at this simple 3 column layout with a full width content area on top and bottom here: https://jsfiddle.net/7drfva0o/2/
.top, .bottom {
width:98%;
padding:1%;
background-color: red;
clear:both;
}
.cols {
width:31%;
padding:1%;
float:left;
background-color:blue;
border: 1px solid #FFF;
}
Is that what you're looking for?
First, you'll need to improve your markup: having images and texts as DOM node to be "flexed"
HTML markup improved
<div class="wrapper">
<div class="column">
<img src="..." />
<p>text</p>
</div>
<div class="column">
<img src="..." />
<p>text</p>
</div>
<div class="column">
<img src="..." />
<p>text</p>
</div>
</div>
Then, each of your div is going to have display: flex + flex-direction: column to allow the image going on top and the text going below. You will be able to adjust margin or whatever. At the minimum, I'd go like this:
CSS improved
.wrapper {
display: flex;
}
.column {
margin: 5px;
display: flex;
flex-direction: column;
}
Wrapped altogether, here is a snippet of what I think you're trying to achieve
Snippet
.wrapper {
display: flex;
}
.column {
margin: 5px;
display: flex;
flex-direction: column;
}
<div class="wrapper">
<div class="column">
<img src="http://fakeimg.pl/300x200" />
<p>text as well</p>
</div>
<div class="column">
<img src="http://fakeimg.pl/300x200" />
<p>text as well</p>
</div>
<div class="column">
<img src="http://fakeimg.pl/300x200" />
<p>text as well</p>
</div>
</div>
Then, feel free to play with flexbox properties to align, wrap, adjust alignments, etc. Great documentation on CSS-Tricks : https://css-tricks.com/snippets/css/a-guide-to-flexbox/

How to create a grid of images using flexbox that fully wraps around a main image?

I want to create a grid of images that first has a large featured image, then to it's right, has a grid of 4 (2 on each row).. and then underneath that, rows of 4 images at a time.
Loosely based on this design.
I think flexbox would probably be able to nail this one.
Say I have some markup like this
<div class="image-grid">
<div>
<img src="https://unsplash.it/1024/1024">
</div>
<div>
<img src="https://unsplash.it/1000/800">
</div>
<div>
<img src="https://unsplash.it/1100/1000">
</div>
<div>
<img src="https://unsplash.it/1120/1000">
</div>
<div>
<img src="https://unsplash.it/1130/1024">
</div>
<div>
<img src="https://unsplash.it/1101/1024">
</div>
<div>
<img src="https://unsplash.it/1020/1024">
</div>
<div>
<img src="https://unsplash.it/1021/1024">
</div>
<div>
<img src="https://unsplash.it/1002/1024">
</div>
<div>
<img src="https://unsplash.it/1003/1024">
</div>
<div>
<img src="https://unsplash.it/1004/1024">
</div>
<div>
<img src="https://unsplash.it/1005/1024">
</div>
</div>
with CSS
.image-grid {
display: flex;
flex-wrap: wrap;
}
img {
width: 100%;
}
.image-grid > div:first-child {
flex-basis: 50%;
}
.image-grid > div {
flex-basis: 25%;
}
this almost does what I need it to. Codepen here.
I need two things fixed though...
display 4 images to the right of the featured image, instead of the current 2.
stretch each image to fit it's space so it's a tight grid (no spacing around any image). I'm thinking of using the object-fit CSS property but I haven't got it working yet.
Thank you.
So I figured the easiest way would be to use a framework like Foundation to create the top row, and then use flexbox for the rest.
<div class="row">
<div class="medium-6 columns featured-image">
<img src="https://unsplash.it/1023/1024">
</div>
<div class="medium-6 columns featured-image-grid">
<div class="row">
<div class="medium-6 columns">
<img src="https://unsplash.it/1024/1024">
</div>
<div class="medium-6 columns">
<img src="https://unsplash.it/1022/1024">
</div>
</div>
<div class="row">
<div class="medium-6 columns">
<img src="https://unsplash.it/1021/1024">
</div>
<div class="medium-6 columns">
<img src="https://unsplash.it/1020/1024">
</div>
</div>
</div>
</div>
<div class="image-grid">
<img src="https://unsplash.it/1020/1024">
<img src="https://unsplash.it/1020/1025">
<img src="https://unsplash.it/1020/1022">
<img src="https://unsplash.it/1020/1021">
<img src="https://unsplash.it/1020/1029">
<img src="https://unsplash.it/1020/1028">
<img src="https://unsplash.it/1020/1027">
<img src="https://unsplash.it/1020/1023">
<img src="https://unsplash.it/1020/1024">
<img src="https://unsplash.it/1020/1025">
</div>
with the CSS
.row {
max-width: 100%;
margin: 0 !important;
}
.columns {
padding: 0;
}
.featured-image img {
height: 400px;
}
.featured-image-grid img {
height: 200px;
}
img {
object-fit: cover;
width: 100%;
}
.image-grid {
display: flex;
flex-wrap: wrap;
}
.image-grid > img {
flex-basis: 25%;
height: 200px;
width: auto;
}
Codepen here.
It needs some work to make it responsive, but it works for what I needed it to do.
.image-grid {
display: flex;
flex-wrap: wrap;
flex-direction: column;
width: 200px;
height: 100px;
}
.image-grid, .featured > img:first-child {
width: 100px;
height:100px;
}
.image-grid > img {
width: 50px;
height:50px;
}
<div class="image-grid featured">
<img src="https://unsplash.it/1024/1024">
<img src="https://unsplash.it/1000/800">
<img src="https://unsplash.it/1100/1000">
<img src="https://unsplash.it/1120/1000">
<img src="https://unsplash.it/1130/1024">
</div>
<div class="image-grid">
<img src="https://unsplash.it/1101/1024">
<img src="https://unsplash.it/1020/1024">
<img src="https://unsplash.it/1021/1024">
<img src="https://unsplash.it/1002/1024">
<img src="https://unsplash.it/1003/1024">
<img src="https://unsplash.it/1004/1024">
<img src="https://unsplash.it/1005/1024">
</div>

2 stacked containers to the right of an image

I'm trying to achieve the following layout for a search result box. Specifically a 100% width and height image that on the right has two stacked containers that equals the height of the image, each with differing background colours that are butted up right against the image.
All attempts to achieve this simple layout are failing miserably. The issue I keep hitting is the when using something like:
<div class="search-result-box">
<div class="row">
<div class="col-md-3">
<img src="" class="img-responsive" style="height: 196px;" height="196">
</div>
<div class="col-md-9">
...
</div>
</div>
</div>
The image doesn't quite fill the col-md-3 column completely and thus you see the column's background.
What's the best way to do this?
Bootstrap columns have a padding of 15px by default. Also the image width has to be 100%. You can do something like this:
<div class="search-result-box">
<div class="row">
<div class="col-md-3" style="padding: 0;">
<img src="" class="img-responsive" style="width: 100%;">
</div>
<div class="col-md-9">
...
</div>
</div>
</div>
Jsfiddle: http://jsfiddle.net/HM4gE/1/
I wouldn't use Bootstrap columns though to achieve this since you seem to have some fixed heights and widths for columns. Instead I would do it like this (given that the height and the width of the image is always 196px): http://jsfiddle.net/HM4gE/2/
Check browser support for calc() before using it: http://caniuse.com/calc
Here a possible answer:
<div class="search-result-box">
<div class="row">
<div class="col-md-3">
<img src="" class="img-responsive" style="height: 196px;" height="196" />
</div>
<div class="col-md-9">
<div class="title">Title</div>
<div>Link1</div>
</div>
</div>
</div>
.search-result-box {
display: table;
width: 100%;
}
.row {
display: table-row;
}
.row > * {
display: table-cell;
}
.col-md-3 {
background: orange;
width: 260px;
height: 196px;
}
.col-md-9 {
vertical-align:top;
background: grey;
}
.title {
background: #ccc;
width: 100%;
height: 150px;
}
http://jsfiddle.net/junkie/fAPQ6/2/