Strategy

Resets and normalisations are agreements, and while they are helpful, understanding their coverage well is a good idea.

You generally can’t go wrong with a reset since its purpose is simply getting rid of unintended styling, which is what happens when you rely on browser-given styles for something. A normalisation, whether it’s something introduced by a library (and in the case of Normalize.css, you can think of it as a less brutal reset) or one you write yourself, has no business existing unless it’s likely that the rules will be applying to every element it references.

A common example of normalisation is when styling paragraphs within a component, deciding that it probably means adding a default font size and margins on a root p tag selector as a first step. The problem is knowing whether that agreement won’t, in fact, create more work than it’ll prevent (the all too common behaviour of then needing to re-reset those defaults more than not). As with much else, a better approach is to mindfully repeat yourself a little and only then refactor when repetition starts happening in a small but significant level.

If most people figured the correct way to drive is back-facing the wheel, that wouldn’t make it a good idea considering not colliding into things is important. This metaphor explains how most people understand and use the Cascading in Stylesheets. They’ll drive it backwards, hit something, and then go on Twitter and say cars are inherently bad and that we all oughta be walking instead.

Cascading needs control, and the best way to go about it is not using it at first , and then applying it judiciously where it makes sense. This has a big impact on further advice, so I’ll go on a little tangent here: early in the intro chapter, I referred to a SCSS file as a “module”. What I mean is:

Unlike CommonJS, or its well-known implementation, the Node.js module system, we aren’t getting the benefits of isolation in variable declaration and such with Sass. So everything is a global, and we have to live with that at least for now. On the upside, we will only ever declare variables when we need to coordinate a value across directives, either within the same file, or when the intention is making said value available to other modules. And then we’ll be making it really obvious that this module is now to be understood as a dependency.

This will let us:

.main-navigation {
  // This applies to all buttons inside this selector.
  button {
    outline: none;
    background: transparent;
  }
}
// very-nice-button.scss
.very-nice-button {
  border: 3px solid black;
  background: transparent;
  border-radius: 2ex;
  color: $black;

  .icon {
    color: $orange;
  }
}

// main-menu.scss
.main-menu {
  // …

  .very-nice-button .icon {
    color: $green;
  }
}

If you write code in other languages, you’ll notice these ideas are largely based on existing modularisation concepts. This is not by accident. Instead of running around with our heads on fire saying CSS is doomed to fail, we reap the benefits of existing logical frameworks that are similar to ideal mindsets we’re already applying elsewhere.

A Sass module is the implementation of all features in the component design, not just the code necessary to reflect a static snapshot of how things look. When you approach writing it with that mindset, things tend to go a lot better.

For instance, say you’ve received a mockup for a component that looks like this:

List navigation example

Most would simply write a horizontal list and call it a day. But ask yourself these:

It’s impressive how such a small component can yield this many questions, but thinking through these creates design that’s better at solving problems, which helps you avoid paying later with interest for what you don’t foresee initially only because you failed to address the basics.

When not working around browser bugs, as in actual bugs and not defects in comprehension of how things work, hacks are the fruit of weak implementations that fail to address all the feature-questions such as the aforementioned ones.

What was explained thus far suggests an approach to styling components that says we are using class names that describe what the component is, and all styles come from that class name (aside from styles shared across classes). This isn’t the only way to go about it, though.

Certain libraries will do the composition on the markup by adding various class names that carry a set of directives each, where then these class names are similar to ingredients carrying certain properties. For example, this snippet from Semantic UI (ignore the grossness of using a div for a button):

<div class="ui primary download button">
  Download
</div>

We could source the classes from their own files. As far as visual outcomes go, it would amount to the same:

// Primary download button
// =======================

.primary-download-button {
  @include ui;
  @include primary;
  @include download;
  @include button;
}

With the difference being that the class name the button exposes in the previous example carries a more descriptive name.

There are other patterns which make use of tag attributes, such as AMCSS, where the core group of directives comes from the attribute name am-Button, with modifiers being passable as values to it, as in:

<button am-Button="primary large">
  Download
</button>
// Button module
// =============

[am-Button] {
  …
}

Modifiers are class names that change the original set of styles in some way. You can think of them as parameters to a command that modify the outcome in a way that makes sense. In my own preferred approach, you let a few modifiers in that can be passed as “commands” to the class name, not unlike AMCSS in that regard:

// Default form styles
// ===================

.default-form {
  // … Core styles go here.

  &.vertical {
    // Label on top of fields styles go here.
  }

  &.labels-left {
    // Labels to the left of fields styles go here.
  }

  &.disabled {
    // Styles for when the whole form is disabled.
  }
}

Which lets you write markup like this:

<form class="default-form vertical">
  …
</form>

Understand that this is all logic juggling. None of these patterns make problems disappear, but they’ll help you distribute them more sensibly. Some being more effective at that than others, but all still largely depending on how smartly you split that logic in the first place.

Manifests in stylesheets are lists of modules required to load a certain page. There are no hard rules on how to write these, but being clear can go a long way. Assume this is called application-manifest.scss:

// Application styles manifest
// ===========================

// Dependencies
@import 'grid';
@import 'type';
@import 'colour-palette';

// Modules
@import 'main-navigation';
@import 'posts-wrapper';
@import 'notifications-wrapper';
@import 'page-footer';

In saying “page”, there’s an immediate problem that comes to mind: in JavaScript apps, there’s hardly such a concept past the initial delivery. So depending on how your website is used (this, by the way, is an important consideration when optimising), a lot of waste can happen with selectors that will never apply during a given session, and are loaded anyway.

The thing is: despite performance being very important, manifests are still useful for grouping modules. An approach coined recently by some consists of loading critical styles at the top of the page, and then the remaining at the bottom (and maybe even more fine grained than that, but bear with me). You can write two manifests, one essentials-manifest.scss sourced in the <head>, and a remaining-manifest.scss sourced before the <body> ends. This can be tricky to do effectively without splitting writing component styles between essentials and enhancements, as you don’t want the page to flash as entirely garbled for even a split second until things such as positional and dimensioning values are loaded.

But that doesn’t address the fact that you’re still potentially loading a lot of styles that won’t be used in a given session. The solution to this won’t be cheap logic-wise, but at the cost of some code in the build script, you can retain manifests as files, but output their compiled contents to a style attribute in the corresponding element, or even as a <style> tag directly in the DOM by using templates and helpers. An example of the former:

An easy to forgo element when implementing a design is colour organisation. There’s a false sense of necessity when it comes to it that leads to sometimes dozens of imperceptible variations if put next to each other. That’s aggravated when a designer loses sight of the whole.

Colour, like the choice of typeset, is part of the message, and dillution happens when too many tones are introduced in a design. And a way to keep the issue visible is declaring the palette in a single file through variables, maybe named colour-palette.scss, and using it as a dependency. Like so:

// Colour palette
// =============

// Base tones
$red: #970808;
$yellow: #f2f213;
$white: white;

// Variations
$dark-red: #3E0000;

// …

Sass provides methods for manipulating colour, such as darken() and lighten(). These are handy for creating stale variations. That is, variations that will not be reused throughout the codebase, since to put it simply, if you were to do that, you’d be better off then actually declaring them in the palette file.

From a strategic perspective, stale variations are less bad than a number of useless variations coded into the palette because they don’t add to the options, thus discouraging them becoming the norm.