The almost sentient CSS grid system

I have been working with grids for a long time now, and there is one challenge that pops up in every project: how many items do you put on a given row. Think, for example, of a row of news or product teasers. You may decide to go for 3 teasers per row, evenly spaced, for a certain breakpoint and move it up to 4 teasers per row on bigger screens. "That'll do fine", you'll say and deliver it to the client. A few days later she calls you and says "Hey, I really love the layout, but on some pages it looks so empty. Especially the homepage." Umm, what? So you go and check it out and voila: the client only put two news items on the homepage and they fill only half the available space in your bigger breakpoint. Before you call her back and tell her to just write more content - or before you start writing some Javascript or server-side logic that counts the news items and adds/removes grid classes to adjust the layout - what if, what if it was possible to make the grid system a bit smarter and handle this with pure CSS?

I saw someone mention a clever technique of chaining different nth-child selectors to achieve a kind of "nth child of m siblings" selection logic. I played around with it this morning and here's what I got:

If you want to have three evenly spaced items in a row, you can target them like so:

.gs-column:nth-child(1):nth-last-child(3),
.gs-column:nth-child(1):nth-last-child(3) ~ .gs-column {
width: 33.333333%;
}

"Target the first child of three total children as well as its siblings."

Moving up to four and five evenly spaced items is easily done:

/* 4 Teasers */
.gs-column:nth-child(1):nth-last-child(4),
.gs-column:nth-child(1):nth-last-child(4) ~ .gs-column {
width: 25%;
}

/* 5 Teasers */
.gs-column:nth-child(1):nth-last-child(5),
.gs-column:nth-child(1):nth-last-child(5) ~ .gs-column {
width: 20%;
}

Obviously this is really specific, but you can both make it more generic and create more complex rules with only minor tweaks. Say you want to target groups of 5, 8, 11, 14, ... items so that the first two share a row and are both 50% wide while all other items fill out the following rows in threes:

.gs-column:first-child:nth-last-child(3n+5),
.gs-column:first-child:nth-last-child(3n+5) ~ .gs-column {
width: 50%;
}

.gs-column:first-child:nth-last-child(3n+5):nth-last-child(5) + .gs-column ~ .gs-column {
width: 33.333333%;
}

If you create similar rules for different total numbers, you will end up with pleasing layouts where all rows are filled out all the time. No more empty spaces, no more need for placeholders.

An almost sentient CSS grid system.

You can check it out and play around with it here: http://codepen.io/polarbirke/pen/NPpyGb

DISCLAIMER: This is just a cool CSS experiment to play around with, I wouldn't recommend to use it in production without lots of testing and thinking about fallback handling for older browsers.

Changelog

  • Oct 20, 2019 Split blog articles and bookmarks
Post a comment If you post a tweet with a link to this page, it will appear here as a webmention (updated daily).

Webmentions

1 likes
  1. liked by Stefan Judis