Full article with more generic rules: https://css-tricks.com/responsive-layouts-fewer-media-queries/
Here is an idea using max(0px, (400px - 100vw)*1000)
inside flex-basis. This formula will eiter give 0px
if 100vw
(screen size) is bigger than 400px
or a very big value in the opposite case giving each element a big flex-basis
and create a wrapping. Simply adjust the 400px
which play the role of @media (max-width:400px)
.container {
display:flex;
flex-wrap:wrap;
}
.container div {
height:100px;
border:2px solid;
background:red;
flex-basis:max(0px, (400px - 100vw)*1000);
flex-grow:1;
}
<div class="container">
<div></div>
<div></div>
<div></div>
</div>
Using CSS grid it can be like below:
.container {
display:grid;
grid-template-columns:repeat(auto-fill,minmax(clamp(30%, (400px - 100vw)*1000, 100%),1fr));
grid-gap:5px;
}
.container div {
height:100px;
border:2px solid;
background:red;
}
<div class="container">
<div></div>
<div></div>
<div></div>
</div>
A similar question where I am controling the maximum number of columns without media query: CSS grid – maximum number of columns without media queries
We can scale the above solution to consider more complex cases.
Example of moving from 6 to 3 to 1 column:
.container {
display:grid;
grid-template-columns:
repeat(auto-fill,
minmax(clamp(clamp(15%,(800px - 100vw)*1000, 30%), (400px - 100vw)*1000, 100%)
/* if(screen> 800px) 15% elseif(screen> 400px) 30% else 100% */
,1fr));
grid-gap:5px;
}
.container div {
height:100px;
border:2px solid;
background:red;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
To understand the values consider the following ranges:
100%/7 100%/6 100%/5 100%/4 100%/3 100%/2 100%/1
14.3% 16.7% 20% 25% 33.3% 50% 100%
To get 6 columns we need a value in the range ]14.3% 16.7%]
(I considered 15%
)
To get 3 columns we need a value in the range ]25% 33.3%]
(I considered 30%
)
We simply avoid the edges to make sure we account for the gaps.
A more generic solution using CSS variables where I will add 0.1%
to make sure the value is big enough to get the needed number of column and it can hold the gap.
Let’s also add some dynamic coloration (related: How to change the color of <div> Element depending on its height or width?)
.container {
/* first breakpoint*/
--w1:800px;
--n1:6;
/* second breakpoint*/
--w2:400px;
--n2:3;
display:grid;
grid-template-columns:
repeat(auto-fill,
minmax(clamp(clamp(100%/(var(--n1) + 1) + 0.1%, (var(--w1) - 100vw)*1000,
100%/(var(--n2) + 1) + 0.1%), (var(--w2) - 100vw)*1000,
100%), 1fr));
grid-gap:5px;
margin:10px 0;
}
.container div {
height:100px;
border:2px solid;
background:
linear-gradient(blue 0 0) 0 /1% calc(var(--w2) - 100vw),
linear-gradient(green 0 0) 0 /1% calc(var(--w1) - 100vw),
red;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="container" style="--w1:900px;--n1:8;--w2:500px;--n2:4;grid-gap:10px;">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="container" style="--w1:600px;--n1:4;--n2:2;grid-gap:2vw;">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
Using flexbox where we can have a different (probably wanted) behavior where the last item of a row will take all the free space:
.container {
/* first breakpoint*/
--w1:800px;
--n1:6;
/* second breakpoint*/
--w2:400px;
--n2:3;
display:flex;
flex-wrap:wrap;
margin:10px 0;
}
.container div {
height:100px;
border:2px solid;
margin:5px;
flex-basis:clamp(clamp(100%/(var(--n1) + 1) + 0.1% ,(var(--w1) - 100vw)*1000,
100%/(var(--n2) + 1) + 0.1%),(var(--w2) - 100vw)*1000,
100%);
flex-grow:1;
box-sizing:border-box;
background:
linear-gradient(blue 0 0) 0 /1% calc(var(--w2) - 100vw),
linear-gradient(green 0 0) 0 /1% calc(var(--w1) - 100vw),
red;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="container" style="--w1:900px;--n1:8;--w2:500px;--n2:4;">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="container" style="--w1:600px;--n1:4;--n2:2;">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>