TGAM Pattern Library Documentation

Browse the pattern library website

CSS methodologies

Although Panther does not require you to organize your CSS in any particular way, we’ve chosen to author our UI component CSS using the following methodologies:

BEM

We use BEM with Harry Roberts’ modified class-naming syntax. Please read the following articles to familiarize yourself with BEM and Harry Roberts’ style:

ITCSS

The CSS in this project is organized according to the ITCSS (Inverted Triangle CSS) methodology. If you aren’t already familiar with ITCSS, please watch this video.

Import order

ITCSS is primarily concerned with CSS selector specificity, and it’s goal is to reduce or eliminate the need to override CSS. In order for it to perform its magic, you must organize your CSS into the following categories. Each category is numbered and corresponds to a layer in the inverted triangle diagram:

  \ ------------------------------------ /
   \              Settings              /
    \ -------------------------------- /
     \             Tools              /
      \ ---------------------------- /
       \          Generic           /
        \ ------------------------ /
         \          Base          /
          \ -------------------- /
           \      Objects       /
            \ ---------------- /
             \   Components   /
              \ ------------ /
               \   Trumps   /
                \ -------- /
  1. Settings
    Global variables, site-wide settings, config switches, etc.
  2. Tools
    Site-wide mixins and functions.
  3. Generic
    “Ground-zero” styles. Low-specificity, far-reaching rulesets (e.g. normalize, resets, box-sizing).
  4. Base
    Unclassed HTML elements (type selectors: a {}, blockquote {}, address {}, etc.)
  5. Objects
    Objects, abstractions, and “cosmetic-free” design patterns (e.g. .o-media {}).
  6. Components
    Designed components. Discrete, complete chunks of UI (e.g. .c-carousel {}).
  7. Trumps
    High-specificity, very explicit selectors. Overrides and helper classes (e.g. .u-hidden {}).

InuitCSS is a CSS framework that employs ITCSS principles. You can browse through its codebase for inspiration. InuitCSS’ ITCSS layers are similar to our own.

Differences between Objects and Components

Components are responsible for displaying themselves, and nothing more. They shouldn’t need to know anything about the context in which they appear. Objects can be used to govern layout, whereas components are meant to be discrete, standalone “lego blocks” that can be used anywhere.

In the following example, the o-container object creates a layout context for the c-button component. The c-button doesn’t attempt to position itself in any way. Instead, it leaves that job to the o-container object:

<div class="o-container">
  <button class="c-button">Click me!</button>
</div>
.o-container {
  padding: 10px;
  border: 1px solid black;
}
.c-button {
  background-color: blue;
  color: white;
}

Media queries

Unfortunately, media queries are only able to provide information about the viewport’s dimensions and not the dimensions of individual elements on the page. This presents a challenge because our pattern library components could be nested inside of elements that are less wide than the viewport (i.e. sidebar columns, grids, etc.). Our components possess no knowledge of the dimensions of their containers, so we’re forced to target our media queries to the global viewport scope. This article describes the problem in more detail.

Someday, when CSS element/container queries exist (or we decide to use a JavaScript “prolyfill”), we’ll be able to write truly encapsulated components. Until then, we’ll have to define our patterns’ breakpoints in higher-level, parent container contexts. For example:

Contents of patterns/stylesheets/foo.scss:

.foo {
  display: flex;
  align-items: flex-start;
}
.foo__body {
  flex: 1;
}
@mixin foo-narrow {
  .foo {
    display: block; // Stack elements in a single column
  }
}

Contents of specimen-assets/foo/style.scss:

@media all and (max-width: 650px) {
  .left-column {
    @include foo-narrow;
  }
}

Instead of defining a media query inside of the pattern SCSS itself, we provide a mixin that external SCSS can @include when we need to put the pattern into the “narrow” state (since the pattern itself isn’t capable of knowing when this needs to happen).

Resources

You may find it helpful to refer to the following resources for ideas on how to organize your CSS: