Is there a way to achieve my Flexbox layout with calc? - html

I'm trying to arrange my containers with Flexbox (not Grid!) to look like this image
With the following HTML:
<div class="container">
<div class="sub-container">
<div class="top-sub-container">
<div class="box box-1">
<img src="yourChoice.png" />
<div class="box-text">
This is the text of the box 1
</div>
</div>
<div class="box box-2">
<img src="yourChoice.png" />
<div class="box-text">
This is the text of the box 2
</div>
</div>
</div>
<div class="box box-3">
<img src="yourChoice.png" />
<div class="box-text">
This is the text of the box 3
</div>
</div>
</div>
<div class="box box-4">
<img src="yourChoice.png" />
<div class="box-text">
This is the text of the box 4
</div>
</div>
</div>
And this CSS:
.container {
display: flex;
gap: 1rem;
height: 25rem;
width: 25rem;
padding: 1rem;
background: pink;
}
.top-sub-container {
flex: 1 1 auto;
display: flex;
gap: 1rem;
}
.sub-container {
flex: 1 1 auto;
display: flex;
gap: 1rem;
flex-direction: column;
}
.box {
display: flex;
flex: 1 1 auto;
flex-direction: column;
border: 1px solid black;
}
However I am getting stuck with my media queries and making this design responsive. Is it because I'm not using calc to evenly divide my flex items within the container? Or does calc have nothing to do with this problem?
If calc is irrelevant, how do I make this layout suitable for a media query with a max-width of 800px? When I test it out on different screen sizes using Dev Tools, there are large gaps.
I am trying to fix it by creating different media query outcomes, but now I'm wondering if there is a maximum amount of media queries I should be creating.
Your advice is gratefully appreciated.

You don't need to many containers, one parent div should be enough for the ".box" classed elements. With one parent, media queries would be much easier to control with different screen sizes.

Related

How to make divs stack on top of each other as page is minimized

I am trying to figure out how to make a section of divs on my page responsive so that as the page is minimized, the divs begin stacking on top of each other. I've tried flex-direction: column but that doesn't seem to be working. I have attached photos of what I am trying to achieve.
Here is my HTML:
<div>
<!-- <section> -->
<center>
<div class="container">
<div class="item3">
<image-tag src="https://></image-tag>
</div>
<div class="item3">
<image-tag src="https://></image-tag>
</div>
<div class="item3">
<image-tag src="https://></image-tag>
</div>
<div class="item3 idk">
<image-tag src="https://></image-tag>
</div>
<div class="item3 idk">
<image-tag src="https://></image-tag>
</div>
</div>
</center>
<!-- </section> -->
</div>
CSS
.container {
display: flex;
flex-direction: row;
}
Photos of what I am trying to achieve
Desktop
Tablet
Mobile
FYI I have taken some code out for confidentiality purposes.
try flex-wrap: wrap;
use .item3{ flex: 1 } if needed
A flex-box solution is hard because it is meant for 1 directional layouts where as your desired layout is 2 directional based on screen width. However, you can come close to the desired layout behavior by using flex-wrap which depends on either the width of your flex-items or flex-container to force the items to a new line. Try the below and adjust either the items' or container's width
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
align-items: start;
}
You can give max-width: 1200px; to your body element then
margin:0 auto to center vertically.
Than create a flexbox inside container class and make flex-wrap: wrap; to make flexbox create new row else all the images will always stay in same row.
You can also add padding: 0 1rem; for always having empty spaces when images comes to limit of wrapping.
/* RESET */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: antiquewhite;
min-height: 100vh;
max-width: 1200px;
margin: 0 auto;
}
img {
max-width: 100%;
display: block;
}
/* RESET ENDS */
.container {
display: flex;
flex-direction: row;
justify-content: center;
flex-wrap: wrap;
gap: 1rem;
padding: 0 1rem;
}
<div class="container">
<div class="item">
<img src="https://source.unsplash.com/random/375x375" alt="" />
</div>
<div class="item">
<img src="https://source.unsplash.com/random/375x375" alt="" />
</div>
<div class="item">
<img src="https://source.unsplash.com/random/375x375" alt="" />
</div>
<div class="item">
<img src="https://source.unsplash.com/random/375x375" alt="" />
</div>
<div class="item">
<img src="https://source.unsplash.com/random/375x375" alt="" />
</div>
</div>

Different number of divs based on how large is the screen best practices?

I am having a problem regarding elements inside a flex box. I am using flex: 1 1 auto with flex-flow: column wrap. I want to show a number of divs whose size increases along with that of the screen.
Using media queries would be so confusing and the code would be so large. I am searching for a way to achieve it without using media queries because the size of each div in the flex is about 200px each, I would need to make a lot of media queries incrementing from low to high resolutions.
The min-width property is rather useful here. I put fifteen divs to show the effect on multiple screen sizes.
.flex-parent {
display: flex;
flex-wrap: wrap; /* this makes the divs wrap */
}
.flex-child {
margin: 3px;
background-color: lightblue;
min-width: 200px; /*prevents the flex-child from shrinking more than 200px */
height: 50px;
flex: auto; /* this auto-adjusts the width */
/* Everything after this is just to align everything to the center */
padding-top: 20px;
text-align: center;
}
<div class='flex-parent'>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
<div class='flex-child'>CHILD</div>
</div>
Use flex-flow: row wrap.
If you want to show more div elements as the screen gets wider, you’ll want to use row for flex-direction, not column. With flex-direction: row, the flex items will be put into each line from left to right, like a line of text. And the bigger the screen, the more items will fit.
If you want your flex items to grow and fill all the available space, use flex: auto. This might mean the items end up with different sizes, because you can have a different number of items in each flex line. If you want all of them to be the same size, you could set something like flex: 200px.
.flex-container {
display: flex;
flex-flow: row wrap;
gap: 8px;
}
.flex-item {
flex: auto;
padding: 32px;
background-color: bisque;
}
<div class="flex-container">
<div class="flex-item">One</div>
<div class="flex-item">Two</div>
<div class="flex-item">Three</div>
<div class="flex-item">Four</div>
<div class="flex-item">Five</div>
<div class="flex-item">Six</div>
<div class="flex-item">Seven</div>
<div class="flex-item">Eight</div>
<div class="flex-item">Nine</div>
<div class="flex-item">Ten</div>
<div class="flex-item">Eleven</div>
<div class="flex-item">Twelve</div>
</div>
If you want to arrange the div elements as columns (top to bottom), then your flex container needs to have a height set on it, for example height: 500px. This is so that the flex container can calculate how many flex items can fit into each column.
.flex-container {
display: flex;
flex-flow: column wrap;
height: 100vh;
gap: 8px;
}
.flex-item {
flex: auto;
padding: 32px;
background-color: bisque;
}
<div class="flex-container">
<div class="flex-item">One</div>
<div class="flex-item">Two</div>
<div class="flex-item">Three</div>
<div class="flex-item">Four</div>
<div class="flex-item">Five</div>
<div class="flex-item">Six</div>
<div class="flex-item">Seven</div>
<div class="flex-item">Eight</div>
<div class="flex-item">Nine</div>
<div class="flex-item">Ten</div>
<div class="flex-item">Eleven</div>
<div class="flex-item">Twelve</div>
</div>

Make child flex measure the same height and width different row

I have 4 items inside a flex container. I want to make the 4 of them the same width and height, but always having them in 2 different rows (so a 2 X 2 grid).
Since the children are in different flex containers, they do not obey flex-grow: 1; Even the children of the same row do not obey the rule. And if I put them in the same container, they put themselves in the same row, and I need the 2 X 2 grid.
You can find a codepen here with the same code: https://codepen.io/mongolhippie/pen/yLYQbVd?editors=1100
.tile {
display: flex;
flex-direction: column;
border: 2px solid #A97C50;
border-radius: 20px;
padding: 20px;
margin: 25px;
/* THESE 3 OPTIONS TO CONTROLL HAVING THE SAME SPACE FOR EVERY TILE */
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
flex: 1;
}
.tile p {
font-size: min(calc( 1.125vw + 1.2rem ), 3.9rem);
}
.flex-center{
display: flex !important;
justify-content: center !important;
align-items: center;
}
.manual-link {
text-decoration: none !important;
color: var(--brown-dark);
}
.manual-link:hover {
text-decoration: none !important;
color: var(--brown-dark);
}
.icon-and-title{
display: flex;
align-items: center;
}
.icon-and-title p{
font-size: min(calc( 1.125vw + .9rem ), 3.9rem);
}
.icon-and-title img{
max-width: 100%;
height: auto;
transition: all .3s;
max-height: 80px;
margin-right: 20px;
margin-bottom: 10px;
}
<div class="flex-center">
<a class="manual-link" href="/manuals/manual-it.pdf">
<div class="tile">
<div class="icon-and-title">
<img src="https://i.pinimg.com/originals/06/bc/e8/06bce81285badba0c3becd273ca67f95.png" alt="">
<p>ADMIN</p>
</div>
<div class="links-manuals">
<p>For the administrator of the app</p>
</div>
</div>
</a>
<a class="manual-link" href="/manuals/manual-developers.pdf">
<div class="tile">
<div class="icon-and-title">
<img src="https://i.pinimg.com/originals/06/bc/e8/06bce81285badba0c3becd273ca67f95.png" alt="">
<p>DEVELOPERS</p>
</div>
<div class="links-manuals">
<p>To upgrade the Code</p>
</div>
</div>
</a>
</div>
<div class="flex-center">
<a class="manual-link" href="/manuals/manual-design.pdf">
<div class="tile">
<div class="icon-and-title">
<img src="https://i.pinimg.com/originals/06/bc/e8/06bce81285badba0c3becd273ca67f95.png" alt="">
<p>DESIGNERS</p>
</div>
<div class="links-manuals">
<p>Style guide</p>
</div>
</div>
</a>
<a class="manual-link" href="/manuals/ngo.pdf">
<div class="tile">
<div class="icon-and-title">
<img src="https://i.pinimg.com/originals/06/bc/e8/06bce81285badba0c3becd273ca67f95.png" alt="">
<p>NGOs</p>
</div>
<div class="links-manuals">
<p>The project</p>
</div>
</div>
</a>
</div>
Which is the secret to having them in a 2 X 2 disposition with the same width and height??
Thanks a lot!
Simply move from Flexbox to CSS GRID.
So change the CSS like this:
.flex-center{
display: grid;
grid-template-columns: 1fr 1fr;
}
Since you are handling your layout in 2 different rows we'll play with the grid-template-columns.
The fr unit tells the grid to have to "cells" with the same width.
Better renaming the class from .flex-center to something else since you'll use CSS GRID.
Here the updated working Codepen
Flebox are very good to make a 1D flexible container (vertically or horizontally) and can also handle multi-lines when they is no more space for all elements (instead of overflow the container)
BUT They is another display type used mainly for 2D flexible grid. And it's called grid, you should look at this guid in order to use it right.
As you want by default a 2D (2x2) grid, it'll be way easier to use it, This is a very basic grid you can set in order to have both columns and rows to take half of available space (50%)
.container {
display: grid;
grid-template-columns: 50% 50%;
grid-template-rows: 50% 50%;
}

How do I put elements two or three in a row?

I have to build a fluid, scalable, device-independent layout where I need to put 4 elements in a row so that they resize and stick together. Let’s say, 4 images, as they naturally are - one above another, and I just want to group them in two rows - 2 images side by side in 1 row so that I have no problems with layout or structure. Can you show me how? Thank you!
Use flexbox and make it responsive like this:
.element-container {
display: flex;
flex-direction: column;
width: 100%;
}
.element-row {
display: flex;
}
.element {
flex: 0 1 46%;
margin: 0 2% 20px 2%;
margin-bottom: 3%;
max-width: 150px;
}
.element img {
display: block;
width: 100%;
}
<div class="element-container">
<div class="element-row">
<div class="element">
<img src="http://via.placeholder.com/150x150">
</div>
<div class="element">
<img src="http://via.placeholder.com/150x150">
</div>
</div>
<div class="element-row">
<div class="element">
<img src="http://via.placeholder.com/150x150">
</div>
<div class="element">
<img src="http://via.placeholder.com/150x150">
</div>
</div>
</div>

Is there a DRY way of Flex ordering?

Newbie to flex use/web development.
I currently have 6 boxes within a flex container ordered like this for mobile devices:
Mobile view
with code more or less like this (CSS not included, but the class “box” is the grey box you see above):
<div class="flex-container">
<div class=“box item” />
<div class=“text item”>
<h4>Text</h4>
</div>
<div class=“box item” />
<div class=“text item”>
<h4>Text</h4>
</div>
<div class=“box item” />
<div class=“text item”>
<h4>Text</h4>
</div>
</div>
This is what I want for mobile devices!
For desktop however, I’d like to achieve this: Desktop View
Currently, the only way I’m achieving this is by using this unappealing flex order css:
item:nth-of-type(1) {order:1;}
item:nth-of-type(2) {order:2;}
item:nth-of-type(3) {order:4;}
item:nth-of-type(4) {order:3;}
item:nth-of-type(5) {order:5;}
item:nth-of-type(6) {order:6;}
My question is, is there a way to achieve my desired goal (i.e. switching the order of items 3 and 4) without having to order every single item in the container creating a yucky, repetitive block of code?
You can accomplish that with only 2 CSS selectors, and with order defaults to 0, we re-position item 3 and 5/6, here done with a media query for screens wider than 600px, to 1 and 2.
.item:nth-of-type(3) { order:1; } /* put 3 after 4 */
.item:nth-of-type(n+5) { order:2; } /* put 5,6 after 3 */
Stack snippet
.flex-container { display: flex; flex-wrap: wrap; }
.item { height: 50px; flex-basis: 100%; }
.box { background: lightgray; }
#media (min-width: 600px) {
.item { flex-basis: 50%; }
.item:nth-of-type(3) { order:1; } /* put 3 after 4 */
.item:nth-of-type(n+5) { order:2; } /* put 5,6 after 3 */
}
<div class="flex-container">
<div class="box item"></div>
<div class="text item">
<h4>Text</h4>
</div>
<div class="box item"></div>
<div class="text item">
<h4>Text</h4>
</div>
<div class="box item"></div>
<div class="text item">
<h4>Text</h4>
</div>
</div>
As far as I know if you reorder items, you need to explicitly order items after the re-ordered items. So you could probably do:
item:nth-of-type(3) {order:4;}
item:nth-of-type(4) {order:3;}
item:nth-of-type(5) {order:5;}
item:nth-of-type(6) {order:6;}
If you only ever want to switch those two, you could wrap them in another flex container and simply switch ordering within. That way your outer flow won't have to be redefined, and you could set up the container to be reused in other areas where you need to achieve the same thing.
<div class="container">
<div class="item one">One</div>
<div class="item two">Two</div>
<div class="item three">Three</div>
<div class="switch">
<div class="item four">Four</div>
<div class="item five">Five</div>
</div>
<div class="item six">Six</div>
<div class="item seven">Seven</div>
</div>
.item {
flex: 1 0 100%;
line-height: 39px;
height: 40px;
width: 100%;
background: #cecece;
margin-bottom: 10px;
text-align: center;
}
.container {
display: flex;
flex-wrap: wrap;
}
.switch {
display: flex;
flex-wrap: wrap;
flex: 1 0 100%;
}
#media (min-width: 400px) {
.switch .item:nth-of-type(1) {
order: 2;
}
}
fiddle
In addition to TripWire's answer, you need not to set a different order number for every <div> after the 4th one.
.item:nth-of-type(3), .item:nth-of-type(4) ~ .item {order:100;}
.item:nth-of-type(4) {order:50;}
A pen: https://codepen.io/israfel/pen/eEbWWG