Better Styles Through ems
29th November, 2016 —
CSS is vital to Better. The Better apps (iOS and Mac) are native apps that use web pages for their content. They’re the same pages you see on the Better site, but with specialised templates. Still, the content you see on the apps is largely HTML and CSS.
The pre-compiled architecture is fairly straight-forward:
- a common CSS file for styles that cover both the site and the apps
- a site CSS file that covers site-specific design elements such as the navigation, footer, and site homepage
- an app CSS file that covers rendering differences between the app(s) and site
Each of the CSS files is compiled into a global CSS file during the build process using first the common CSS file, and then either the app or site CSS files.
The opportunity
When we first launched Better, the iOS app had a coloured frame around the content (see below). The frame was in the native app, and meant the content viewport size was slightly different than when viewing the same content on the site in a web browser on the same device. It also meant the CSS required specific media queries to ensure more complex design elements, such as the statistics, would fit the viewport and still look good on narrow devices.
In September, Aral removed the coloured frame from the app interface. Firstly, this gave the interface a much cleaner and more spacious feel. It also meant the viewport widths were exactly the same whether you were looking at Better content in the app or in a web browser on the same device. This gave me the opportunity to overhaul the CSS, removing excess rules and repetition mostly caused by a gazillion media queries.
Changing the way I design for the web
In a yet-to-be-releasable redesign of my own site, I’d started experimenting with a new approach to units and measurements in my design and overall CSS. I started using em
s for every unit. Using em
s turned out to be easy, and made my CSS clean and simple, especially as I was writing the CSS from scratch. Using em
s isn’t new or revelatory in the web world. But it was always an approach I shied away from before.
I’m pretty good at CSS. You don’t get away with being this bad at JavaScript without knowing CSS very well. Still, it’s taken me a long time to relinquish control over the pixel precision-based thinking learned through years of designing in bitmap graphic software. One can take the Photoshop away from the woman, but you can’t take the Photoshop mindset out of the woman. Even though I hadn’t designed in Photoshop in nearly a decade, had used vector graphic software, had jumped on responsive web design as soon as I heard about it, my brain still thought, and designed, in pixels. When I read anything new about responsive design and other development approaches, I used those techniques, but I still envisioned my work as pixels mapped in the canvas space. I used rem
s and media queries, but these were usually compiled from pixel units. I abstracted away my inflexible pixel brain.
To a flexible everything with ems
As Better no longer needed so many media queries, the leap from rem
s and px
to em
s was straight-forward. Though from a visual perspective, it was hard to visualise the units as relationships between the type and space without starting from scratch. In order to better visualise the design in flexible units, it turned into a complete refactor.
I started by converting all font-size
s to em
s, then removing any subsequent media queries relating to those font sizes, instead using two media queries on the root:
With all font sizes scaling up from the root at 460px and 600px-wide viewports, every other rule using em
s will scale up too. Thanks to the cascade, the scaling is always in proportion to the font size. This makes most media queries redundant, with exceptions only when tweakpoints are required between or above these viewport sizes. Scaling with em
s requires fewer rules, and makes every rule proportional. It’s building on the existing flexibility of the web.
Then I took all the paddings, margins, max-widths, and anything else related to space or layout, and converted those units to em
s, removing their media queries too. I generally used the old target/context = result
rule. A margin: 12px;
, with a root font-size
of 14px
becomes margin: 0.857142857em;
. The decimals are ugly, and harder to visualise, so I rounded units as I re-factored. This makes the margin: 0.857142857em;
a much tidier margin: 0.85em;
.
With barely any media queries, the CSS was easier to manage. It meant I could have a fresh look at the relationships between the type and the space, adjusting consistently across all the elements. When writing CSS, I first style based on the naked elements (h1, h2… ul… p
etc) themselves. (Heydon recently wrote a great article on the benefits of this approach.) Styling without classes is also necessary as most of our content is generated directly from markdown.
The few modules that rely on classes for more complex layouts and styles (such as the statistics below) didn’t need a million breakpoints either. The core typography and spacing of these modules were already adjusting to the available space derived from the base element CSS, so when refactoring, the rules only occasionally needed minor tweakpoints.