UX Design and Development course

Large CSS files and increased complexity

CSS started out with very simple intentions, but as table-less web design began to really take a foothold, our stylesheets quickly began to grow in size. Developers tried to break them into smaller documents, but these strategies proved to have serious performance issues. Linking to multiple style-sheets meant multiple server round-trips adding the time it takes for a page to acquire it's necessary resources, not including the time it takes to transfer the data.

It's not entirely uncommon to see multiple links to stylesheets in websites.

<link rel="stylesheet" href="stylesheets/reset.css">
<link rel="stylesheet" href="stylesheets/base.css">
<link rel="stylesheet" href="stylesheets/skeleton.css">
<link rel="stylesheet" href="stylesheets/font-awesome.css">
<link rel="stylesheet" href="stylesheets/buttons.css">
<link rel="stylesheet" href="stylesheets/layout.css">

The practice of importing stylesheets into the one stylesheet linked in the HTML document was adopted by many as shown in this example from the MOZILLA DEVELOPER NETWORK. This technique had many promisses. It not only supported breaking your CSS into manageable documents but it also supported media types.

@import url("fineprint.css") print;
@import url("bluish.css") projection, tv;
@import 'custom.css';
@import url("chrome://communicator/skin/");
@import "common.css" screen, projection;
@import url('landscape.css') screen and (orientation:landscape);

It's ultimate failure was that this feature has such a negative impact on web page performance, as pointed out by Steve Sounders back in 2009, it's practice was quickly abandoned. Using the link method, the stylesheets are loaded parallel (faster and better). The @import method loads any extra css files one-by-one (slower), and potentially gives you flash of un-styled content.

Looking for new solutions, developers began to adopt the use of CSS preprocessors to manage growing CSS code bases, but sadly didn't change old habits. Still clinging to the practice of creating large documents, many placed mixins and variables at the head of the doc and simply hashed out a bunch of CSS rules in the body. To make matters worse, as the documents began to grow in size, mixins and variables began to show up at random places within the stylesheet.

Realizing the need for better management techniques, many began to break these large stylesheets into smaller documents based on common principles like variables and mixins. Typography, forms and global design soon followed. Sure this reduced file size and increased readability, but without a real strategy this process was easily doomed. As files grew in number, sub-directories quickly gave way to junk-drawers of haphazardly daisy-chained files, filterable only my failed attempts at naming conventions.

Controller/action based styles

Inspired by Model-View-Controller(MVC) frameworks, mainly Rails, developers began to adopt these file structure solutions to help solve their issues. While there is some merit to this in regards to template/layout styles, this practice inevitably lends itself to creating styles that are too specific to each individual view and not easily reused throughout the rest of the application.

As a site's design progressed, duplicated code began to reveal itself between views. Attempts at abstraction, following another MVC pattern, typically resulted in the creation of a /partials directory. Basically, a simple repository for custom built mixins, variables and other reusable code. In essence, a Sass junk-drawer.

Following another Rails MVC patterns, developers attempted abstract away from the view and organize their files based on actions. If the visual elements are part of an action, making directories based on these actions makes sense, right? Sadly, this quickly falls apart as not all UI elements can be easily categorized this way. Random files again populate the directory, universal widgets, plug-ins, and custom mixins begin to collect. Once again we find ourselves suffering from the Sass junk-drawer effect.

Learning from our mistakes

Life is about journeys. It was during my journey of 'doing it wrong' that I began to see clearly. Ironically, I had the right solution all along, but didn't realize it. While part of a team developing an enterprise CMS, our process was to decompose a site's UI to it's lowest common elements. From those elements we could then build modules and then finally assemble the view templates. Each step building on the previous. Although my stylesheet management techniques weren't perfect, my concept of UI abstraction was solid.

In 2009, I began working with a new team, sans a CMS and my first encounter with Sass. I approached the project with the same conceptual understanding, but the outcome was drastically different. The code became increasingly harder to reuse and making simple edits resulted in the re-engineering of HTML as well as CSS. Post launch, I sat down and analyzed the code I wrote. I came to the realization that, as a team, we were engineering our UI (CSS and HTML) from entirely the wrong perspective. We were approaching our development from the full page perspective. Engineering all our visual elements from the outside-in and scoped to a specific view.

I started thinking back to the processes I pioneered with the CMS. Patterns established in the framework dictated we start from the elemental perspective; type, colors, forms, basic UI chrome (borders, shadows, icons, etc) all coded first. Once those base element styles were completed, it was a matter of applying the skin to the individual CMS modules. The modules then in-turn were used to assemble the view within the various automated templates. It worked quickly and seamlessly. Building the UIs from the inside-out was clearly the right solution.

Elements, modules and layouts

Applying these principals to new projects was the next challenge. First we need to be better at decomposing our designs. The inside-out approach is key to this process, the goal of the file structure, and necessary for a scalable architecture. Simply put, code the element, create the module and assemble the layout.

At this point you may be drawing parallels with Jonathan Snook's SMACSS approach, as you should. The approach I adopted shares many similarities that were later outlined in Jonathan's book. But alas, there are differences due to the vary nature of Sass and the additional features that it supports over vanilla CSS.

  • Base
  • Layout
  • Module
  • State
  • Theme

While many of these concepts are solid ways to architect a scalable CSS structure, they are somewhat constrained by the limitations of vanilla CSS. But this is a book about Sass and we are not as easily constrained by these limitations.

In SMCASS, there are five types of style categories:

Base

Core styles that will make up your site or application. Base rules are commonly applied to an element using the element selector itself. Thrown into this bucket would be the CSS reset, typography, forms and buttons. These base styles will each have their own Sass file for easy management, here is an example from a _typography.scss Sass file.

html {
  font: em($font_size, 16) $primary_font_family;
  line-height: baseline($font_size);
  color: $primary_text
}
// Heading CSS rules
// --------------------------------------------
h1, h2, h3, h4, h5, h6 {
  @include heading();
}
// Standard body text support
// --------------------------------------------- 
p{
  margin-bottom: baseline-margin($font_size);
  text-indent: 0;
}
a{
color: $href_color; text-decoration: none; &:hover, &:active {
    text-decoration: underline;
  }
  &:visited {
    color: $href_color;
  }
}

Modules

SMACSS and I share a similar point of view. Consider modules as 'nouns' in your code. These are the 'things' that you will be making the most use of. Leveraging the styles created in base, I can begin to create small and large modules that can be infinitely reused.

Where Sass begins to add super powers is it's ability to break down modules even further into infinitely more reusable code. The use of mixins and placeholder selectors strike an even more amazing balance between presentational selectors in your CSS and semantic selectors in your markup.

State

State is a powerful concept and again fully supported. State typically is an over-ride to the default style placed on an element or module. If the module is a noun, then the state is the module's verb. Common concepts are .is-hidden or .is-error.

Where I slightly differ with Sass is I feel that state rules are better managed within the parent selector versus always having completely separate rules. This is not a fundamental change in the state concept, but an area where Sass shines a light on the limitations of vanilla CSS.

SMACSS emphasizes using the !important tag when creating stand alone selectors. I find this approach to be somewhat problematic. Instead, I advocate for not only creating a standalone default rule for the management of state, but in the cases where specificity is needed, nesting the state rule in the module it is designed to augment is preferred.

Layout

In regards to layout, I take a different approach all together. SMACSS considers layout as slightly different representation of the module, conceptualizing them as major page components. Examples would be .site-header, .site-footer and .main-nav.

I on the other hand, as discussed further in this chapter, consider layout to be a more holistic assembly of a view or template for modules to be inserted. I consider the layout to be the structural CSS that comprises the grid in various states depending on user input and environment. To me, the layout is the key to easily manage responsive web designs as so may of the UI decisions are based on the layout, not the module themselves.

Theme

Much like layout, I take a completely different approach all together. Sass' ability to create UI variables, mixins and placeholder selectors allows me to re-write the concept of CSS theming. In SMACSS theme is not considered part of the core types, where I see it as an essential player on the construction of the site design.

A good example of a theming solution would be with a tool-tip bubble. For example the tool-tip module would consist of inheriting typography, applying some shape and aesthetics such as a carrot. The theme of the tool-tip would be it's padding, color, border and possibly a shadow effect. With vanilla CSS, it is recommended that you engineer the module itself, then later in a "theme" section of your CSS you again reference the selector to add it's theme rules.

With Sass we can take this to a whole new level by engineering the tool-tip as a self contained module either as a mixin that accepts arguments or a placeholder selector with variables. Selectively enhancing the module at the time of placement and coupled with the concept of a _config.scss file, I can list out all the configurable "theming" parts of the site's design.