CSS and the path of least resistance

Web styling advances at a ferocious rate. Vanilla CSS is a rarity. Almost every web presence relies on new frameworks, preprocessors, and workflows. Yet even in the midst of progress, the fundamentals often trip up our work.

Our CSS fights against the natural DOM (Document Object Model) flow. The DOM flows from left to right, and from top to bottom. Block elements expand as wide as possible within a bounding container. Elements grow only as tall as absolutely necessary. The more we resist this flow, the more likely things break.

To avoid this, I follow three rules. Whenever my layout feels janky or otherwise hard to debug, it’s usually because I’ve strayed off course from these guidelines.

Use position and float strategically

Even total beginners understand how absolute positioning and floating can move a target element. Yet it’s easy to misunderstand how the elements around the target respond. For a float, containing elements may need a clearfix to keep their natural height. And non-floated elements will move around the floated element, occasionally in unpredictable ways. This is especially true with variable height content.

Absolute positioned elements can overlap or having weird spacing with nearby elements. And an absolute element’s declared position isn’t always obvious. It’s origin for x/y coordinates could the first surrounding container. Or it might be the entire viewport, or any container between these two extremes. It all depends on what surrounding elements have their position set to relative.

Granted, absolute positioning and floats still have their purpose. But ask yourself if there’s a less drastic option to achieve the same effect. For example, for a small “nudge”, don’t jump first to absolution positioning. Try some padding, margin, or a coordinate tweak (e.g. left, top) first.

Avoid brittle magic numbers

A magic number is an old programming term for a value that works, but is hard to understand why it was written. In the context of CSS, it feels arbitrary, a value that doesn’t sync with expected patterns in the code base.

For example, let’s say your code base has standardized padding in ratios of 10px and 20px. For one edge of an element you throw in 17px just to make things look “nice”. 17px is your magic number.

For code consistency and maintenance, you should generally avoid magic numbers. But I’m especially concerned over what I’d term “brittle” magic numbers. These are CSS properties that, without a precise magic value, can significantly alter or otherwise break a page’s layout.

Take the earlier example of padding-left: 17px. Let’s say it’s added to make text line up with a nearby image. It’s inconsistent, but if you were to remove that single property, the text block and layout remain intact. It’s a magic number with minimal damage.

But let’s say that padding-left property is to keep a column in horizontal alignment with two other columns. If you remove or change the property, the entire column falls out of the viewport. That’s brittle, something to refactor and clean up asap.

Use flexbox aggressively

I find flexbox one of the most useful web styling developments to come along in quite a while. It’s not overtaking my designs; most elements in my work remain block or inline. But it’s superglue for otherwise tricky layout situations. Vertical centering becomes easy. And you can position fixed elements up against a fluid element with little fuss.

Flexbox is often a smart substitute to magic and other hacks. The more you use flexbox smartly, the less you’ll fight the DOM flow in tricky situations.

The usual knocks levied against flexbox are that it’s hard to learn and doesn’t have widespread browser support. Both are not true. Flexbox’s learning curve is mild; the key is only diving into the bare minimum of what you need. Often that’s setting a containing element to position flex and adding align-items or justify-content. That’s only two or three lines of code, with no adjustment on any inner elements.

And browser support today is widespread. Only IE 9 and older doesn’t support flexbox, for most sites a tiny fraction of the user base. If those legacy IE users are a huge fraction of users, you may want to hold off for now. But for everyone else, write with flexbox as a default, and add graceful degradation (e.g. Modernizr with the no-flexbox class prefix) to handle older browsers. Or you can play it conservative by defaulting to a quick and dirty method that doesn’t use flexbox. Then add it in with progressive enhancement (e.g. flexbox Modernizr CSS prefix).

Going with the flow

Three rules: position strategically, avoid magic numbers and embrace flexbox. Each rule is straightforward to apply and remember. And they’re applicable almost anywhere, from simple WordPress templates to complex, React-powered web apps. Most web advice comes with a huge learning curve. These rules don’t.