DEV Community

Damon Muma
Damon Muma

Posted on

My favourite line of CSS

Hey folks.

This is my favourite line of CSS:

  grid-template-columns: repeat( auto-fill, minmax(min(calc(180px + 12vmin), 100%), 1fr));

Here's what it does:

Not a big deal, eh? just a bunch of squares. But try resizing the codepen window like a weirdo and see how they all just fit! Oooooh.

Here's why I like it:

It (along with a lil display: grid) is a fully responsive grid written with no media queries that keeps a good amount of content on screen for everyone no matter their screen size.

The design goal solved here is basically: "I want all these things to be about yay big, but I want them to tile evenly into a row, and I want them to get a little smaller as there's less room on the screen".

It's to my brain a simple need but the mathy reality of it is pretty complicated. I really like that I can express it with one line of CSS.

There's a lot of cool stuff in this one line, so let's take it apart to let it shine.

Vmin?

The black sheep/vermin of the css unit family, but, vmin is, in fact, the bomb, diggity.

1% of the smaller of the height or width of the viewport

Because here's the problem with sizing everything based on the width of the viewport:

A large horizontal rectangle with barely any of a large square fitting inside of it. The rest falls off the bottom.

Most people do it this way, and it's why the landscape view of a mobile website is usually a bit garbage. Don't forget to be responsive when you're being responsive!

I'm not saying always use vmin, but it does elegantly allow you to consider tall narrow windows and short wide windows as similarly restricted space-wise, which we usually forget to do on the internet.

Another cool thing you try at home: a vmean unit: calc({n/2}vh + {n/2}vw). This gives you 1% of the average of the viewport height + width — the overall amount of screen space available (This is actually cooler than vmin, but I mainly want to rant about height queries so I'm just tucking it in here.)

calc(vsomething + pixies)?

The above assumes you're doing some 'responsive scaling' of an object in order to make best use of the screen real estate. Combining a base px or em size with a percentage of the viewport allows you to make things smoothly scale up as the window gets bigger (and just got super snazzy with clamp().

This is often used with font-size to quickly achieve slightly bigger text on bigger screens that have room for it. Here's a great overview from a couple days ago

How do you choose how many of each unit to use? The higher the v*, the more it will scale with the screen. Other than that I do some real sloppy head math as a starting point, then try different values and drag the corner of my screen around all over the place like a weirdo until it looks right. Do you have a better way?

(🔥 hot tip: compared to copy, give headings more of the v-units so they scale more dramatically as the screen size changes)

min() ?

Min (along with his friend Max Clamp) is new but very handy. (I also edited this article to add it when I realized that it does work inside minmax, and the trick is just not to have syntax errors 🤦‍♂️).

The trick with minmax is that it favors the minimum, so if your value is wider than the screen (say if you want to base it on 400px, but your container is 300px wide) it will stretch outside its bounds.

The same image of squares from before, but rotated so that the inner square is escaping out the side of the outer square

This is a weird decision to me—I never want something to stretch outside its container—but you would have to choose one of min or max to win in a fight and The CSS Lobby chose minimum.

the min() function allows us to request the smallest of two values. Inside minmax feels redundant, but it will let you make sure the element never gets too big for its britches, hence minmax( min(calc(180px + 12vmin), 100%), 1fr) (the result of the calc but not more than the size of the container).

Great writeup on this here.

This part is honestly pretty weird and needing it almost makes this not my favourite line of CSS anymore (you don't need it if your base size is small enough. Technically we don't need it here, but it's an important feature to know if you wanna try this at home).

repeat ( auto-fill ( minmax ( ?

There are probably a bunch of blog posts about this one already. To me it was kinda the most exciting part of grid: not needing to mess around with media queries to just put em in a row and let em wrap when they ought to.

Usually they tell you:

repeat(auto-fill, minmax(300px, 1fr))

It makes the thing be at least 300px but stretches it out to fill the rest of the row.

Which is pretty cool. But cmon that responsive scaling just dopens it up that extra bit doesn't it? Bigger screens want bigger stuff!

The old ways

(a.k.a. if you still need to support IE11 😟)

So you could also still do

.tile {
  width: 100%;
}

@media screen and (min-width: 620px){
  width: 50%;
}

@media screen and (min-width: 920px){
  width: calc(100% / 3);
}

@media screen and (min-width: 1150px){
  width: calc(25%);
}

(continued up to 4 more times depending on what sizes we're dealing with)

Or you could do

<div class="container">
  <div class="row">
    <div class="tile col-sm-6 col-md-4 col-lg-3">
      ...
    </div>
  </div>
</div>

But they have their own problems

  • You have to define potentially arbitrary breakpoints, or arbitrarily use your already existing ones.
  • You would have to buy into the idea of a 12 column grid system even if you don't want to. (Which also means you can only have a number of items per row that is divisible by 12)
  • Basically, you have to fill your brain with a lot of stuff that isn't "I want em to fit, and be about this size".

My fav line of css is a bit intense (4 nested functions??) but look at it again:

  grid-template-columns: repeat( auto-fill, minmax(min(calc(180px + 12vmin), 100%), 1fr));

A bit of a mouthful, but it represents the actual task it's solving a lot more directly than the other methods. I know we take grids for granted and many of us live and breathe dividing things into 12, but the fact that you go "this is 6" when you want to have 2 things per row has always felt unnecessarily circuitous to me.

In the wild

Peruse my real-world usecase if you want.

What's missing?

This is great, but I still lament some things about laying things out in CSS Grid that I couldn't figure out a way to do here:

  1. I want to have grid-lines between items instead of just gap, and you kinda just can't do that (you'll see this not really working on the codepen).
  2. I want to be able for the last line's items to be centered instead of left or right aligned, and you kinda just can't do that.

Let me know if there's a way to do those things and thanks for dropping by!

And since we can nest declarations 4 functions deep in CSS now, is it time to introduce a pipe operator? Sorry wrong link try again. Pipe operator

Top comments (12)

Collapse
 
thecodepixi profile image
Emmy | Pixi

I love this and I love that you explain how it works.

Collapse
 
thedamon profile image
Damon Muma

Thanks for taking the time to check out, Emily. I'm glad you found it valuable!

Collapse
 
bayuangora profile image
Bayu Angora • Edited

What's pros and cons compared to general grid? Because grid template columns with fr fr fr value is repeatable too?

Collapse
 
thedamon profile image
Damon Muma

This is grid (one of its many possible configurations at least). I should have called out the needed accompanying ‘display: grid’ (it’s hidden in the codepen)

Collapse
 
bayuangora profile image
Bayu Angora

Oh, I see. By the way, using var on grid (and another style value) can't be rendered by Opera Mini with extreme mode, isn't it?

Thread Thread
 
thedamon profile image
Damon Muma

min() is quite new and only in evergreen browsers.
Grid-auto-columns is not in IE but is in Opera Mobile. To be honest I’ve never tested in opera mini, but this could degrade pretty gracefully with a simpler fallback grid.

Collapse
 
ooloth profile image
Michael Uloth

This is great! It never occurred to me to use a min() inside minmax(). Super useful.

Collapse
 
dillonheadley profile image
Dillon Headley

Doesn’t justify-items and/or justify-content : center help with the last line thing?

Collapse
 
thedamon profile image
Damon Muma

They would in a flex layout I think! Within grid, those properties seem to align the items/content within their existing row or column, but not affect the placement of the items themselves.. in a way it makes sense, though, since a grid is.. well, a grid—so the columns and rows are continuous throughout the entire grid

Collapse
 
dillonheadley profile image
Dillon Headley

Ah yes you are right. I have come across similar situations where what I need is some kind of blend of flex and grid

Thread Thread
 
thedamon profile image
Damon Muma

Yeah often what feels like grid ends up being better off flex. I might mess around A bit and see what the closest flex version of this I can come up with

Collapse
 
vagoel profile image
Varun

Super cool.