Looking for a quick way to roll your own responsive CSS Grid? Look no further. This guide provides two simple ways to create them, no frameworks required; only CSS.
For completeness, there are examples with CSS nesting, and without.
With media queries
Start by creating the HTML:
You need what's known in the trade as a grid container, my grid container is this:
The children contained within the grid container are known as grid items.
You can name them anything you like, the CSS is not dependent on the names.
Now write the initial CSS:
Unless you specify
grid-template-columns the grid items will be stacked on top of each other:
The best approach is mobile-first, so let's utilise this default behaviour where all the columns are 100% of the viewport width, and add a
min-width: 510px media query where it makes sense.
By doing this, we tell the browser that if the device's screen is bigger than
510px to change the number of columns.
Here's the end result:
To add another media query, just repeat this step, but remember that it's good practice to keep media queries in cascade order (top to bottom).
I nested the media queries, if you don't want to use nested CSS you simply wrap each declaration in a
@media rule, like so:
If you want to add images, checkout this example: Images in a 12-column grid
If media queries are not for you, there's another option;
it's a combination of CSS Grid,
repeat() CSS function and the
Take the HTML from the first step, and add the following CSS:
What you get is a solution with no media queries, which means less code, and it's completely up to the browser to decide when to change things.
Note the value I used is
231px, does it seem random? It's not, it's actually the width of the column when using the media query
min-width: 510px minus the padding on the body and the grid gap, e.g.
(1rem * 2 + 1rem + 510px) / 2)
This solution works very well with container queries, and that brings up a really important problem that I want to highlight.
There's a potential bug in this code
There are a lot of articles on the topic of using
minmax() that claim to provide a responsive solution,
but they're all somewhat flawed.
The bug is to do with fluidity and overflow,
as long as you never go below the minimum value used in the
which in the previous example is
231px, you'll never see it.
That's a pretty safe bet
if you're using this a drop-in replacement for media queries,
They seem to use a low number like
240px because of this reason,
they assume that the smallest screens are
and unless you're building a responsive layout for a watch, I agree.
But let's be honest about calling it what it is, a solution, and not ignoring the fact that these examples are not 100% fully responsive and turning a blind eye. If you go below the lowest value, the content will overflow:
I was never happy knowing that this kind of solution could be discovered by a user, or god forbid, a tester.
The one thing they're all missing is this:
In conjunction with
min(100%, 231px) tells the browser to pick the lowest value, which is either
231px, if you go below
100% is used, which makes things fluid again.
Not only is this solution complete, it also works with container queries.
There are advantages and disadvantages to either approach, with media queries you have total control of the breakpoints, and you won't have to get your calculator out to determine the width of the grid-items.
auto-fill gives a tremendous amount of flexibility and in most cases is an ideal pairing with
If you're using
auto-fill as a drop-in replacement for
@media, just use a media query, they do different things.
If you have any suggestions as to how the examples can be made clearer, easier to understand, or how I can add any missing use-cases you feel would help others, I'd love nothing more than to hear from you! Reach out to me on Twitter, or shoot me an email.
Written by Morgan Feeney
I’ve been designing and developing for almost 2 decades.
Read about me, and my work.
For juicy tips and exclusive content, subscribe to my FREE newsletter.