Flexblocks, a CSS Library

The 12 column grid system is the most popular grid used in websites today. Classes between col-1 and col-12 are used in a row to form columns of content. Gutters run between columns to slightly separate them.

This 12 column model may work well, but it was designed around the old limitations of CSS. We now have flexbox! Flexbox-based grid systems already exist, but I’ve found that they often are only a small upgrade over old 12-column grid systems. I think it’s time to try something different.

Flexblocks (yes, blocks) is a new CSS layout library. It likely still has kinks to be ironed out, but I’ve successfully used it for almost a year on numerous real-world commercial sites. It’s about 800 bytes gzipped, incredibly easy to learn, vastly simplifies how I design websites.

If you’re just interested in using Flexblocks, check out the readme, but if you’re interested in why I’m creating yet another CSS framework, read on.

Why is CSS so difficult?

My friends frequently complain about CSS, but they’re never complaining about how background-color or border-radius is impossible to understand. People complain mostly about one thing — positioning elements is difficult and bug-ridden. (This is why grid systems exist.) I think this positioning problem breaks down into two sub-problems: alignment and margin. Let’s talk about these two problems, and how I attempt to fix them with Flexblocks.

Aligning Elements is Difficult

CSS beginners have no idea how to use float to create columns, how to vertically center elements, or how absolute positioning works. This is understandable — although these are the core building blocks of layout, they’re not well documented, the techniques are filled with obnoxious corner cases, and the syntax is inane. Before flexbox, I’d frequently do something like this to vertically align:

How is a beginner supposed to know this? CSS documentation isn’t going to highlight this technique, so the only way they’ll find out is by Googling it, and hoping whatever Stack Overflow post they find works in their particular instance. Hopefully eventually they’ll learn why this works, but still, this is gross.

Flexbox does a lot to reduce the number of hacks needed to do basic layout, but there is still a lot of syntax for a beginner to get past. To vertically align with flexbox (ignoring vendor prefixes):

.parent{display:flex;align-items:center;justify-content:center;}

Sure, it’s a little less code, and if you understand the concepts of align-items and justify-content, it’s much more straightforward. However, if a beginner wanted to modify this to align to the bottom instead of the center, what would they do? In the first example, they could probably (correctly) guess to set vertical-align to bottom, but with flexbox, do they switch align-items or justify-content to bottom? Trick question — the word bottom doesn’t exist in flexbox.1 They’d need to switch align-items to flex-end. If they wanted to align right, they’d need to switch justify-content to flex-end. In the first case, flex-end means the bottom, but in the second, it means right. Not exactly the most intuitive.

So, the syntax for aligning items within their parents is difficult. How can we fix this? For inspiration, let’s take a look at a tool that everybody is familiar with, the humble word processor.

A screenshot from Pages

Align left, center, right, or justify. Align vertically top, middle, or bottom. Everybody is familiar with word processors. Flexblocks reflects this same system, which (hopefully) makes it more immediately understandable than terms like flex-start.2 For instance, to replicate the Pages screenshot above with Flexblocks, we simply write this:

<divclass="middle right"><div>Text</div></div>

Easy, simple, and if the user decides they want to align to the bottom instead of the right, changing middle to bottom is obvious.

Margins are Difficult

Although it seems like second nature to those familiar with CSS, margin overflow (when an element with no padding has a child with margins) and margin overlap (when the margins of two siblings overlap) are obnoxious to deal with and debug. Overflow and overlap also make building pixel-perfect styles across a large site difficult, since an element with margin behaves differently depending on which elements appear next to it. I’ve found my components that use margin often need situation-specific code to make it look right.

I also often see excess space at the bottom of lists like this:

Every link in the list has margin-bottom to space it from the next link, but nothing comes after the last link, so the margin just extends into empty space:

There are a couple common solutions to this, some hackier than others. We could use :last-child to remove margin from just the last element, reduce the padding-bottom of the parent to make the sides visually the same, or add negative margins to the parent. All of these require extra case-specific code, and due to the subtle nature of the bug, it will be frequently missed. Even if the bug is found in one place, the fix may not work in every instance across a large site.

To solve these margin problems, I propose a simple rule that avoids the whole mess: don’t use margins.

If you want to use margin to space items apart, just use a Flexblocks gap class. Flexblocks has five classes, gap-1 through gap-5. Apply one to a col or row to add spacing between its children. Internally, Flexblocks uses margins to make the gap classes work properly, but it is designed to automatically avoid overlapping, overflowing, and adding margin before the first element or after the last.

If you’re thinking of using margin to center items, you can easily use the center class described above.

“No margins” is an odd rule to have, but I’ve found that 95% of the times I seem to need margin, I can more cleanly use either a gap class or padding instead. Padding is not difficult. Compared with the complexities of margin, padding is easy to use perfectly. It never overlaps, it never overflows, and since it’s applied inward, you don’t have the last-element problem like with margin. I also find I enjoy specifying the margin on the parent instead of the items inside. This system also encourages uniform spacing between elements, especially when there are a number of different items in the same list, which helps prevent sloppy-looking designs.3

Why Flexblocks?

In particular, why use Flexblocks instead of Bootstrap? Bootstrap is a very different project, designed to allow beginners to rapidly create interfaces, whereas Flexblocks is a lightweight layout base that you can build your own components on top of. If you prefer styling things yourself, this is difficult with Bootstrap, since there are a ton of styles you must overwrite. Flexblocks is smaller, there’s less to learn, there’s nothing to overwrite, yet it still solves the positioning issues that frustrate beginners, while leaving the less frustrating decisions like colors and borders up to the user. Also, since Bootstrap is difficult to overwrite, it teaches you less about CSS. With Flexblocks, all the classes correspond to simple, understandable CSS, so it’s easy to transition your site away from Flexblocks if you decide to do so.

Another apt question is why not use just raw flexbox? Raw flexbox is very powerful, and there are things you can do with it that are impossible with Flexblocks, but the syntax isn’t immediately obvious for beginners in the same way Flexblock’s is. Even with experienced front-end developers, over time in a long project, margins will become imperfect, and there will be layout problems that will require an increasing number of custom classes. By aiming to make layout drop-dead simple, and separating the styling of an element from its positioning, Flexblocks helps fight that creep.

Bootstrap makes websites look good by default, at the expense of your website looking like everybody else’s. With Flexblocks, I’m attempting to make a just-layout system that makes layouts look good by default, and let you determine the styling yourself. I hope you enjoy, or at least have some interesting thoughts as a result of my little experiment.

Flexblocks is available on Github under the MIT license. I’d be excited to hear any questions or thoughts you have about it — feel free to tweet at me. If you’re using Flexblocks and confused with how to do something, that is a bug, and I’d love to know.

This makes sense for flexbox, since flexboxes can be rows or columns, and must support right-to-left text, but for users getting started with most languages, I think this is confusing. ↩

This is a trade-off. flex-start is a more accurate name, since in a right-to-left language it would be on the right, no the left. It also would be inaccurate with reverse rows and reverse columns, although users would have to create these manually, since we don’t provide any way to create them. Flexblocks is filled with these trade-offs, but I like to think (and hope) that we’re using 30% of the mental overhead to cover 90% of the use-cases. ↩

There is one caveat — if the first element is hidden with display: none, there will be extra margin at the top. However, you’ll notice that Flexblocks puts this error at the top of the element, making the problem more prominent than space at the bottom, and less likely to be shipped unnoticed. There are also small performance hits, since it uses a universal child selector, but it’s not a descendant selector, and I think the performance hit will be minimal. ↩