I was recently asked is it possible to select every element in the last row of a grid containing an arbitrary number of items using CSS selectors? Not wanting to shy away from a challenge, I started hacking and found a solution which I’ve written up along with a few other techniques for targeting elements in the first or last row of a grid.

View the demo

Throughout this post I’ll be using the terms “balanced grid” and “unbalanced grid”. So we’re clear, a balanced grid has content in every grid cell and an unbalanced grid doesn’t have enough content to fill every cell, resulting in whitespace in the last row.

balance-unbalanced
Example of a balanced (left) and unbalanced (right) grid

For this post I’ll be working with the follow test markup. These techniques are very flexible and can be adapted to work with any markup that uses sibling elements to create a grid.

<ul class="grid-3">
   <li>Grid item 1</li>
   <li>Grid item 2</li>
   ...
   <li>Grid item 14</li>
   <li>Grid item 15</li>
</ul>

Styling the first row of a grid

Targeting elements in the first row of a grid

Targeting elements in the first row of a grid is relatively simple. It doesn’t matter if the grid is balanced or unbalanced, the same solution applies to both cases. We need a selector that will only target the first x elements, where x is the number of columns in the grid. We can do that with the :nth-child pseudo-class:

li:nth-child(-n+x) {
  /* Add style rules */
}

For a 3 column grid:

li:nth-child(-n+3) {
    background-color: red;
}

For a 5 column grid:

li:nth-child(-n+5) {
    background-color: green;
}

For a 12 column grid:

li:nth-child(-n+12) {
    background-color: blue;
}

Styling the last row of a balanced grid

Targeting elements in the last row of a balanced grid

Targeting elements in the last row of a grid is simple if the grid is balanced. The same principles used to target the first row are used here except we’ll use the :nth-last-child pseudo-class to target the last x elements in the grid. Again, we’re substituting x with number of columns in the grid.

li:nth-last-child(-n+x) {
  /* Add style rules */
}

Last row of a balanced 3 column grid:

li:nth-last-child(-n+3) {
    background-color: red;
}

Last row of a balanced 5 column grid:

li:nth-last-child(-n+5) {
    background-color: green;
}

Last row of a balanced 12 column grid:

li:nth-last-child(-n+12) {
    background-color: blue;
}

Last row of a balanced or unbalanced grid

Targeting elements in the last row of an unbalanced grid

Styling elements in the last row is a little more tricky if the grid is unbalanced. Unlike the selector used for a balanced grid, we can’t just target the last xth elements and style them. What if the grid has 5 columns with only 3 elements in the last row? – we would target the last 2 elements in the previous row too.

To style the last row of a grid we’re going to use the following rule, again, substituting x with number of columns in the grid.

li:nth-child(Xn+1):nth-last-child(-n+X),
  li:nth-child(Xn+1):nth-last-child(-n+X) ~ li {
    /* Add style rules */
}

The :nth-child(Xn+1) pseudo-class will target every xth element in the grid, which will be the first item in each row. The :nth-last-child(-n+X) pseudo-class will target the last x elements in the grid. Combining these pseudo-classes will only target elements that match both, which in our case is the first element in the last row of the grid.

To select all elements in the last row we add a general sibling combinator ~ to the previous selector so it targets everything after the first element in the last row.

Last row of a balanced or unbalanced 3 column grid:

li:nth-child(3n+1):nth-last-child(-n+3),
  li:nth-child(3n+1):nth-last-child(-n+3) ~ li {
    background-color: red;
}

Last row of a balanced or unbalanced 5 column grid:

li:nth-child(5n+1):nth-last-child(-n+5),
  li:nth-child(5n+1):nth-last-child(-n+5) ~ li {
    background-color: green;
}

Last row of a balanced or unbalanced 12 column grid:

li:nth-child(12n+1):nth-last-child(-n+12),
  li:nth-child(12n+1):nth-last-child(-n+12) ~ li {
    background-color: blue;
}

If the grid will always have two or more rows, or if you want to completely ignore single row grids, a simpler selector can be used. This selector will fail to match the first item in a grid with a single row. To use it, substitute x with the number of columns in the grid and y with the number of columns in the grid +1:

li:nth-child(Xn):nth-last-child(-n+Y) ~ li {
  /* Add style rules */
}

Last row of a balanced or unbalanced 3 column grid with more than one row:

li:nth-child(3n):nth-last-child(-n+4) ~ li {
    background-color: red;
}

Last row of a balanced or unbalanced 5 column grid with more than one row:

li:nth-child(5n):nth-last-child(-n+6) ~ li {
    background-color: green;
}

Last row of a balanced or unbalanced 12 column grid with more than one row:

li:nth-child(12n):nth-last-child(-n+13) ~ li {
    background-color: green;
}

The end

I hope you found this useful.

Comments

  • Leon Zoutewelle

    Why don't you use the :last-child? Now i can't see if your list items go from top to bottom or left to right but this makes it alot easier.

    Also why do you use a list for a grid? I can't figure out why.

    • Keith Clark

      :last-child would only select the very last element, the purpose of this is to select all elements in the last row of a grid.

      I'm using a <ul> list because this solution was originally developed for displaying a grid of products and portfolio items.

    • Leon Zoutewelle

      So if im correct your using one ul and repeat the li. Well that makes things alot more clear.

  • George Anderson

    WOW - How did you manage to sort that one out. Well done and thanks for letting us see it.

    Regards George