Deprecated: Our Legacy HTML/CSS Approach

💡

Cantilever now uses an ITCSS methodology for new sites. Until 2018, we built sites using a style inspired by Nicole Sullivan’s OOCSS project. It allowed us to write less code per site, with higher predictability, speed, and maintainability. After flexbox, CSS grid, and CSS custom properties became usable in production, this method was no longer necessary to accomplish those goals.Here is our original writeup on the topic for posterity. This style is important to understand for any developers who need to go back and update one of our old codebases.

We use a modified version of BEM syntax to write our classes. BEM allows us to clearly scope styles to the components which need them. The style leads to somewhat more wordy classes and in some cases, code duplication, but we prefer the structure and predictability of it.

Core Principles

  • Styles should be independent from their content (what goes in them) and the context (where they are).
  • We write many components which each perform a small part of constructing a page. We do not write the styles of a page, write the styles of the components which make up that page.
  • Styles should be defined by their purpose, not their appearance
  • We like to wait for new technologies to be tried and tested, but embrace new techniques and technologies when they are viable
  • We have a consistent style which can adapt to new approaches. For instance, we changed from float-based layouts to flexbox without affecting our style.

Code Structure

We have projects with LESS, SASS and no preprocessor at all. The structure and philosophy remains the same.

  • layout: Directory containing components which are never contained by other components. These are always the outer wrapper elements.
    • Header
    • Footer
    • Content
    • Hero
    • etc.
  • containers: Directory containing components with ARE contained by other components, and also DO contain other components. Modules, Grids, Etc. These structure the page.
    • Module
    • Layer
    • Grid
  • objects: Directory containing all components which CANNOT contain any other components. These are the end of the line.
    • Heading
    • TextBlock
    • Image
    • VideoBlock
  • main: Assemble all styles into one stylesheet, order them. Required by preprocessors but not raw CSS
  • vars: Store variables.
  • reset: Store CSS reset
  • special: Store exceptions and third-party CSS that cannot be modified

Nuts & Bolts Style Rules

  • Two-space indentation
  • Avoid IDs
  • BEM syntax in Cantilever style
  • Prefix javascript-related classes with `JS__`
  • Allow, but do not overuse, special modifier and utility classes to support corner cases.
  • Double quotes
  • Be as ambitious as you can within your browser requirements
  • :: for pseudoelements
  • Carriage return after comma in selectors

The linter will bother you about most of this stuff.

Example

NB: This section is hastily written and will contain mistakes. Not actual code, used for demonstration purposes only :-)

A seminal example of how our system applies is a sidebar. An old-school method would do something like this:

<div id="main">
  <div class="header">
    My Header
  </div>
  
  <div class="content">
    My Page Content
  </div>
</div>

<div id="sidebar">
  <!-- First Sidebar Unit-->
  <div class="sidebar-newsletter">
    <h2 class="sidebar-heading">Sign up for our newsletter</h2>
    <img class="sidebar-thumb" src="..." />
    <p class="sidebar-main">It’s really great</p>
    <a href="#" class="sidebar-newsletter-signup">Click Here</a>
  </div>

  <!-- Second Sidebar Unit-->
  <div class="sidebar-social">
    <h2 class="sidebar-heading">Social Media</h2>
    <a href="#"><img class="social-icon" src="twitter.png">Twitter</a>
  </div>
</div>

<styles>
  body {
    display: flex;
  }

  #sidebar {
    margin-right: 16px;
    max-width: 25%;
  }

  .sidebar-newsletter,
  .sidebar-social {
    background: #ccc;
    color: #999;
    font-size: 12px;
    margin-bottom: 16px;
    color: #888;
  }

  .sidebar-social {
    margin-bottom: 0;
  }

  .sidebar-newsletter .sidebar-heading {
    margin-bottom: 8px;
    font-size: 18px;
  }

  .sidebar-social .sidebar-heading {
    font-size: 14px; // Special size for the social heading
  }

  .sidebar-newsletter .sidebar-thumb {
    margin: 8px 0;
  }

  .sidebar-social .social-icon {
    margin-right: 4px;
    width: 16px;
  }
</styles>

Let’s take out the id-based structure and replace it with a more flexible grid.

<div class="Grid">
  <div class="Grid__Cell">
    <div class="header">
      My Header
    </div>
    
    <div class="content">
      My Page Content
    </div>
  </div>
  <div class="Grid__Cell Grid__Cell--1of4">
    <div class="Grid">
      <div class="Grid__Cell Grid__Cell--1of1">

        <!-- First Sidebar Unit-->
        <div class="sidebar-newsletter">
          <h2 class="sidebar-heading">Sign up for our newsletter</h2>
          <img class="sidebar-thumb" src="..." />
          <p class="sidebar-main">It’s really great</p>
          <a href="#" class="sidebar-newsletter-signup">Click Here</a>
        </div>

      </div>
      <div class="Grid__Cell Grid__Cell--1of1">

        <!-- Second Sidebar Unit-->
        <div class="sidebar-social">
          <h2 class="sidebar-heading">Social Media</h2>
          <a class="sidebar-social-link" href="#"><img class="social-icon" src="twitter.png">Twitter</a>
        </div>

      </div>
    </div>
  </div>
</div>

<styles>
  .Grid {
    display: flex;
    margin: -16px 0 0 -16px;
  }

  .Grid__Cell {
    padding: 16px 0 0 16px;
  }

  .Grid__Cell--1of4 {
    max-width: 25%;
  }

  .sidebar-newsletter,
  .sidebar-social {
    background: #ccc;
    font-size: 12px;
    color: #888;
  }

  .sidebar-newsletter .sidebar-heading {
    margin-bottom: 14px;
    font-size: 18px;
  }

  .sidebar-social .sidebar-heading {
    font-size: 14px; // Special size for the social heading
  }

  .sidebar-newsletter .sidebar-thumb {
    margin: 8px 0;
  }

  .sidebar-newsletter-signup, .sidebar-social-link {
     font-size: 10px;
     color: blue;
  }
  .sidebar-social .social-icon {
    margin-right: 4px;
    width: 16px;
  }
</styles>

This grid is more flexible and generic. It would serve as the beginning of a full grid structure that can aid both in large-scale and intricate styling. It ensures unity of gutter sizes between areas of the page. With this grid in place, we do not need custom CSS rules so that the sidebar can have gutters. Good.

Now let’s deal with the sidebar units. Instead of one-off classes, let’s use a .Module element. These containers will provide spacing and alignment between the elements.

We have all sorts of font sizes and colors that need to be specified with these poor classes. Let’s make the headers more object-oriented, and move responsibility for the colors to the Modules.

Finally, we’ll make the CTA links and their icon a more general component that could be used anywhere.

<div class="Grid">
  <div class="Grid__Cell">
    
    <div class="header">
      My Header
    </div>
    
    <div class="content">
      My Page Content
    </div>

  </div>
  <div class="Grid__Cell Grid__Cell--1of4">

    <div class="Grid">
      <div class="Grid__Cell Grid__Cell--1of1">

        <!-- First Sidebar Unit-->
        <div class="Module">
          <div class="Module__Head">
            <h2 class="Heading Heading--Secondary">Sign up for our newsletter</h2>
          </div>
          <div class="Module__Row">
            <img class="FlexImage" src="..." />
          </div>
          <div class="Module__Row">
            <div class="TextBlock">
              <p>It’s really great</p>
            </div>
            <a class="CTALink" href="#">Click Here</a>
          </div>
        </div>

      </div>
      <div class="Grid__Cell Grid__Cell--1of1">

        <!-- Second Sidebar Unit-->
        <div class="Module">
          <div class="Module__Head">
            <h2 class="Heading Heading--Tertiary">Social Media</h2>
          </div>
          <div class="Module__Row">
            <a class="CTALink" href="#"><img class="CTALink__Icon" src="twitter.png">Twitter</a>
          </div>
        </div>
        
      </div>
    </div>
    
  </div>
</div>

<styles>
  .Grid {
    display: flex;
    margin: -16px 0 0 -16px;
  }

  .Grid__Cell {
    padding: 16px 0 0 16px;
  }

  .Grid__Cell--1of4 {
    max-width: 25%;
  }

  .Module {}

  .Module__Head + .Module__Row,
  .Module__Row + .Module__Row {
    margin-top: 8px;
  }

  .Module--Muted {
    background: #ccc;
    
  }

  .TextBlock {
    font-size: 12px;
    color: #888;
  }

  .Heading {
    font-weight: bold;
  }

  .Heading--Primary {
    font-size: 18px;
  }

  .Heading--Secondary {
    font-size: 14px;
  }

  .CTALink {
    font-size: 10px;
    color: blue;
  }

  .CTALink__Icon {
    margin-right: 4px;
    width: 16px;
  }
</styles>

This the Cantilever style. It is more verbose than the old-school method, but more flexible. Notice that no class says "sidebar" anymore – these classes do not care about their context. Notice that no class says "newsletter" or social – they don’t care about their content. If we wanted to use any part of the styles of the page in any other page, it would be simple. Most of these are actual component names we use in our projects.