Stop Worrying and Learn to Love the Cascade

CSS is definitely a step up from <font> and <table> designs, and its straight-forward declarative nature has made it one of the most-used “languages” that exists today. Anyone can sit down, having never seen it before, start making changes and be productive in minutes. That’s a seriously big deal. CSS is awesome that way.

But I see many people trying to force CSS to behave with absolute precision as if it were printed ink, and I see others trying to make CSS jump as if it was a full-blown programming language like Javascript or Python (or they want to shove it into JS or Py). I feel like this is missing the forest for the trees; all CSS does is 1. target a DOM element, 2. describe what it should look like, and 3. cascade those looks to related elements. You should be able to swap one stylesheet for another and change a web page’s aesthetic without touching how it works. It is precisely this simplicity which makes CSS so useful and powerful; it’s a feature, not a bug.


Web != Print

I’m a full-stack developer/designer, so when I start a new project I’m not usually thinking about CSS right off the bat, but I must confess: applying styles and implementing a graphic design in CSS is the part of any project that I look forward to the most. I find it the most relaxing, straightforward, and impactful part of the process (from an observing user’s point of view). It’s where the app has life breathed into it, when it starts
 looking like something. You first see an app’s magic happen here.

I’ve talked to a lot of devs and they think I’m crazy. They say things like “Why doesn’t CSS have programming feature X?” or “Why are all these styles overriding other styles?” or “How are you supposed to get anything done?” or “Where’s the OOP!?”

I think a lot of this sense of dread comes from a misunderstanding from both designers and developers. I see designers harassing developers for pixel-precision to match the screen to their fabulous design files and I see developers cutting corners in markup, wrapping each and every part of a UI in useless <div>’s just to namespace a little section of the DOM so they can clobber all the other styles cascading down the hierarchy.

I think everyone involved just needs to step back, take a deep breath, and accept that when it comes to web design, flexibility is the name of the game, not pixel-perfection. You have to know going in that your design is going to shift and change slightly on different systems, at different resolutions, and in different lighting conditions. You have to create with this in mind. I know we’re over 20 years in, but it seems like it still needs to be said: the web is not print! Rendering in browsers is different than printing on paper. And keeping it all organized doesn’t happen automatically: you gotta do a bit of thinking.


Only Say What Needs to Be Said

The most perplexing thing I see when I look at other people’s CSS isn’t even the CSS itself, but the markup that it’s trying to style. “Semantic” means it means something. The whole point of HTML is to mark up content to give it context, so that when computers look at it they see a nicely structured and meaningful collection of associated concepts. Markup should only be introduced if it adds clarity, specificity, and/or definition to the content. You should avoid adding it just for the sake of styling (although during the process of styling content, you may discover some ill-defined areas of your markup which could use some additional semantic definition).

As you might imagine, my opinion on CSS involves an absolute minimum of markup: only use what you absolutely need to express the meaning of the content. I also believe in short, concise, well-expressed class names (and variable names in general), such that in looking at the raw markup, even a lay person could make well informed judgements regarding the purpose of those words (e.g., just call a class “signup-form” rather than “form-simple form form_signup-new h50p redbold” or “column-2 grid-4 span-half p-12”).

I believe in DRY (Don’t Repeat Yourself) and KISS (Keep It Simple, Stupid), and I believe in minimalism in general— if you can express the same thing in fewer words, then do it. Shorter is better. But that is not to say eliminate meaning altogether by reducing your labels to simply ‘x’. The point is to reduce as much as possible, without losing any meaning.

I also think UI shouldn’t take centre stage in an app. It should sit back and be as invisible as possible, only presenting itself when needed to empower users to solve their problems. UI designs should strive to introduce as little UI as necessary and let the user use the app and focus on the content. This doesn’t mean “no UI”, but “smart UI”. Your app shouldn’t look like an airplane cockpit. It should be a hammer when you’re hitting nails and then change to a brush when you’re applying paint. Common sense will almost always win the day.

I’m not really a big fan of things like BEM or Bootstrap or PostCSS or what-have-you. When it comes down to it, CSS is pretty darned good at solving visual web presentation problems all on its own. I think these tools are great for what they were invented for: rapid prototyping and bootstrapping a web app to allow you to focus on core business problems over finicky styling problems until you get some momentum going. But every app has its own idiosyncrasies that never fit perfectly into a generalized framework. I think the goal should ultimately be to “do it for real” and take the training wheels off. Using a framework shouldn’t be a replacement for understanding your medium.


Yet Another Way to Organize Your Styles

Organizing large application styles can be daunting and requires a bit of forethought so you don’t get lost in a tangled web of overriding overrides that are all !important. The architecture I’ll lay out here will be, I hope, a guide that can help you organize your styles by meaning.

Before I get started, I should mention that I don’t use plain vanilla CSS (I like SASS — LESS is pretty much the same thing). There are a few annoyances such as vendor prefixes, no modularity, and a lack of variables that make certain details more difficult when using vanilla CSS. That said, the SASS I make is very minimal. I use a subset of the SCSS syntax, which is pretty much just vanilla CSS with sprinkles on top (I only make use of variables, @importand maybe a convenience method from time to time, such as darken()or lighten()). This just helps me structure my code and stay DRY, that’s all. I don’t go crazy with mix-ins or creating a convoluted OOP hierarchical taxonomy or anything (FYI, don’t do that), so I think it’s pretty simple and easy to understand.

The structure I’m defining here isn’t the be-all-end-all of CSS organization, nor should it always be followed to the letter. I just find this structure gives me room to maneuver and capture an app’s ever-growing complexity without mucking things up too much. It feels natural and organic, and it can adapt to changing circumstances to meet oncoming challenges. Maybe it can help you, too. I’m constantly re-evaluating how I work and revising how I do things (you should too: always be thinking!), so take this with a grain of salt. This might be overkill if you just have a handful of styles for a small component that would be well-supported by a single CSS file. Or it might not be enough for a huge 100+ person mega project that needs more sophisticated coordination and verification processes. This is just a starting point that you can adapt to the way you work.


High Level Categories

Let’s start with folder structure. I like to create a folder called “styles” in the root of my project from which I can make use of build tools (like with Gulp, Grunt, Webpack, or whatnot) to pull in my SASS and output the resulting vanilla CSS to another build folder for use in production.

Inside this base folder, I then create one or more app-specific folders. For a particular web app, I may have a folder for “client” (perhaps a public-facing SPA), “admin” (a different, locked-down SPA used only by administrators), and maybe another one called “marketing” which is a separate set of styles for the static marketing website which promotes my “client” app. These are the highest-level buckets, grouping styles into logical sub-apps, which are all related in a single project that will be distilled down to single, independent stylesheet files for production. Inside each of these high-level buckets I use the same repeated structure to organize per-app styles.

Inside each app folder I then create an index.scss file which acts as the root for each app’s stylesheet. This file does nothing more than import all the other styles in the order in which they should cascade. This file gives you a broad overview of the app styles and makes it easy to re-order things to help with cascades and overrides (e.g., you might use a default app-wide style at the top of the file which is overridden by more specific component styles further down).

An example index file might look like this:

@import "vendors/normalize";
@import "vendors/ionicons";
@import "helpers/colors";
@import "helpers/measurements";
@import "core/defaults";
@import "core/layout";
@import "core/fonts";
@import "core/shared";
@import "components/header";
@import "components/page";
@import "components/forms";
@import "components/flash";
@import "components/chat";
@import "animations/spinner";
@import "animations/progress-bar";
@import "animations/slide-down";

As you can see, the styles are broken down into logical buckets which can easily be arranged as you see fit simply by editing this file. The things that are imported closer to the top will be overridden by things that are imported closer to the bottom. I should also mention that in SASS, any variable that is imported before another file will make that variable available in that other file. This way you only need to import those variables once, here, and then just use them in all your other files.


Folder Structure

Along side the base index.scss I then include a standard set of folders which I use for each and every app/stylesheet I want to create. It looks something like this (here, I’m only showing the admin stylesheet, but the same things would be done for each stylesheet inside client and marketing too):

styles\
admin\
animations\
components\
core\
helpers\
vendors\
index.scss
client\
marketing\

This is the basic structure. There is a styles folder which has one or more children, each of which represents a single stylesheet (for example, per app/website/section). Each of these folders uses a standard internal structure to help organize the different parts of each stylesheet, each containing a main index.scss file which will be compiled down to a single vanilla CSS file by your build tasks (however you want to do that).

The names of these internal folders are fairly self-explanatory. I start with a core folder which includes any global or shared styles which will apply to the stylesheet as a whole (e.g., defining the base font, the size of headers, and the general, broad-strokes of the layout). I then make use of some helpers which include re-useable variables for things like colour palettes, grid measurements, and fonts. Next to that is vendors which contains 3rd-party CSS which I use, like resets, icon sets, etc. Most of the work will likely be done in the components folder which contains separate .scss files for each logical “component” in the UI (e.g., things like “header”, “lists”, “forms”, and more specific widgets like “switch”, “suggestion-input”, or “signup-button”). The idea is to group styles by logical components or problem domains; little pieces of the UI that group a bunch of markup into a nameable category. I don’t have any hard-set rule on how to divide things up, but it’s like anything in programming when you’re trying to name variables and segregate modules: I don’t think it’s possible to define some universal rule on how to do it; just use common sense. Lastly, there’s the animations folder, which I keep separate because I find CSS animations can get pretty big and verbose, so I like grouping those into their own files (e.g., “loading-spinner”, “progress-bar”, “page-flip”, etc.). Each file in this folder would correspond to a single animation which could be applied to an element with a class name.

This is what a fully populated admin stylesheet folder might look like:

admin\
animations\
spinner.scss
progress-bar.scss
slide-down.scss
components\
header.scss
lists.scss
switcher.scss
buttons.scss
core\
defaults.scss
fonts.scss
layout.scss
shared.scss
helpers\
colors.scss
fonts.scss
measurements.scss
vendors\
ionicons.css
normalize.scss
index.scss


Core

It’s worth talking a bit more about the core folder specifically because the files in here are always the same. These are meant to be global styles which would cascade down through all the others; things that would always apply except in very special circumstances.

default.scss

This is usually the first thing to be loaded by index.scss (after any resets and whatnot). In this file I try to only define base HTML tag styles (that is, no classes are defined here). These are styles that apply app-wide which define the core essence of the app/stylesheet. I might include things like applying box-sizing: border-box to all elements, or define the font-size and line-height for the <html> and/or <body> tags (which would cascade down to all children unless overridden specifically). This, thus, also defines the size of an em or rem which will be used for layout purposes deeper down. I usually define a set of header tag sizes here for <h1>, <h2>, <h3>, etc., so that they are always consistent. I’ll define the <a> tag’s style to standardize all links. I’ll define how <b>/<strong> and <i>/ <em> will look (e.g., I might use an actual italic font rather than a browser’s fake italicize function). I might set some basic <button> styles (like remove the default 3d shadow stuff), I might do the same thing for <input> and <textarea> as well. The point is, define your root, app-wide, generic styles here. Think of this file as an app-specific reset which sets up all your subsequent styles so they start off on the right foot.

layout.scss

I like using this file to store the broad strokes of my layout. The stuff that doesn’t change. But I don’t apply any “decorations” here, only layout styles (i.e., no colors, fonts, or borders; only display, position, overflow, padding, and margin for the main parent containers of the UI). I find this helps me “see” the structure of the app’s layout at a glance which makes it easier to later make adjustments for things like responsiveness. So, for a classic layout like this:


============================================
| header |
============================================
| nav |
| — — — — — — — — — — — — — — — — — — — — -|
| | |
| | |
| | |
| content | sidebar |
| | |
| | |
| | |
| | |
============================================
| footer |
============================================

I might define each of these sections in the layout.scss file where I simply apply styles like display: flex and flex-direction: row etc., which simply place each of these containers in the locations of the viewport that I desire in order to structure this general layout. I won’t define smaller widget layouts here, only the broad-strokes which apply to the app-as-a-whole.

HTML:

<body class="my-app">
<header></header>
<main>
<section class="content"></section>
<nav></nav>
<aside></aside>
</main>
<footer></footer>
</body>

SCSS:

.my-app {
display: flex;
flex-direction: column;
min-height: 100vh;
  & > header {
}
  main {
display: flex;
flex: 1;
    .content {
flex: 1;
}
    & > nav,
& > aside {
flex: 0 0 12em;
}
    & > nav {
order: -1;
}
}
  & > footer {
}
}

shared.scss

I put a file in here called “shared” just as a placeholder for any re-usable, high-level classes I might want to use in my app that don’t necessarily belong to any individual component, or for which I may want to override with component-specific versions of the same class. Things like “button” or “divider” or “disabled”. To be honest, I don’t use this file that much as most of these things make more sense to me as their own “components” anyway (e.g., I’ll make a buttons.scss file in the components/ folder for buttons and import that above all other components which contain all button-related classes and styles). But I find this file handy as a placeholder while I’m developing, while I haven’t fully fleshed out what my style structures are yet. So I might make a little .button class in here, first, and later expand that into a full-fledge component file.

fonts.scss

This is just a place to put all of my font-face definitions. These are usually pretty verbose and deserve their own file to contain them all. Also, by placing them in a high-level file, here, they can be imported, in order, above all other components in the index.scss file.


Keep It Simple, Stupid

I find that in most circumstances there really isn’t even a need to create a new CSS class where a plain HTML tag name can be used. I think devs should really take more advantage of what’s already there. HTML has great semantics you can latch your styles onto right out of the box. Don’t over-think things!

For example, rather than doing this:

<div class="my-component">
<div class="my-list">
<ul>
<li>
<div class="my-list-item"></div>
</li>
</ul>
</div>
</div>
.my-component {
.my-list {
.my-list-item {
}
}
}

Just use what God gave you:

<div class="my-component">
<ul>
<li></li>
</ul>
</div>
.my-component {
& > ul {
& > li {
}
}
}

Take advantage of the semantics that are already there! Use newer tags like <main> and <aside> rather than <div class="main content"> or <div class="sidebar">. Use combinators like >, +, and ~ to create specificity without adding more crufty classes (think hard before you create a new class).

While you’re at it, use attribute selectors like input[type="checkbox"] and pseudo-classes like :last-child:focus, and :checked too. Stop using float and table; use flexbox and grid (anyone using IE9 should have their internet license revoked). Don’t use px for measuring things (unless you have a good reason); use em or rem based off a standard grid size. Use box-sizing: border-box because anything else just doesn’t make sense (at least to me).

Think about how your design will resize with the viewport (this isn’t static print!). Be careful not to nest things too deep in your SASS/LESS (it’s really easy to forget about it — define things from the root as much as possible). Don’t use !important; if you’re using it, you’re probably doing something wrong (there are exceptions, but in general it’s bad form). Try to use the same measurements to position things (e.g., use a grid of, say, 4 pixels and base all your measurements off that such that elements are positioned in multiples of 4 pixels). A good design should have a well-defined grid which should make the CSS a no-brainer. If you find yourself shoving stuff around by 1px increments using floats and absolute positions, this might be an indication that the design needs revision, not your CSS.


The Web is Fuzzy; Design for Flexibility

I’m concerned about the graphic designers out there who aren’t understanding how the web works. I see poor developers being told to push things, one pixel at a time, spending hours and hours revising minuscule little things just to force a website to conform to a designer’s internal sense of what’s “right”. Look: stuff is gonna move around and be slightly different on different platforms. Know this going in, and work with it, not against it. Stop wasting time trying to turn the web into print and let developers actually make stuff work instead of churning on the facade.

Don’t get me wrong, I absolutely love good design and I truly believe it’s one of the most important aspects of any good app: it’s the part people touch and feel and love. But it’s not more important than an app that actually does something. I don’t care how great it looks, if it’s broken! And in the commercial world there are usually deadlines to deal with as well. Balance and flexibility are key. Trade off a little pixel-precision here, for a few less bugs over there.

Talk to your developers and listen to them; they know stuff. Also, learn CSS yourself and push pixels ’til your heart’s content (you’ll probably think differently about how you create your layouts). Ultimately, the final CSS should be an iterative process of trial and adaptation which transforms your ideal design into the real design based on a healthy back-and-forth between graphic design and HTML/CSS implementation. Your job is to define this ideal, not to enforce strict adherence. Work together to discover the best way of representing the solutions to UX problems through visual communication in the web medium; this means actually using the medium of the browser, not InDesign.


TL;DR

I think there’s a conversation that’s missing from the production process which involves a back-and-forth between developers and designers: implementation should inform design as much as design informs implementation and adjustments on both sides should be taken to balance functionality/implementation/interactivity, time/cost/effort, and ux/aesthetics/branding.

I also think the implementation of graphic designs in CSS can be made a lot less complex. I’ve presented one possible approach to managing it beyond the framework-sandbox. CSS doesn’t need to be a full-blown programming language. It has a lot of great features built-in. Learn how to embrace the cascade!

References

Be sure to share the post if you found it useful. And if you have suggestions of even better methods we should try, tell us in the comments! (Always be learning, right?)

Written by

Rob McLarty

Rob McLarty

Sign up for our newsletter