While at CSSDevConf 2015, I also took a workshop from Jonathan Snook. He helped lead the Yahoo! Mail redesign and works at Shopify as a lead front-end engineer.

He developed the SMACSS philosophy and has an e-book on the topic.

Intro

SMACSS is:

  1. Categorization
  2. Naming Convention
  3. Decoupling CSS from HTML (minimize side effects of CSS we write)
  4. State-based Design

Categorization

Base

These HTML elements will always get this style

Maybe fonts, default paddings

Not a fan of CSS reset

  • Only write the CSS when I need it (end up with smaller code base)
  • Grid systems: most of it is not used
  • Normalize: normalizes video, html5 elements, many others
  • Don't just throw stuff in

Layout

Usually simple, keep it at the high level (header, content, sidebar, footer)

Module

90 to 95% of your project
Logos, navigation, modals, media objects

  • Contain content
  • Each module is an interface that your users have to learn
  • Each module is a code that has to be written, delivered and maintained

If you have too many modules, your site is too complex
Users have to re-learn new things

Module Variations (sub modules)

E.g. Buttons

Start with a common base
Maybe same rounded corners, same font, size

Make variations from there
BG color, FG color

Sometimes removing borders or increasing size/padding

Module child elements (sub components)

E.g. a Modal is the parent, and the child elements are the title, content inside

How deep should a module be?
If we go too deep, should refactor and make into other components

Goals of Modules

  • Isolate modules from each other
  • Prevent styles from bleeding out, others from bleeding in

Recognize similar patterns across different places. Good example at Shopify:

date picker in reports
filter UI
contact cards on hover

They all had a popover/dropdown with rounded corners, shadow and little divet at the top. So the above all share this one module, and contain other module(s) inside them

CSSCSS (redundancy checker tool)

State

Can effect layout changes (a hamburger sidebar menu)
Open, closed, active, disabled, default, shown, hidden

  • Like a module variation, but indicates a JavaScript dependency

Theme

Many folks do not have to worry about theming

Simplified down to 6 colors per theme

primary
darker
darkest
lighter
lightest
disabled

  • Only for on-the-fly style changes
  • Usually aren't needed (preprocessors can help)

CSS preprocessors can help with colors, for example if I want to have 50 shades of grey for my project...

  • Categorization allows for identifying patterns

Naming Conventions

Base: no names, just use semantic DOM elements
Layout: always use layout prefix

.layout--header {}
.layout--content {}
.layout--sidebar {}

Use class over ID always. CSS will style all things by that ID (doesn't enforce or care if there is only one)

Go with .link-danger rather than .link-cancel (to allow re-use)

Module: no prefix of "module", since its 95% of code

In modules: does not include hyphens (listview, tab, tabpanel)

Module Variations: use the module prefix, and no hypens in variation name (.btn, .btn-large, .btn-small)

Sub Modules: use the module prefix and no hyphens (.modal, .modal-body, .modal-footer)

State: use an is prefix, indicates js dependency (.is-btn-active, .is-btn-disable)
new naming he prefers, put it after module (.btn-is-active, .btn-is-disable)

  • Indicates togglable state
  • States specific to a module should include module name

Global states:

/*able to be applied to multiple modules*/
.is-selected {}  

Themes:

.theme-header {}
.theme-border {}
.theme-background {}

Text:

.text-xl { font-size: 140%; }
.text-l { font-size: 120%; }
.text {}
.text-s { font-size: 90%; }
.text-sx { font-size: 80%; }

Not covered in the book:

Prefix for versioning or packaging

Sometimes need to add a prefix to all styles using post-processing

Yahoo made PureCSS (out of SmacCSS philosophy) (everything is prefixed with "post-")

During redesign process

Two modules in same project

.next-btn {}

.next-btn-is-active {}
.next-btn-is-disabled {}

CSS in JavaScript/React

Naming conventions are the important thing there too, regardless of what your team comes up with

Hard to minify CSS (cant just change the classes, since you need to control all the HTML/JS)

Recap naming

.modulename
.modulename-submodule
.modulename-subcomponent

Variations in naming (BEM style):

.module-name
.module-name--sub-module
.module-name__sub-component

Using camel case:

.moduleName
.moduleName-subModule
.moduleName--subComponent
  • Layouts specify widths and margins
  • Modules expand to fill layouts
  • states are !important (only)

Questions & Answers

Try to mitigate change

  • Describe things for what they do, not their context
  • Ask the designer why it's highlighted, or why there's extra padding, or why the font is bigger, etc

When is it Base?

// Some comment mistakes:
<button>
<table>
<input>
  • Don't over-styleize the above when it should just be a module
  • Base file should be very minimal
  • If you have to unstyle things, you're doing things in the wrong place (bootstrap!!)

More on specificity

  • Goal is 1 selector
  • One selector and a descendant selector, okay too
.comment-author {}
.comment-number > a {}

State

When having 3+ states (not just boolean) and they can only be in one state at a time (for example you don't want to support pressed + disabled):

.button[data-state=default] {}
.button[data-state=pressed] {}
.button[data-state=disabled] {}

Include media queries with the file they effect (whether layout or modules)

Preprocessors

CSS Panic

Prototyping

  • Build and test individual components
  • Allow for front-end development independing of engineering team/cycle

doc / styleguide generators:
dexy.it
snk.ms/23 - collection of style guides

===
Exercises

5by5.tv

Exercise 1

Identify layout sections (and class names)

Layout

  • Header
  • Hero (Highlight Zone)
  • Content
  • Sidebar
  • Footer
  • Layout-constrained (applied to each section since fixed width)

Grid system supported 4 & 5 columns

Exercise 2

5 possible modules, and their class names

NavBar
ListHeading
List
ShowCover
SocialIcon

what do you call the container w/ body
when you already have boxes, you could call pod

Exercise 3

engagdge nav structure

SASS:

/* nav.scss */
.nav {}
.nav > li {}

.nav > li > a {}
.nav > li > a.is-active {}

/* menu.scss */
.menu {}
.menu-horizontal {}


/* card.scss */
.card {}
.card-image {}
.card-title {}

/* rating.scss */
.rating {}


/* button.scss */
.button {}
.button-with-more {}
.button-is-active {}

HTML:

<ul class="primarynav">
	<li>
		<a href=""></a>
		<div class="primarynav-canexpand">
  		  <div class="megamenu">
			<ul>
			  <li>
			    <a href="#" class="reviewcard">
			      <span class="rating">92</span>
			      <span class="reviewcard-title"></span>
			    </a>
			</ul>
			<ul>
			  <li>
			    <a href="#" class="chiclet"></a>
		     </li>
		    </ul>
		  </div>
		</div>
	</li>
	<li>...</li>
	<li>...</li>
	
	<li>
      <a href=""></a>
      <div class="...">
			<input />
		</div>
	</li>
	<li>
		<a href=""></a>
		<ul>
			<li></li>
			<li></li>
		</u>

One solution to reduce dependencies:

.primarynav-has-dropdown {}

OR

.primarynav-canexpand {}

Always keep modules in separate DOM elements (even if not needed technically at the moment - single responsibility principle, separate of concerns)