# A CSS3 Responsive Grid you can Use Today

**Alternate Titles: Why CSS3 Selectors are Awesome** or **Counting Elements in CSS3** or **Faking Flexbox** or **CSS3 witchcraft**

# Intro

CSS3 selectors are just plain awesome. With the new selectors and a little critical thinking, there's so much you can do. Take for example the oh-so-popular dynamic grid. There are many ways to achieve grid layouts, some of the up and coming best practices include the CSS Grid specification and Flexbox. However neither grid nor flexbox layouts have enough browser support for many companies. So what are we to do?

How about using CSS3 selectors to count our cells and then style them appropriately. Here's an example:

# Counting Cells with CSS???

That's right. Thanks to CSS3's :nth-child() family of selectors (which have pretty good adoption) we can count exactly how many children a container has. In it's most basic form, that would look something like:

` ````
.grid-element:nth-child(3):last-child
{
/* The third element is also the last. That means there are 3 elements. */
}
```

This is a good start, but it's too specific. This rule counts if there are 3 and excactly 3 elements. The rule also can *only* be used to style the last element in the grid. We'll deal with this last problem first

# Hi I'm DIV this is my brother DIV and that's my other brother DIV

Enter the General Sibling Selector (~). This selector, as the name indicates, lets us style the siblings of an element. Given the nature of CSS however, it only styles siblings that come after the element that matches the preceding selector. That means if we tacked it onto our previous rule to get something like:

` ````
.grid-element:nth-child(3):last-child ~ .grid-element`
```

**Nothing would happen** since the first part of that selector has already matched the last element, and it has no siblings that follow it.

## Counting Backwards

To fix this problem and help the general sibling selector to do it's job we need to match the *first* of the 3 grid elements. We can do this by counting backwards so-to-speak. If we make our rule look like:

` ````
.grid-element:first-child:nth-last-child(3)
{
/* If the first element is also the third from last element, then there are three elements*/
}
```

What we've been able to do now is write a rule that still counts elements, but gives us a match to the first element in the grid. That means we can now use the sibling selector to expand the rule to all other grid elements.

` ````
.grid-element:first-child:nth-last-child(3), /* This will match the first element when there are 3 */
.grid-element:first-child:nth-last-child(3) ~ .grid-element /* This matches all the elements following the first when there are 3 */
{
width: 33.33%; /* We have a grid with 3 elements, set width to 33% */
}
```

So now we can count the number of elements in a grid, and select all of the grid elements for styling. But does that mean that we're stuck writing as many rules as there are elements? That's not very flexible.

# Generalizing All The Things

When making a grid, we don't actually care how many elements the grid has, but rather how many columns it should be presented in. So can we rework our cell-counting rules to pick an optimal number of columns based on the number of elements?

## The N in :nth-Child()

Thanks to the :nth-child selector's ability to select every N objects we can not only count the total number of elements, but also determine if the number of elements is *divisible* by a given factor. Let's take our CSS rule from above and expand it to determine if the elements are best split into 2 or 3 columns.

` ````
.grid-element:first-child:last-child
{
/* There is only one element */
width: 100%:
}
.grid-element:first-child:nth-last-child(2n), /* The number of elements is divisible by 2 */
.grid-element:first-child:nth-last-child(2n) ~ .grid-element
{
/* Use a 2 column grid since the number of elements is divisible by 2 */
width: 50%;
}
.grid-element:first-child:nth-last-child(3n), /* The number of elements is divisible by 3 */
.grid-element:first-child:nth-last-child(3n) ~ .grid-element
{
/* Use a 3 column grid since the number of elements is divisible by 3 */
width: 33.33%;
}
```

Now we can style the elements as a 1, 2 or 3 column grid depending on how they split up most efficiently. And it only took 3 rules! But there's a problem. Not every number is divisible by 2 or 3. For example 5, 7, 11, and 13 cannot be split into 2 or 3 columns evenly.

## Fighting the Primes

The easiest way to deal with these numbers is to just use an exception to our divisible by 2 rule. Any number of elements that isn't divisible by 2 will have exactly one too many elements. I don't know a better way to word that, but here's what I mean: 5 can't be evenly divided by 2, but 5-1=4 and 4 can. The same goes for 7, 11, 13, 17, etc etc. With that mathematical principle in mind we can attack all of our "prime" numbers in one fell swoop. Namely these 2 rules:

` ````
.grid-element:first-child:nth-last-child(2n+1), /* The number of elements is one too many to be divisible by 2 */
.grid-element:first-child:nth-last-child(2n+1) ~ .grid-element
{
/* Use a 2 column grid for most of the elements */
width: 50%;
}
.grid-element:first-child:nth-last-child(2n+1) ~ .grid-element:last-child {
/* This is our "leftover" element so make it 2 columns wide */
width: 100%;
}
```

With two more rules, a total of 5, we have now created a 3 column grid that can accomodate any number of elements.

# Outro

Using nothing but widely adopted CSS3 selectors and 5 rules we've been able to create a responsive grid that will dynamically resize it's elements to fill the available width and have 1-3 columns. The rules described in the article still leave a little bit to be desired however. It's left as an exercise for the reader to try the following:

- Place(or change) the 2n+1 rules in the stylesheet so they don't conflict with the (3n) rule (see pen above)
- Never orphan an element on a row by itself. e.g. If there are 7 elements split them into 2,2,3, not 2,2,2,1 or 3,3,1 columns. (see pen above)
- Change the rules to use the minimal number of rows. e.g. For 5 elements don't split into 2,2,1 but rather 3,2 (see pen above)
- Try reversing the logic to put the wider elements at the top
- Expand the rules to cover 4 or 5 column grids

Super interesting. I've been following Heydon Pickering on these counting queries. I just haven't needed them yet. I like this grid implementation though.

Love it! This approach makes loads of sense for all sorts of things.

@brownerd - I'm glad I'm in good company when it comes to using nth-child selectors this way.

@markseifert - If you figure out any other cool things to do with this I'd love to hear about it.

This deserves more kudos, this is awesome. Has anyone already tried the excercises?

Glad you like it @joranovski. I have a few more ideas I'd like to expand this with in addition to the ones I listed above (like multi-column width elements)

@TBernard is it inspired by the Quantity Queries?

Not directly @joranovski, this was an expansion of a pen I first did about a year ago. I like to think that I independently discovered this technique, but I read so much about CSS tips and techniques it's possible I picked it up somewhere and just forgot where.

Nice article! Thanks! You can use :only-child selector instead of first-child:last-child

@inliner good catch. I didn't know there was an :only-child selector.