Flexbox Grid with Images - Maintain Aspect Ratio / Proportions - html

I'm trying to use flexbox to layout something like the following:
-- ------ --
| | | |
|--| |--|
| | | |
-- ------ --
Each corner 'box' has an img within it who's aspect ratio is 1:1 (square). The center 'box' is 3:2.
The problem is for whatever reason the height of the corner boxes and the center box is larger than the hight of the responsive img within it, I'm trying to get them to align perfectly.
How can I get the flex items to line up correctly?
Here's a codepen: https://codepen.io/codybarr/pen/zNgpVK
EDIT: adding display: flex to .container .item fixed the issue in Firefox but not Chrome/Safari. Now the images stretch to be their full resolution height..weird...
img {
max-width: 100%;
}
#media (min-width: 700px) {
.main {
display: flex;
flex-direction: row;
background-color: orange;
}
.container {
display: flex;
flex-direction: column;
}
.container.second-column {
flex: 1 0 60%;
}
.container .item {
display: flex;
}
.container.second-column .item {}
.container.first-column .item:nth-child(1) {
background-color: blue;
}
.container.first-column .item:nth-child(2) {
background-color: yellow;
}
.container.third-column .item:nth-child(1) {
background-color: red;
}
.container.third-column .item:nth-child(2) {
background-color: green;
}
}
<head>
<title>Flex Testing</title>
</head>
<body>
<h1>Flex Test!</h1>
<div class="main">
<div class="container first-column">
<div class="item">
<img src="http://i-cdn.phonearena.com/images/article/90741-image/Google-touts-advanced-recipe-search-in-mobile-app.jpg" />
</div>
<div class="item">
<img src="https://lh3.googleusercontent.com/-cigJW9TQSRU/AAAAAAAAAAI/AAAAAAAAABg/Pg3e9ogcsHU/s640/photo.jpg" />
</div>
</div>
<div class="container second-column">
<div class="item">
<img src="https://www.inetsolutions.org/wp-content/uploads/2016/01/Capital-Letters-in-URLs-Do-Not-Influence-Google-Rankings.png" />
</div>
</div>
<div class="container third-column">
<div class="item">
<img src="http://www.sociallyawareblog.com/files/2016/12/GettyImages-610773752_small.jpg" />
</div>
<div class="item">
<img src="https://s-media-cache-ak0.pinimg.com/564x/b1/e2/db/b1e2dbe6c6b547a2ebc53a49fc3ffa8c.jpg" />
</div>
</div>
</div>
</body>

An initial setting of a flex container is align-items: stretch. This means that flex items will expand, by default, to cover the full length of the cross axis of the container.
Consider overriding the default with align-items: flex-start.
container .item {
display: flex;
align-items: flex-start; /* new */
}
revised codepen

Related

How to make these image tiles responsive

I have 3 image tiles (Image and Description) within a div element. I have used a flexbox such that all the 3 tiles are shown side by side in a row in full screen view. But when shown in a smaller screen, I want 2 of the tiles to be in the first row and the third tile to start a new second row. I tried it by giving the tile width 33% in the full screen case and width 50% in the smaller screen view but it isn't working mostly because I've made some mistake.
.container{
display: flex;
flex-direction: row;
}
.tile {
width: 33%;
}
.img {
width: 100%;
}
#media screen and (max-width: 685px) {
.tile{
width:50%;
}
<div class="container">
<div class="tile">
<img class="img" src="Sld1.jpg">
<p>Img1</p>
</div>
<div class="tile">
<img class="img" src="Sld2.jpg" >
<p>Img2</p>
</div>
<div class="tile">
<img class="img" src="Sld3.jpg">
<p>Img3</p>
</div>
</div>
<div class="container">
<div class="tile">
<img class="img" src="Sld1.jpg">
<p>Img1</p>
</div>
<div class="tile">
<img class="img" src="Sld2.jpg" >
<p>Img2</p>
</div>
<div class="tile">
<img class="img" src="Sld3.jpg">
<p>Img3</p>
</div>
</div>
<style>
.container{
display: flex;
flex-direction: row;
}
.tile {
width: 33%;
}
.img {
width: 100%;
}
#media screen and (max-width: 685px) {
.tile{
width:50%;
}
}
</style>
I cant quite figure out what to write in the media screen function such that in small screen view there are 2 tiles in upper row and the third div tile of container moves to another row below it. Please help me out with the CSS.
Set flex-wrap: wrap so the flex container will wrap at break points and then you can set up a class to break the wrap in media query with flex-basis. Just add that class to the div with the tile selector.
.container{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}
.tile {
width: 33%;
}
.img {
width: 100%;
}
#media screen and (max-width: 685px) {
.tile {
width: 50%;
}
.break {
display: flex;
flex-basis: 55%; /* Change to 100% if you want it to fill up entire area under two images on top */
}
<div class="container">
<div class="tile two">
<img class="img" src="Sld1.jpg">
<p>Img1</p>
</div>
<div class="tile two">
<img class="img" src="Sld2.jpg" >
<p>Img2</p>
</div>
<div class="tile break">
<img class="img" src="Sld3.jpg">
<p>Img3</p>
</div>
</div>
All you need to do is to add flex-wrap: wrap inside your container class.
.container{
display: flex;
flex-direction: row;
flex-wrap: wrap;
}

Resize flex items to fit container (prevent items from overflowing)

I've been struggling with an issue that i think will have a pretty simple solution, but i just can't see it right now. I have a nested flexbox layout. The first level of flex items are divs that are display:flex themselves, and depending on class they can have a flex-directon: of row or column. Both the first and second level of these nested flex items should grow to fill up the remaining parent size, and shrink if new elements are added, never overflowing.
My Problem: When adding new flex items to the "first level", this seems to work fine. However, adding new flex items to the second level seems to always overflow the parent container height.
As i'm not really good at describing stuff like this, here's a picture of what i need:
The purple box is the parent container (not flex)
The orange box is the flex container with flex-direction: row, with the red lines being its flex items (each item is a flexbox as well).
The blue lines are the nested flex items.
Nested Flexbox layout
Adding new red items works and expands or shrinks as needed, but adding new blue items, overflows the container.
https://jsfiddle.net/t40x7or8/
Here's my code sample:
CSS
width: 1800px;
height: 500px;
border: 4px blue solid;
}
.flex-container {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
}
.flex-item {
flex-grow: 1;
flex-basis: 0;
display: flex;
}
.flex-item > div {
flex-grow: 1;
border: 1px solid orange;
}
.height-1 {
flex-direction: column;
max-height: 100%;
}
.height-2 {
max-height: 100%;
}
img {
width: 100%;
height: 100%;
object-fit: cover;
}
HTML
<div class="flex-container">
<div class="height-2 flex-item">
<div class="img-div">
<img src="https://picsum.photos/1080/600" />
</div>
</div>
<div class="height-1 flex-item">
<div class="img-div">
<img src="https://picsum.photos/1080/601" />
</div>
<div class="img-div">
<img src="https://picsum.photos/1080/602" />
</div>
</div>
</div>
</div>
Sorry for the chaotic description, i'm quite bad at these kind of things.
Thanks for the help
I think we should use flex: 1 1 0 for the fix the layout of the flex items.
And using width: 100% to control the size of the inner image.
https://jsfiddle.net/ramseyfeng/kxf46bju/
.page {
border: 3px solid green;
width: 600px;
height: 300px;
}
.flex {
display: flex;
}
.cols {
display: flex;
flex-direction: row;
}
.rows {
display: flex;
flex-direction: column;
}
.flex-1-1-0 {
flex: 1 1 0;
}
.img-div {
flex: 1 1 0;
display: flex;
}
.img-div img {
width: 100%;
}
<div class="page cols">
<div class="flex-1-1-0 rows">
<div class="img-div">
<img src="https://picsum.photos/1080/600" />
</div>
</div>
<div class="flex-1-1-0 rows">
<div class="img-div">
<img src="https://picsum.photos/1080/601" />
</div>
<div class="img-div">
<img src="https://picsum.photos/1080/602" />
</div>
</div>
<div class="flex-1-1-0 rows">
<div class="img-div">
<img src="https://picsum.photos/1080/607" />
</div>
<div class="img-div">
<img src="https://picsum.photos/1080/608" />
</div>
</div>
<div class="flex-1-1-0 rows">
<div class="img-div">
<img src="https://picsum.photos/1080/605" />
</div>
<div class="img-div">
<img src="https://picsum.photos/2000/1000" />
</div>
<div class="img-div">
<img src="https://picsum.photos/2000/1001" />
</div>
</div>
</div>

Responsive CSS Image size effects row sizes

I know this sounds like it's been asked before but I've played around with a lot of techniques I've found from other questions and nothing seems to get the desired effect I need.
I'm trying to make something that will be responsive like this:
Responsive Example gif
I basically need an image to be centered, where the image is at 100% size.
Here is what I tried to get this effect:
I first made a div containing three child divs for "columns". Then inside the center column I made three child divs for "rows". Now I need the image to fill the max width it's allowed while still maintain that square aspect ratio. As well the height of the image should determine the height of the top and bottom rows.
Then it should just be a matter of having the text inside the top and bottom row align to the bottom and top of their divs respectively.
This would look something like this:
HTML Visualization of columns
HTML Visualization of center rows
The issue I'm running into is I can't seem to get the center image to determine the heights of the rows above and below it.
I've tried...
Flexbox
using vh (view height)
and a bit of using calc() but to no luck
Setting aspect ration with padding-top: 100%
What the code looks like
/* .row & .col from materialize.css */
.full {
height: 100vh;
}
.art_top {
height: 10vh;
/* I Don't actually want this fixed though */
padding-bottom: 10px;
display: flex;
}
.art_center {
height: 80vh;
/* I Don't actually want this fixed though */
}
.art_bottom {
height: 10vh;
/* I Don't actually want this fixed though */
padding-top: 10px;
display: flex;
}
#cover_art {
width: 100%;
height: 100%;
background: center / cover no-repeat;
}
#song_name {
align-self: flex-end;
}
#artist_name {
align-self: flex-start;
}
<div class="row">
<div class="col s2 m3 full"></div>
<div class="col s8 m6 full">
<div class="row art_top">
<a id="song_name" class="bold-title"></a>
</div>
<div class="row art_center">
<div id="cover_art"></div>
</div>
<div class="row art_bottom">
<a id="artist_name" class="bold-title"></a>
</div>
</div>
<div class="col s2 m3 full"></div>
</div>
Flexbox makes this kind of layout very straightforward. The trick is selectively allowing items to flex or shrink.
The flex property shorthand takes 3 values for flex-grow, flex-shrink, and flex-basis (the initial width or height depending on flex direction). Just keep clear which divs are serving as flex containers as you get into the details in the layout. It is very common to have divs that are both flex containers and flex items themselves too.
I also recommend using an img element instead of applying the image as a background so you dont have trouble with the aspect ratio in responsive window sizes.
A very nice resource: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
/* .row & .col from materialize.css */
body {
margin: 0;
}
.full {
height: 100vh;
}
.row {
display: flex;
}
.column {
flex: 1 1 auto;
}
.column2 {
background: #b4c2cf;
display: flex;
flex-direction: column;
}
.column1 {
background: #cbb3cc;
}
.column3 {
background: #cbb2b2;
display: flex;
align-items: center;
justify-content: center;
}
.art_top {
flex: 1 0 10vh;
display: flex;
justify-content: flex-start
align-self: flex-end;
}
.art_center {
flex: 1 1 auto;
display: flex;
align-items: center;
justify-content: center;
}
.art_bottom {
flex: 1 0 10vh;
text-align: right;
}
#cover_art {
max-width: 100%;
max-height: 100%;
width: auto;
height: auto;
}
#song_name {
align-self: flex-end;
}
#artist_name {
align-self: flex-start;
}
.bold-title {
display: block;
font-weight: bold;
padding: 10px;
}
.small-box {
background: #8f588c;
height: 100%;
max-height: 70px;
width: 100%;
max-width: 70px;
}
<div class="row full">
<div class="column column1"></div>
<div class="column column2">
<div class="art_top">
<a id="song_name" class="bold-title">My Album Title</a>
</div>
<div class="art_center">
<img id="cover_art" src="https://picsum.photos/400" />
</div>
<div class="art_bottom">
<a id="artist_name" class="bold-title">Artist Name</a>
</div>
</div>
<div class="column column3">
<div class="small-box"></div>
</div>
</div>

place two divs per row

so I have X divs and I want to put 2 divs in one row next to each other. If the screen size width is below n px there should be 1 div per row.
Currently I have this
#container {
display: flex;
}
.box {
width: 50px;
background: red;
}
#media(max-width: 300px) {
#container {
display: block;
}
}
<div id="container">
<div class="box"> 1 </div>
<div class="box"> 2</div>
<div class="box"> 3 </div>
<div class="box"> 4 </div>
</div>
How can I limit the flex box to two divs per row?
Add 50% width on .box and flex-wrap:wrap on the container
Additionally, what you did by changing display: flex to block was not required. Just change the .box elements width to 100%
#container {
display: flex;
flex-wrap: wrap;
}
.box {
width: 50%;
background: red;
}
#media(max-width: 300px) {
.box {
width: 100%;
}
}
<div id="container">
<div class="box"> 1 </div>
<div class="box"> 2</div>
<div class="box"> 3 </div>
<div class="box"> 4 </div>
</div>
Just add a property in your container class like
.container {
display: flex;
flex-wrap: wrap;
}
And in box class just specify the width of your box as 50% like
.box {
width: 50%;
background: red;
}
That should do the trick.
Flex will do a trick for you. flex-wrap: wrap for #container will make children wrap when necessary. .box with 50% and after breakpoint 100%.`
According to MDN:
The CSS flex-wrap property specifies whether flex items are forced into a single line or can be wrapped onto multiple lines. If wrapping is allowed, this property also enables you to control the direction in which lines are stacked.
If you are new to flexbox I recommend this guide.
Snippet
#container {
display: flex;
flex-wrap: wrap;
}
.box {
width: 50%;
background: red;
}
#media(max-width: 300px) {
.box {
width: 100%;
}
}
<div id="container">
<div class="box"> 1 </div>
<div class="box"> 2 </div>
<div class="box"> 3 </div>
<div class="box"> 4 </div>
</div>

How to use `flex: grow` on floating content?

I have a header with 2 rows of 2 Foundation columns of content, as below:
<div class="wrapper">
<div class="header row">
<div class="large-6 columns">
HEADER
</div>
<div class="large-6 columns">
menu
</div>
</div>
<div class="row">
<div class="large-5 none show-for-medium columns info">
Some information to the left
</div>
<div class="large-7 columns">
<div class="image-container">
<div class="image">
image to the right
</div>
</div>
</div>
</div>
</div>
The .header height is dynamic and not set. I want the .image element to take up 100% of the remaining vertical space.
eg:
To that affect I have tried using flex and flex-grow, eg:
.wrapper {
display: flex;
flex-direction: column;
min-height: 100vh;
width: 100%;
}
.image-container {
flex-grow: 1;
}
but had no luck, see fiddle: https://jsfiddle.net/9kkb2bxu/46/
Would anyone know how I could negate the dynamic height of the header from the 100vh of the image container?
.wrapper {
display: flex;
flex-direction: column;
min-height: 100vh;
width: 100%;
border: 1px solid black;
background-color: #ccc;
}
.row {
width: 100%;
}
.header {
background-color: green;
}
.info {
background-color: yellow;
border: 1px solid #ccc;
}
.image-container {
border: 1px solid black;
display: flex;
}
.image {
background-color: red;
flex-grow: 1;
width: 100%;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css" rel="stylesheet"/>
<div class="wrapper">
<div class="header row">
<div class="large-6 columns">
<h1>
HEADER
</h1>
</div>
<div class="large-6 columns">
<h1>
menu
</h1>
</div>
</div>
<div class="row">
<div class="large-5 none show-for-medium columns info">
Some information to the left
</div>
<div class="large-7 columns">
<div class="image-container">
<div class="image">
image to the right
</div>
</div>
</div>
</div>
</div>
Set the second row to take up the rest of the remaining height with flex: 1 and make sure you nest that flex with display: flex:
.row.target-row {
flex: 1;
display: flex;
}
Set the .image-container to 100% height of its column parent.
.image-container {
height: 100%;
}
By default both columns will expand. Stop the left column from expanding with:
.large-5 {
align-self: flex-start;
}
(flex-start reference: https://stackoverflow.com/a/40156422/2930477)
Complete Example
.wrapper {
display: flex;
flex-direction: column;
min-height: 100vh;
width: 100%;
border: 1px solid black;
background-color: #ccc;
}
.row {
width: 100%;
}
.header {
background-color: green;
}
.info {
background-color: yellow;
border: 1px solid #ccc;
}
.image-container {
height: 100%;
background-color: red;
}
.large-5 {
align-self: flex-start;
}
.row.target-row {
flex: 1;
display: flex;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css" rel="stylesheet" />
<div class="wrapper">
<div class="header row">
<div class="large-6 columns">
<h1>
HEADER
</h1>
</div>
<div class="large-6 columns">
<h1>
menu
</h1>
</div>
</div>
<div class="row target-row">
<div class="large-5 none show-for-medium columns info">
Some information to the left
</div>
<div class="large-7 columns">
<div class="image-container">
<div class="image">
image to the right
</div>
</div>
</div>
</div>
</div>
flex-grow only applies to flex children.
.image-container isn't a direct child of a display: flex element, so that property has no effect.
Plus, it affects the flex axis, which is not what you want.
Instead, you need to put those two elements in their own flex row, and use align-items (on the parent) and align-self (on either child) so that the first one aligns (on the cross axis) to flex-start (stick to top) and the second one to stretch.
You'll also want that flex row (parent) to have flex-grow: 1 so that it stretches along the vertical flex axis of its parent (.wrapper) to fill the rest of the page (otherwise, the grandchild will have nothing to stretch to).
For more information, read a good flex tutorial.
div.wrapper > div:not(.header).row {
flex: 1; /* 1 */
display: flex; /* 1 */
}
div.large-7.columns {
display: flex; /* 2 */
}
div.image-container { /* 3 */
flex: 1;
}
div.large-5.show-for-medium { /* 4 */
align-self: flex-start;
}
jsFiddle
Notes:
flex container and items consume all remaining height of respective parents
give children full height (via align-items: stretch initial setting)
flex item consumes all available width
yellow box does not need to expand to full height; now set to content height