The World of Styling for the Web

CSS Methodologies, Preprocessors, Frameworks, and Beyond. An Overview of Everything You Need to Know About Styling.

·

10 min read

Introduction

Should you use a framework? Should you write pure CSS? What about LESS and SASS? Styled components?

Styling for the web is constantly evolving. I've looked through dozens of different approaches to styling and summarised it up here so you can get to building that site you've been thinking about.

If you have some experience with styling using CSS, and you want to learn more about the wide variety of options to approach styling your websites and webapps, this is the right article for you.

Contents

CSS

CSS separates content from its presentation. CSS controls layouts, colors, and fonts. This is what every other styling technique will end up as - the browser only understands your styling in terms of pure CSS (or inline styles).

In CSS you use a selector to declare which part of the markup a set of style rules apply to. Selectors can match the element type such as an <h1> or an <article>, or by an elements attributes such as it's class or id, and selectors can be used to match elements that are placed relative to other elements, such as siblings or children.

Some standard CSS might look like this:

h1 {
  color: white;
  text-align: center;
}

.center {
  text-align: center;
  color: red;
}

Once your project starts growing in complexity, you need methodologies to keep your CSS in order. You need a set of rules on how to organize your CSS, when to use different types of selectors, and so on. All of these methodologies work with preprocessors as well, which I'll get into in a later chapter of this post.

CSS Design Methodologies

There are many CSS methodologies out there, here's a few of the most popular ones. I'll talk a bit about each.

  • BEM
  • SMACSS
  • OOCSS
  • ACSS
  • ITCSS

BEM

BEM stands for Block Element Modifier. BEM is a naming convention for your CSS.

  • Block - Standalone entity that is meaningful on its own; a component.
  • Element - A part of a block that has no standalone meaning and is semantically tied to its block; an element inside a component.
  • Modifier - A flag on a block or element; a variation is signified by a modifier.

The BEM naming convention would look like this if all three are used:

[block]__[element]--[modifier]

Block with an element

In the example below, there is a block with an element inside. The block, or main component is photo, and the elements are photo__img, photo__caption, and photo__quote

Elements are children of blocks, but the classes shouldn't communicate structural depth. In the example below you have a nested <blockquote> in the <figcaption>, but you can see the classes don't reflect the nesting. You may be tempted to write the class for the <blockquote> as "photo__caption__quote" because of the nesting, but this would be incorrect according to BEM.

<figure class="photo">
  <img class="photo__img" src="me.jpg">
  <figcaption class="photo__caption">
    <blockquote class="photo__quote">
      Look at me!
    </blockquote>
  </figcaption>
</figure>
.photo { }
.photo__img { }
.photo__caption { }
.photo__quote { }

Block with a modifier

Modifiers aren't used on their own, they should always be used along with a block or element. The modifier augments the block, therefore we use both button and button--secondary.

<button class="button button--secondary">click me</button>
.button {
    display: inline-block;
    color: blue;
}
.button--secondary {
    color: grey;
}

Element with a modifier

Elements can also have modifiers. In this example you see photo__img as the element, and photo_img--framed modifying that specific element.

<figure class="photo">
    <img class="photo__img photo__img--framed" src="me.jpg">
    <figcaption class="...">Look at me!</figcaption>
</figure>
.photo__img--framed {
    /* incremental style changes */
}

Resources to learn BEM

SMACSS

SMACSS stands for Scalable and Modular Architecture for CSS. It's best understood as a CSS style guide.

SMACSS is about the categorization of CSS rules. There are five categories:

  1. Base
  2. Layout
  3. Module
  4. State
  5. Theme (optional)

For each category, you'll create a separate folder to hold the CSS for that category.

Base styles are applied to element selectors:

In the base styles, you'd include a CSS reset. Base styles are default sizes, margins, colors, border, and anything else that will ensure consistency across your website. Typography and form inputs would fall into base styles.

body, form {
    margin: 0;
    padding: 0;
}

a {
    color: #039;
}

a:hover {
    color: #03F;    
}

Layout styles are the major sections of the site such as header, article, and footer:

These are the largest sections of your site that all of your modules would live inside. Usually you will name the layout sections with an id to ensure uniqueness.

#header, #article, #footer {
    width: 960px;
    margin: auto;
}

#article {
    border: solid #CCC;
    border-width: 1px 0 0;
}

Modules are the meat of the website, navigation bars, carousels, and so on.

For each module, it's best to create a separate CSS file to house the styles for it.

.module > h2 {
    padding: 5px;
}

.module span {
    padding: 5px;
}

State rules modify other style rules. They are applied to layouts and/or modules, and usually indicate a JavaScript dependency.

In the example, is-collapsed and is-hidden are state rules; they modify the elements they are attached to.

<div id="header" class="is-collapsed">
    <form>
        <div class="msg is-error">
            There is an error!
        </div>
        <label for="searchbox" class="is-hidden">Search</label>
        <input type="search" id="searchbox">
    </form>
</div>

Theme can affect any of the previous base styles (base, layout, module, and state), and is stored in a separate theme.css file.

Themes define colors, backgrounds, typography, etc. They are rarely used, but they give you some freedom to change the theme of your website if need be.

// in module-name.css
.mod {
    border: 1px solid;
}

// in theme.css
.mod {
    border-color: blue;
}

OOCSS

OOCSS stands for Object Oriented CSS. It applies object oriented programming concepts to CSS. A dynamic bottom-up approach is used rather than a procedural top-down one.

The "object" in OOCSS can be any repeating pattern that can be specified in a separate piece of code.

There are two rules in OOCSS:

  1. Separate Structure and Skin
  2. Separate Container and Content

Separate Structure and Skin

Structure - things that are "invisible" to the user:

  • Height
  • Width
  • Margins
  • Padding
  • Overflow

Skin - the visual properties of an element:

  • Colors
  • Fonts
  • Shadows
  • Gradients
/* Structure */
.side-widget {
  width: 100%;
  padding: 10px 5px;
}

/* Skinning */
.recent-posts {
  font-family: Helvetica, Arial, sans-serif;
  color: #2b2b2b;
  font-size:1.45em;
}

Separate Container and Content

Content are elements that are nested inside other elements called Containers.

Styles for Content should be independent from the Container.

Essentially, avoid using child selectors whenever possible. Give unique elements unique classes rather than using descendant selectors.

ACSS

ACSS means Atomic CSS, or Functional CSS.

In ACSS you define classes with a single attribute inside:

.relative {
  position: relative;
}

.mt10 {
  margin-top: 10px;
}

.pb10 {
  padding-bottom: 10px;
}

There is also a programatic variation of ACSS that utilizes Atomizer to programatically generate styles. This can be categorized as a preprocessing step.

With programatic ACSS, styles are generated based what's in the HTML, using a function style syntax in the element's class:

<div class="Bgc(#0280ae) C(#fff) P(20px)">Lorem ipsum</div>

The above HTML will generate the following CSS:

.Bgc\(#0280ae\) { background-color: #0280ae; }
.C\(#fff\) { color: #fff; }
.P\(20px\) { padding: 20px; }

ITCSS

ITCSS stands for Inverted Triangle CSS. It helps you organize your CSS files in a way that makes it easier to deal with global namespaces, cascade, and selector specificity. ITCSS is meant to be used in conjunction with most of the previously mentioned methodologies (BEM, SMACSS, OOCSS).

Your styles will be separated into the following folders:

  • Settings
  • Tools
  • Generic
  • Elements
  • Objects
  • Components
  • Utilities

ITCSS works best with preprocessing languages like SCSS or LESS, etc. The examples below use SCSS syntax.

  1. Settings – fonts, colors definitions, etc
@font-face {
    font-family: 'Source Sans Pro';
    src: url(../../font/Source_Sans_Pro/SourceSansPro-Regular.ttf);
}

$fontType: 'Source Sans Pro',
sans-serif;

$colorPrimary: #ff9617;
$colorSecondary: #4078c0;
  1. Tools – globally used mixins and functions
@mixin box-size($width:100%, $height:100%) {
  width: $width;
  height: $height;
}
  1. Generic – reset and/or normalize styles
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  font-family: $fontType;
}
  1. Elements – styling for bare HTML elements, redefining the browser's default styling

body,
html {
  @include box-size();
  background-color: $colorDark;
  scroll-behavior: smooth;
  overflow-y: hidden;
}

header {
  @include box-size(100%, 60px);
  background-color: $colorDark;
}
  1. Objects – abstract elements, the same as "structure" in OOCSS

Objects are "non-styling" elements: border, padding, text-align, cursor etc.

.button {
    display: inline-block;
    padding: 8px;
}
  1. Components – specific UI components. The bulk of the styling
.button {
    color: $colorLight;
    background-color: $colorDark;
}
  1. Utilities – utilities and helper classes

It's best to think of this in terms of atomic CSS.

.mt10 {
  margin-top: 10px;
}

.pb10 {
  padding-bottom: 10px;
}

An example of ITCSS in use can be found here: github.com/csswizardry/frcss

Preprocessors

CSS preprocessors are programs that generate CSS using the preprocessor's own unique syntax.

Preprocessors add an extra build step to your programs, and might generate larger CSS files than plain CSS.

There are a few flavors of preprocessors that will generate CSS for you:

  • Preprocessing languages
  • CSS in JS

Preprocessing Languages

Preprocessing languages add useful features such as variables, loops, conditional statements, nested styles, mixins, inheritance, and more.

The most popular preprocessing languages are:

  • SASS / SCSS
  • LESS
  • Stylus
  • PostCSS

The following examples use the SCSS syntax. Most preprocessing languages have a similar syntax.

Variables

$primary-color: #4D926F;

#header {
  color: $primary-color;
}

Nesting

nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }
}

Mixins

@mixin important-text {
  color: red;
  font-size: 25px;
}
.danger {
  @include important-text;
}

Modules

@use 'base';

.inverse {
  background-color: base.$primary-color;
  color: white;
}

Inheritance

%message-shared {
  border: 1px solid #ccc;
  padding: 10px;
  color: #333;
}

.success {
  @extend %message-shared;
  border-color: green;
}

Operators

article {
  width: 600px / 960px * 100%;
}

CSS in JS

CSS in JS is just as it sounds, it allows you to control CSS from within your JavaScript files. Typically these solutions are used with JavaScript frameworks such as Vue, Angular, React, and so on, but work with vanilla JavaScript as well.

Dynamic functionality, scoping, and portability are some of the limitations of CSS that are tackled by CSS in JS.

Within the umbrella of CSS in JS, you have a few options:

  • CSS modules
  • Styled components

Modules In CSS modules, your styles are written in separate files, and referenced in your JS.

import styles from './Button.module.css';

render(
  <button className={styles.error}>Err Button</button>;
);

Styled Components Styled components have your styles written next to your JS.

const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: palevioletred;
`;

render(
  <Title>
    Hello World!
  </Title>
);

CSS Frameworks

A CSS framework is a collection of stylesheets that allows you to quickly add styling to your projects. Frameworks utilize many of the CSS methodologies from the previous chapters and build up a set of styles that you can quickly apply to your project.

CSS frameworks commonly have the following features:

  • Semantics
  • Design Systems
  • Customization
  • Components
  • Responsiveness
  • Utilities
  • Grid system
  • JavaScript Integration
  • Browser Support
  • Integration with JavaScript Frameworks
  • Reset stylesheet
  • Typography Support
  • Icons
  • Interactions (hover, focus, etc)

Generally CSS frameworks fall somewhere between a utility framework and a component framework.

Utility frameworks utilize features in line with atomic CSS, providing static utility classes that you can use to build up your styles:

<h3 class="h1 pad-3-vert text-blue">Lorem ipsum</h3>

Component frameworks have predefined components that can be used to build up your application, typically following naming conventions similar to BEM:

<div class="card">
  <div class="card-body">
    This is some text within a card body.
  </div>
</div>

A combination of both of these types is the most common - providing both utilities and components.

Conclusion

The most important takeaway is that you should choose a method and stick with it for the project. Depending on you and your teams skillset, the tools and frameworks you're using, and how much time you are able to invest will determine which method you should choose.

Whether you're bootstrapping an MVP or creating a large-scale application, choose the methodology or framework that aligns best with the scope of the application. Keep in mind the maintainability and scalability of the method you choose.

You may even consider creating your own styling library or system tailored exactly to your needs.