Skip to content

Instantly share code, notes, and snippets.

@charliepark
Last active June 5, 2021 15:03
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save charliepark/7669673 to your computer and use it in GitHub Desktop.
Save charliepark/7669673 to your computer and use it in GitHub Desktop.

Some key quotes:

SMACSS has two core goals: 1. Increase the semantic value of a section of HTML and content. 2. Decrease the expectation of a specific HTML structure.

SMACSS is about identifying the patterns in your design and codifying them.

Five Types of Categories of Code

  1. Base
  • the default style
  • single-element selectors (body{})
  1. Layout
  • divide the page into sections
  • not reusable on a single page
  • start with ".l-"
  1. Module
  • reusable, more modular
  1. State
  • for changeable things
    • collapsible / expandable navs
    • favorite / not a favorite
  • how does this item look at this moment?
  1. Theme
  • might not be necessary
  • skins and other changes based on some special condition

Naming Rules

(merge this with notes from before; starting on p. 13)

Layout

Laying out major sections is different from laying out minor sections of the page. Major sections are Layout elements; Minor sections are Modules.

One way to think about them is to use IDs for major sections, since they're only coming up once per page:

  • #header
  • #article
  • #footer

(Arguably, since those are all HTML elements, might be better just to go with the raw element. NBD, though.)

Sometimes a major section might need to be modified in some way, like an #article section that might need to be full-width on some pages: .l-no-sidebar #article

Note the presence of the .l- to indicate that it's NOT a module, but, rather, a layout block.

He gives an example layout, from CNN. Showing the grid of "featured" stories. I can see how he approached it, but I'm not yet convinced his naming scheme is necessary.

Modules

More discrete component of the page.

  • navigation bars
  • search boxes
  • login forms

Each should be designed to exist as a standalone obejct.

Will often have a child selector or hierarchy to scope it.

It's a good idea to avoid element selectors, like ".fld span" since you might need spans for other things down the road

Sub-Classing

You're overriding a base class with a more specific sub-class.

So normally, you'd have "class='pod '" class, now you might have "class='pod pod-constrained' "

Again, this is describing the thing that the class is being applied to, not the location on the page.

In the CSS file, you can make sure you're scoping it by writing the CSS like this:

.pod{}

.pod.pod-constrained{}

Not mentioned in the text, but worth noting: With Sass, you can move that to the CSS file, and have the following: .pod { } .pod-constrained { @extend .pod }

State Rules

States override generic styles. They're used in cases where the visual state of a component on the page can change, often based on a user's activity.

For example, a navigation tree that can expand out might be in a default "is-collapsed" state or in an "is-expanded" state. It's probably simpler to simply use a default and an alternate. That is, the default, collapsed state, is the normal setup, and if there's an "is-expanded" class, that gives additional rules.

Or a form input might have an "is-error" state.

A few distinctive elements about State rules:

  • They indicate a JavaScript dependency.
  • They can apply to either layout classes or module classes.

Unlike most CSS scenarios, you'll often need to use "!important" in your CSS rules to override other, existing classes with a greater specificity. Don't use it unless you need to, but if you need to, use it.

If a state needs to be scoped to a specific module, include that module's name in the state's classname setup. Example:

#nav {}
#nav.is-expanded{}

That way, you won't have a collision with something else, like:

.article-meta-info{}
.article-meta-info.is-expanded{}

Theme Rules

Themes

Themes are uncommon, but need to override defaults. Think: seasonal branding, special announcements, etc.

As Snook explains it, the theme files simply have the same class names, but you define the specific colors and other changes in the theme file, not in the core module file. I think it might be easier to keep the default color set in the core file, but to have an override in the theme file, using some parent class. So, for example, you could have a class of "holiday" or whatever that you apply to the body element.

// in sidebar.css
    .callout {
        border: 4px solid #333
    }

// in theme-holiday.css
    .holiday .callout {
        border-color: #fcc
    }

Typography

Fonts will affect base, module, and state styles, but since fonts aren't a part of layout, they shouldn't be present in layout styles. Snook implies that typography would be defined within those (base, module, state), but NOT in an external typography style file. The typography file would be for when you have internationalization or other unusual situations to handle.

You should not have more than 3 - 6 font sizes in your project. More than 6 and your users aren't going to notice and you're just making your site harder to maintain.

Changing State

State changes are handled in one of three ways:

  1. class name - change happens with JavaScript
  2. pseudo-class - change
  3. media query - change happens based on what kind of device / dimensions the page loads on

Snook advocates for state changes where the interacted-with element (say, the dropdown item or button) is the thing that takes the ".is-active" class, and its sibling is the thing that then gets modified. So, for example, instead of adding "is-active" to a parent element, you'd apply it to the button. And instead of a descendent CSS control, you'd have it set on a sibling.

.btn.is-active + .menu {display: block}

Snook discusses the possibility of using data- attributes to define state.

.btn[data-state=default]{opacity: .85}
.btn[data-state=disabled]{opacity: .5;pointer-events: none}
.btn[data-state=pressed]{opacity: 1}

I like that, as it doesn't cloud up the element with classes.

Media Queries

With SMACSS, the goal is to keep styles that pertain to a module together, whether they're for desktop or for mobile, or for anything else. So instead of having one "mobile" stylesheet where you duplicate classes, you'd have media queries peppered throughout, with each module getting its own media query.

Depth of Applicability

It's important to minimize the number of classes you invoke in each CSS rule, for two reasons:

  1. If the HTML changes, the CSS breaks
  2. You can't re-use components as easily, so you duplicate your CSS.

Selector Performance

(Nothing super-new in here.)

Use Google Page Speed. The style of an element is evaluated on element creation. CSS gets evaluated from right to left.

Key: The evaluation of any more than a single element to determine styling is inefficient.

That isn't always practical. We don't want to end up with a class applied to every paragraph tag. (Right?)

Snook has three rules:

  1. Use child selectors.
  2. Avoid tag selectors for common elements.
  3. Use class names as the right-most selector.

At the same time, Steve Souders, who focuses on performance, notes that CSS isn't a high-value target for optimization, so don't waste too much time on it.

HTML5 and SMACSS

SMACSS has two core goals:

  1. Increase the semantic value of a section of HTML and content.
  2. Decrease the expectation of a specific HTML structure.

HTML5 plays very nicely with those goals.

Instead of framing a set of list items as .nav-primary li {display: inline-block} or .nav-secondary li {display: block} Set them as .l-inline-list li {display: inline-block} .l-stacked-list li {display: block}

Prototyping

SMACSS is about identifying the patterns in your design and codifying them. So are prototypes.

Goals of a prototype

  • show states
  • review localization
  • isolate dependencies

At Yahoo! they built a prototype engine to dynamically generate prototypes.

Maybe a prototype isn't necessary, but an easy-to-review format is really helpful. Perhaps just a document showing the various styles used for the site, and the code required for each module.

Preprocessors

The good: variables, functions, extend directives. The bad: too-deep nesting, @extending across modules, overused mixins.

SMACSS extensions

Handle extensions at the HTML level, not the CSS level. Define multiple classes in the HTML.

<a class="btn btn-default">button</a>

Snook encourages putting common thematic elements into their own classes that you can call, stacking classes in the HTML. So, for example, .theme-border{}

Media Queries + Nesting

As in the IFTTT code, Snook recommends splitting media queries throughout, and nesting them under their parent elements. His example:

.nav > li {
    width: 100%;

    @media screen and (non-width: 320px){
        width: 100px;
        float: left;
    }
    @media screen and (min-width: 1200px) {
        width: 250px;
    }
}

Organizing Your Files

  • Place all Base rules into their own file.
  • Major Layouts can either go into one big file, or several smaller files.
  • Each module should go in its own file.
  • Sub-modules should go in their own files.
  • Global styles should go in their own files.
  • Layout and Module States (including media queries that affect those layouts and modules) should go into the layout and module files.

You'll also need a master file that collects the other files.

Drop the Base

A few elements should be defined at the base-level.

Table

It's tempting to just declare a single table style, on the bare element. Don't do this.

Each table is a module. Treat it as such.

Specify child selectors to keep the impact as small as possible.

Buttons and Inputs can often suffer the same fate.

The litmus: Does this style serve a particular purpose? If so, create a specific module.

The Icon Module

Classic approach with sprites: .menu{} .menu-home{} .menu-mail{} etc.

Problematic in a few ways.

  • over-reliance on li{}
  • sprites had to be redefined in other modules to be used elsewhere
  • bumping up font size could break the layout as more sprites came into view

Now icons are their own modules" <> Inbox</>

Why three different classes? Each has a slightly different purpose.

/* turn the <i> into an inline-block element */
.ico {
    display: inline-block;
    background: url(/img/sprite.png)
    no-repeat;
    line-height: 0;
    vertical-align: bottom;
}

/* set the height and width */
.ico-16 {
    height: 16px;
    width: 16px;
}

/* define which icon shows through */
.ico-inbox {
    background-position: 20px 20px;
}
.ico-drafts {
    background-position: 20px 40px;
}

So as we think about Channel icons for IFTTT, one way to display them would be to have: channel-icon channel-icon-40 channel-icon-facebook

Complicated Inheritance

table/calendar example

Takeaway: inheritance can wreak some havoc on our well-laid plans' there isn't always a perfect solution.

Not sure why he's relying on "is-selected" as a tr class instead of a more descriptive "current-week".

Formatting Code

Snook's approach:

  • single-line per rule; this can get nasty with lots of CSS vendor prefixes; also tough with a large team
  • space after the colon
  • four-space indent
  • properties grouped by type
  • opening bracket on same line as rule set
  • colors use short form when possible

Organizes in the flowing order:

  1. Box
  • display, float, position, left, top, height, width, etc.
  1. Border
  • border, border-image, border-radius
  1. Background
  • background, background-color, background-image, background-size, etc.
  • can get pretty large, esp. w/ vendor prefixes, gradients, etc.
  1. Text
  • font-family, font-size, text-transform, letter-spacing, etc.
  1. Other
  • everything else

Color Declarations

3-digit or 6-digit hex codes, not text names. Also, rgba or hsla are options.

(Doesn't factor in Sass.)

Naming: How would you file this in a folder?

- .team-bios
  .team-member
    .team-member__photo
    .team-member__name
    .team-member__twitter-username

.article
  .article__head
    .article-headline
    .article-date
    .article-byline
  .article__body
    .article-copy

Criticisms of SMACSS

  • naming convention should have element built-in .comparison{} should be .table-comparison{}

  • doesn't leverage the power of Sass, namely @extend

    • so much could be simpler
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment