How to scale a number of images to fill area - css

I'm trying to fill an area of web page of a certain, fixed size with an unknown number of images (max 10), maximising the size of the images without overflowing the area. To be mobile friendly, I want it to work both in landscape and portrait mode without needing scrolling.
I've been trying to use flexboxes to have the images wrap, but then they don't scale down and end up overflowing the area. If I use non-wrapping flexboxes, the images scale in landscape mode, but not in portrait. I feel there should be a nice, simple solution to this. Any ideas?
Update:
Here's the essence of the code I've got so far. I've been trying a lot of different things, but this is the cleanest.
html {
height: 100%;
}
body {
padding-top: 0;
padding-bottom: 0;
height: 100%;
}
.container {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
text-align: center;
}
.above {
margin-bottom: 20px;
font-size: larger;
background-color: lightgrey;
}
.middle {
flex-grow: 1;
max-height: 100%;
}
.below {
margin-top: 20px;
background-color: lightgrey;
}
img {
border: 5px solid transparent;
height: 100%;
}
.images {
flex-direction: row;
justify-content: center;
display: flex;
flex-wrap: wrap;
height: 100%;
}
.image {
margin: 5px;
}
<html>
<body>
<div class="container">
<div class="above">
Some text about the images
</div>
<div class="middle">
<div class="images">
<div class="image">
<img src="https://dummyimage.com/200x200/000/fff" alt="" />
</div>
<div class="image">
<img src="https://dummyimage.com/200x200/000/fff" alt="" />
</div>
<div class="image">
<img src="https://dummyimage.com/200x200/000/fff" alt="" />
</div>
<div class="image">
<img src="https://dummyimage.com/200x200/000/fff" alt="" />
</div>
<div class="image">
<img src="https://dummyimage.com/200x200/000/fff" alt="" />
</div>
<div class="image">
<img src="https://dummyimage.com/200x200/000/fff" alt="" />
</div>
<div class="image">
<img src="https://dummyimage.com/200x200/000/fff" alt="" />
</div>
<div class="image">
<img src="https://dummyimage.com/200x200/000/fff" alt="" />
</div>
<div class="image">
<img src="https://dummyimage.com/200x200/000/fff" alt="" />
</div>
<div class="image">
<img src="https://dummyimage.com/200x200/000/fff" alt="" />
</div>
</div>
</div>
<div class="below">
<button>Ok</button>
<button>Cancel</button>
</div>
</div>
</body>
</html>
The point is to try to get the images to stay completely within the div called "middle", but scaled as large as possible. Here are a few wireframes.
Landscape, 10 images:
Portrait, 10 images:
Portrait, 4 images

I Think you need to consider flex property here, it's the short hand version of flex-grow, flex-shrink, and flex-basis properties. See if this is what you're looking for.
html,body{
padding: 0;
margin: 0;
width: 100vw;
box-sizing: border-box;
}
.container{
width: 100%;
display: flex;
align-items: flex-start;
justify-content: flex-start;
flex-direction: column;
}
.row{
display: flex;
width: 100%;
flex-direction: row;
}
.col{
display: flex;
width: 100%;
flex-wrap: wrap;
justify-content: center;
align-items: center;
text-align: center;
}
.item{
display: flex;
max-width: 100%;
height: 150px;
background-color: #222;
margin: 1%;
flex: 1 1 15%;
}
#media only screen and (max-width: 600px) {
.item {
height: 100px;
flex: 1 1 45%;
max-width: 100%;
}
}
<div class="container">
<div class="row ">
<div class="col">
<h1>some text about images</h1>
</div>
</div>
<div class="row">
<div class="col">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
<div class="row">
<div class="col">
<p>Some other elements</p>
</div>
</div>
</div>

Related

Image goes out of flexbox

I have an image that I want to fit in flexbox.
Card has fixed size, and I want the image to fit in without specifying size but it just ignores flexbox.
.card {
border: 2px solid #072227;
border-radius: 20px;
display: flex;
height: 30vh;
width: 40vw;
}
.card__profile-image {
display: flex;
flex-direction: column;
}
.img__cont img {
height: 100%;
}
.img__cont {
}
.card__name {
min-height: 100%;
}
<div class="card">
<div class="card__section card__profile-image">
<div class="img__cont">
<!-- <div class="image"> -->
<img src="https://scontent.fkiv9-2.fna.fbcdn.net/v/t39.30808-6/317808332_704091791080096_1098720845539800517_n.jpg?_nc_cat=1&ccb=1-7&_nc_sid=09cbfe&_nc_ohc=FFO8v3dmkM8AX_aR9js&_nc_ht=scontent.fkiv9-2.fna&oh=00_AfDQCQcHmZH4QuauHvdxiLEFX0rExv9gMENs8ptsEzdoYg&oe=63DEF9AD" alt="Profile Picture" />
<!-- </div> -->
</div>
<div class="card__name">Alex Hill</div>
</div>
<div class="card__section">
<div class="card__info-top">
<span class="info__top-job">Senior Developer | A1-D</span>
<span class="info__top-contact">alexhill#0001</span>
</div>
<div class="card__info-bottom">6 000$</div>
</div>
</div>
https://codepen.io/watermelon-and-me/pen/jOpQGje
UPD.
Expected result:
https://i.imgur.com/MBRLAMp.png
On .img__cont and .img__cont img, set max-width and max-height to 100% each.
.card {
border: 2px solid #072227;
border-radius: 20px;
display: flex;
height: 30vh;
width: 40vw;
}
.card__profile-image {
display: flex;
flex-direction: column;
}
.img__cont, .img__cont img {
max-width: 100%;
max-height: 100%;
}
.card__name {
min-height: 100%;
}
<div class="card">
<div class="card__section card__profile-image">
<div class="img__cont">
<!-- <div class="image"> -->
<img src="https://scontent.fkiv9-2.fna.fbcdn.net/v/t39.30808-6/317808332_704091791080096_1098720845539800517_n.jpg?_nc_cat=1&ccb=1-7&_nc_sid=09cbfe&_nc_ohc=FFO8v3dmkM8AX_aR9js&_nc_ht=scontent.fkiv9-2.fna&oh=00_AfDQCQcHmZH4QuauHvdxiLEFX0rExv9gMENs8ptsEzdoYg&oe=63DEF9AD" alt="Profile Picture" />
<!-- </div> -->
</div>
<div class="card__name">Alex Hill</div>
</div>
<div class="card__section">
<div class="card__info-top">
<span class="info__top-job">Senior Developer | A1-D</span>
<span class="info__top-contact">alexhill#0001</span>
</div>
<div class="card__info-bottom">6 000$</div>
</div>
</div>

What am i doing wrong with flexbox trying to align these images?

So I am trying to align images one next to another with display flex but they're not working, tried a lot of things but none of them helped
.container {
display: flex;
width: 100%;
flex-wrap: wrap;
}
.image {
width: 100%;
margin-right: 10px;
}
<div class="container">
<div class="image">
<img src="photo.jpg">
</div>
<div class="image">
<img src="photo.jpg">
</div>
<div class="image">
<img src="photo.jpg">
</div>
<div class="image">
<img src="photo.jpg">
</div>
</div>
You need to remove
width: 100%;
from your .image styles.
Working Example:
.container {
display: flex;
width: 100%;
flex-wrap: wrap;
}
.image {
margin-right: 10px;
}
<div class="container">
<div class="image">
<img src="photo.jpg">
</div>
<div class="image">
<img src="photo.jpg">
</div>
<div class="image">
<img src="photo.jpg">
</div>
<div class="image">
<img src="photo.jpg">
</div>
</div>
Update:
Do you want a single row of 4 images? If so, you'll need to give each image a width or a flex-basis of equal to or less than 25% of the .container.
Otherwise an image will be assumed to have a width corresponding to its original size.
You can achieve this by inserting .image {flex: 0 1 25%;} into your CSS:
.container {
display: flex;
width: 100%;
flex-wrap: wrap;
}
.image {
flex: 0 1 25%;
margin-right: 10px;
}

Fill vertical space with Flexbox in a list of items

I have a list of items, each one in display: flex to position its children elements. The height of the item is given by the image, and the button at the right position should fill the vertical space of the item. But I can't do that.
.Main-item {
display: flex;
border: 1px solid gray;
margin-bottom: 2px;
}
.Main-img {
height: 50px;
width: 50px;
overflow: hidden;
object-fit: cover;
object-position: center;
border-radius: 50%;
}
.Main-name {
display: flex;
flex-wrap: wrap;
flex-direction: column;
justify-content: space-evenly;
align-items: flex-start;
flex: 1 1;
padding: 0 10px;
}
.Main-buttonWrapper {
height: 100%;
width: 146px;
}
.Main-button {
height: 100%;
width: 100%;
}
<div>
<div class="Main-item">
<img class="Main-img" src="https://picsum.photos/200/300" />
<div class="Main-name">Lorem ipsum</div>
<div class="Main-buttonWrapper"><button class="Main-button">button</button></div>
</div>
<div class="Main-item">
<img class="Main-img" src="https://picsum.photos/200/300" />
<div class="Main-name">Lorem ipsum</div>
<div class="Main-buttonWrapper"><button class="Main-button">button</button></div>
</div>
<div class="Main-item">
<img class="Main-img" src="https://picsum.photos/200/300" />
<div class="Main-name">Lorem ipsum</div>
<div class="Main-buttonWrapper"><button class="Main-button">button</button></div>
</div>
<div class="Main-item">
<img class="Main-img" src="https://picsum.photos/200/300" />
<div class="Main-name">Lorem ipsum</div>
<div class="Main-buttonWrapper"><button class="Main-button">button</button></div>
</div>
</div>
Any idea will be welcome!
When you create a flex container various default flex rules come into play.
Two of these default rules are flex-direction: row and align-items: stretch. This means that flex items will automatically align in a single row, and each item will fill the height of the container.
If you change the value of align-items to for example flex-start it will change the default behavior 'stretch' as well if you set a specific height to the child of a flex container.
So just remove the height: 100% from .Main-buttonWrapper and it will have the default behavior.
For a better understanding look this answer: https://stackoverflow.com/a/33220564/4966662
I've given a height to the Main-item + align-items:stretch;. I hope this is what you need.
.Main-item {
align-items:stretch;
height: 50px;
}
.Main-element {
padding-top: 16px;
}
.Main-item {
display: flex;
border: 1px solid gray;
margin-bottom: 2px;
align-items:stretch;
height: 50px;
}
.Main-img {
width: 50px;
overflow: hidden;
object-fit: cover;
object-position: center;
border-radius: 50%;
}
.Main-name {
display: flex;
flex-wrap: wrap;
flex-direction: column;
justify-content: space-evenly;
align-items: flex-start;
flex: 1 1;
padding: 0 10px;
}
.Main-buttonWrapper {
width: 146px;
}
.Main-button {
width: 100%;
height: 100%;
}
<div class="Main-element">
<div class="Main-item">
<img class="Main-img" src="https://picsum.photos/200/300" />
<div class="Main-name">Lorem ipsum</div>
<div class="Main-buttonWrapper"><button class="Main-button">button</button></div>
</div>
<div class="Main-item">
<img class="Main-img" src="https://picsum.photos/200/300" />
<div class="Main-name">Lorem ipsum</div>
<div class="Main-buttonWrapper"><button class="Main-button">button</button></div>
</div>
<div class="Main-item">
<img class="Main-img" src="https://picsum.photos/200/300" />
<div class="Main-name">Lorem ipsum</div>
<div class="Main-buttonWrapper"><button class="Main-button">button</button></div>
</div>
<div class="Main-item">
<img class="Main-img" src="https://picsum.photos/200/300" />
<div class="Main-name">Lorem ipsum</div>
<div class="Main-buttonWrapper"><button class="Main-button">button</button></div>
</div>
</div>
A flex item stretches along the container cross axis by default, so the only thing you need to make the button stretch visually as well, is to make the button container a flex container by adding display: flex to .Main-buttonWrapper.

Maintain ratio of container and children while resize

I have modular grid of cards with and without image, based on flexbox.
Normally cards without image are 50% of the width, cards with image are 100% of the width, and those cards without image that doesn't have a pair are also 100%.
----------------
[[ txt ][ img ]] – card with an image
----------------
[ txt ][ txt ] – 2 cards without image
----------------
[ txt ] – card without image
----------------
[[ txt ][ img ]] – card with an image
----------------
Is it possible to maintain ratio of the cards and its content while resize, and also maintain modularity with css?
Here's the code
that let me maintain ratio, but when I try to apply this technique to cards children everything breakes
<div class="wrapper">
<div class="card">
<div class="card-text">
</div>
<div class="card-image">
</div>
</div>
</div>
.wrapper
display: flex
flex-wrap: wrap
justify-content: space-between
width: 620px
.card
height: 0
padding-bottom: 50%
display: flex
flex-direction: row
justify-content: space-between
flex: 1 1 300px
.has-card-image .card-text,
.has-card-image .card-image
height: 300px
width: 300px
I can see one way this could be done w/o script.
Either as in this case, using px values, or e.g. using vw, and the reason is that the card-text and card-image needs to know the wrapper's width to be able to size according to the expected output (which mean percent can't be used).
Fiddle demo
Stack snippet
.wrapper {
display: flex;
flex-wrap: wrap;
width: 600px;
}
.card {
display: flex;
flex: 1 300px;
}
.card .card-text,
.card .card-image {
height: 100px;
width: 300px;
}
.card .card-text:only-child {
flex: 1 300px;
}
/* demo styles */
.card .card-text, .card .card-image {
border: 1px solid;
box-sizing: border-box;
}
.card .card-text::before {
content: 'text';
}
.card .card-image::before {
content: 'image';
}
<div class="wrapper">
<div class="card">
<div class="card-text">
</div>
<div class="card-image">
</div>
</div>
<div class="card">
<div class="card-text">
</div>
</div>
<div class="card">
<div class="card-text">
</div>
</div>
<div class="card">
<div class="card-text">
</div>
</div>
<div class="card">
<div class="card-text">
</div>
<div class="card-image">
</div>
</div>
</div>
If you need the margin, you'll need an extra wrapper
Fiddle demo
Stack snippet
.wrapper {
width: 620px;
overflow: hidden;
}
.inner {
display: flex;
flex-wrap: wrap;
margin-left: -20px;
}
.card {
display: flex;
flex: 1 300px;
}
.card .card-text,
.card .card-image {
height: 100px;
width: 300px;
margin-left: 20px;
}
.card .card-text:only-child {
flex: 1 300px;
}
/* demo styles */
.card .card-text,
.card .card-image {
border: 1px solid;
box-sizing: border-box;
}
.card .card-text::before {
content: 'text';
}
.card .card-image::before {
content: 'image';
}
<div class="wrapper">
<div class="inner">
<div class="card">
<div class="card-text">
</div>
<div class="card-image">
</div>
</div>
<div class="card">
<div class="card-text">
</div>
</div>
<div class="card">
<div class="card-text">
</div>
</div>
<div class="card">
<div class="card-text">
</div>
</div>
<div class="card">
<div class="card-text">
</div>
<div class="card-image">
</div>
</div>
</div>
</div>
Updated
Here is a version using vw and margin, and is responsive.
Note, the make up for margin set on the wrapper can also be set on each item, though I found it simpler like this.
Fiddle demo
Stack snippet
.wrapper {
width: calc(80vw + 20px); /* 20px extra for margin */
margin: 0 auto;
overflow: hidden;
}
.inner {
display: flex;
flex-wrap: wrap;
margin-left: -20px;
}
.card {
display: flex;
flex: 1 40vw;
}
.card .card-text,
.card .card-image {
height: 100px;
width: 40vw;
margin-left: 20px;
}
.card .card-text:only-child {
flex: 1 40vw;
}
/* demo styles */
.card .card-text,
.card .card-image {
border: 1px solid;
box-sizing: border-box;
}
.card .card-text::before {
content: 'text';
}
.card .card-image::before {
content: 'image';
}
<div class="wrapper">
<div class="inner">
<div class="card">
<div class="card-text">
</div>
<div class="card-image">
</div>
</div>
<div class="card">
<div class="card-text">
</div>
</div>
<div class="card">
<div class="card-text">
</div>
</div>
<div class="card">
<div class="card-text">
</div>
</div>
<div class="card">
<div class="card-text">
</div>
<div class="card-image">
</div>
</div>
</div>
</div>

How to make a layout, where the 3rd child is full width?

Is it possible to make the following layout just with Flexbox? Or what would be the recommended way?
Example code (getting images from an API):
<div class="container">
{images.map(image => {
return(
<div class="item">
<img src={image.thumbnail} />
</div>
);
})}
</div>
Example CSS:
.container {
display: flex;
flex-flow: row wrap;
}
img:nth-child(3) {
flex: 1 100%;
}
Simply set flex-basis: 100% to your third flex item
An additional rule setting the img to width: 100% will make them size properly.
Also, for best cross browser support, keep the wrapper around each img
.container {
display: flex;
flex-flow: row wrap;
}
.item {
background: lightgray;
flex-basis: calc(50% - 10px);
margin: 5px;
}
.item:nth-child(3) {
flex-basis: calc(100% - 10px);
}
.item img {
width: 100%;
}
<div class="container">
<div class="item">
<img src='http://placehold.it/300x100' />
</div>
<div class="item">
<img src='http://placehold.it/300x100' />
</div>
<div class="item">
<img src='http://placehold.it/300x100' />
</div>
<div class="item">
<img src='http://placehold.it/300x100' />
</div>
<div class="item">
<img src='http://placehold.it/300x100' />
</div>
<div class="item">
<img src='http://placehold.it/300x100' />
</div>
<div class="item">
<img src='http://placehold.it/300x100' />
</div>
</div>
Maybe i don't understand correctly what you want, but here it is :
see jsFiddle or snippet below
.container {
display: flex;
flex-flow: row wrap;
}
img {
height:auto;
flex:1 50%;
}
img:nth-child(3) {
flex: 1 100%;
}
<div class="container">
<img src="http://via.placeholder.com/150x150">
<img src="http://via.placeholder.com/150x150">
<img src="http://via.placeholder.com/150x150">
<img src="http://via.placeholder.com/150x150">
<img src="http://via.placeholder.com/150x150">
<img src="http://via.placeholder.com/150x150">
<img src="http://via.placeholder.com/150x150">
<img src="http://via.placeholder.com/150x150">
<img src="http://via.placeholder.com/150x150">
<img src="http://via.placeholder.com/150x150">
<img src="http://via.placeholder.com/150x150">
</div>
In your example you're doing img:nth-child(3) but your images are wrapped with an div. So your images are not the flex childs. Here is a possible solution to your problem:
.container {
display: flex;
flex-wrap: wrap;
}
.container div{
width: 50%;
/* just for demonstration, not needed: */
text-align:center;
margin-bottom: 10px;
background-color: #eee;
border: 2px solid white;
box-sizing: border-box;
}
.container div:nth-child(3) {
width: 100%;
}
<div class="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
Your CSS works, you just need an additional rule for the other images to get two each into the other rows, plus you can leave out the wrapping DIVs (if that's not possible/desired, just apply the same rules to the DIVs instead and set all image widths to 100%):
.container {
display: flex;
flex-flow: row wrap;
}
img {
box-sizing: border-box;
width: 50%;
padding: 10px;
}
img:nth-child(3) {
flex: 1 100%;
}
<div class="container">
<img src="http://placehold.it/500x200/ed8">
<img src="http://placehold.it/500x200/ed8">
<img src="http://placehold.it/500x200/ed8">
<img src="http://placehold.it/500x200/ed8">
<img src="http://placehold.it/500x200/ed8">
<img src="http://placehold.it/500x200/ed8">
<img src="http://placehold.it/500x200/ed8">
<img src="http://placehold.it/500x200/ed8">
</div>

Resources