Skip to content

Instantly share code, notes, and snippets.

@Heydon
Created November 28, 2015 11:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Heydon/743d356f670bd3658457 to your computer and use it in GitHub Desktop.
Save Heydon/743d356f670bd3658457 to your computer and use it in GitHub Desktop.

Flexbox Grid Exploits

Flexbox — not to be confused with Sex Box, the British TV show wherein Mariella Frostrup interviews people who’ve just had sex in a box — is the CSS layout toolkit de rigueur. Of all the celebrated features of Flexbox, it is the light work it makes of producing wrappable grids, tolerant of dynamic content, that I think's integral.

In this article, I'll cover a few techniques to exploit Flexbox's internal algorithms and design finessed grids intended for changing quantities and dimensions of content.

Basic wrapping

.parent {
	display: flex;
	flex-flow: row wrap;
}

.child {
	flex: 1 0 25%;
}

I've made the .parent a flex container and used the flex-flow shorthand to set the flex-direction to row (i.e. following the horizontal axis) and enabled wrapping. Wrapping operates according to the flex-basis set on children; in this case 25%.

100 divided by 25 is 4, meaning what we have here is a 4 column grid. Simple stuff, I know. With wrapping on, a new row is begun every time you exceed 4 additional children. The last row is always complete, either because the total is exactly divisible by 4, or because the left over children are "grown" to share a row's width. The "1" in flex: 1 0 25% essentially means the ability for children to grow is set to on.

[illustration]

The upshot is that you can employ a grid which "tidies" itself, distributing children automatically. This is powerful stuff. I can be assured that no matter the number of children currently included, my layout will be acceptable.

Element queries

I'm not the first (I think Zoe Gillenwater pointed it out) to notice that Flexbox can be made to employ something akin to "element queries"; changes in an element's layout based on that element's own dimensions. By incorporating a min-width into the last example, I can trigger elements to grow at this "breakpoint".

.parent {
	display: flex;
	flex-flow: row wrap;
}

.child {
	flex: 1 0 25%;
	min-width: 300px;
}

I have made my grid entirely responsive with just one additional declaration. The number of columns is predicated on the simple axiom that no one column (element) can be fewer than 300px in width. Flexbox's grow takes care of expanding children that hit this minimum width, making sure they never get any narrower than this setting. Wrapping takes care of everything else.

[illustration]

Dealing with remainders of 1

If I have a 4 column grid with 8 children present then I add a child element, that element will constitute the whole of the bottom row. Ideally, I'd like to move things around so that this is not the case. By harnessing the ability of my elements to grow and incorporating nome nth-child magic, I can essentially borrow elements from the penultimate row to distribute the elements towards the end of the grid more reasonably. I can also do this without negatively affecting other quantities of elements producing more than a single remainder or no remainder at all.

In the following example, I've adapted the first example in this article.

.parent {
	display: flex;
	flex-flow: row wrap;
}

.child {
	flex: 1 0 25%;
}

.child:nth-last-child(2):nth-child(4n) {
  min-width: 33%;
}

This selector expression in the last block targets any element that falls in the fourth and final column (4n) which is simultaneously the penultimate element -- that is, the element before the long, single remainder. By bumping this element's width to 33%, it's forced down into the final line, leaving the penultimate line with just three elements.

The result is the elimination of the single element and a dynamic grid that resolves into a line of 4, then 3, then 2 children when there is a single remainder. No matter how many child elements are present, the grid never ends with a single element row.

[illustration]

Try adding and removing items in this codePen demo and experimenting with different numbers of columns. The basic formula for the selector is .child:nth-last-child(2):nth-child([number of columns]n). The width you set has to be somewhere between the base width and the base width for the grid if it had one less column. So, if there are five columns, the width set in this override should be between 20% and 25%.

Controlled chaos

In the last example, I singled out a child element based on its index using the algebraic :nth-child and nth-last-child. Because of my Flexbox configuration's insistence of filling the available space according to its element growth and wrapping features, I could do this safe in the knowledge that I would not produce an incomplete, gap-ridden grid.

Based on this principle, I can arbitrarily change the widths of any grid children I like. I can get quite expressive with this and build in some algorithmic asymmetry.

.child:nth-child(3n) {
  width: 33.333%;
}

.child:nth-child(5n) {
  width: 50%;
}

.child:nth-child(7n) {
  width: 66.666%;
}

http://codepen.io/heydon/pen/GpbQdP

By using prime numbers (3, 5 and 7) to augment the child elements' width at intervals, any perceived regularity in the layout can be easily diminished. However, the layout never breaks as such thanks to our go-to wrapping and growth settings. Be sure to try out the codePen demo for this one and experiment with different, superimposed nth-child intervals.

Conclusion

I hope that this short article has given you something to think about regarding the way Flexbox handles and tolerates dynamic content, allowing you to tersely code robust yet expressive layouts. With Flexbox, for the first time, we're afforded something akin to true grid systems; grids which govern themselves, freeing us to focus on content creation and aesthetics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment