Skip to content

Instantly share code, notes, and snippets.

@maxparm
Created May 18, 2016 15:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maxparm/bb5827a57f44a7a205515f599d4f3477 to your computer and use it in GitHub Desktop.
Save maxparm/bb5827a57f44a7a205515f599d4f3477 to your computer and use it in GitHub Desktop.
Writing CSS - 7Geese

title: Writing CSS at 7Geese author: name: Maxime Parmentier twitter: maxparm url: http://maximeparmentier.com output: basic.html controls: true

--

Writing CSS at 7Geese

--

Goals

  • WIP to improve 7Geese's CSS
  • Review our CSS
  • Have a quick look at the industry standards and conventions
  • Provide tips and best practices on writing CSS
  • Let's practice!
  • Next steps to improve our CSS stack

--

The state of 7Geese's CSS

  • Lot of files
  • Complex organization and architecture of CSS files
  • Large file size
  • Gigantic CSS output
  • UI complexity (rules, conditions)
  • Multiple contributors: developers and designers

--

Problems

  1. Large codebase
  2. Daily updates
  3. CSS becomes unruly
  4. Difficult to maintain and iterate on
  5. Lack confidence to edit
  6. Contributors will add new rules instead of amending existing code
  7. Bloated CSS/redundant rules
  8. Increase of side effects

--

Needs

  • Easy maintenance of CSS codebase over time
  • Allow portions of CSS to be removed without affecting remaining style
  • Rapid iterations on new designs
  • Avoid side effects when updating properties

--

Currently at 7Geese

  • Use BEM with LessCSS
  • 117 css files in static/css
  • 379 with static/components
  • StyleStats
  • Complex folders structure

--

Folder Structure: Libraries

  • /static/components & /node_modules/** package manager libraries and framework
  • /static/css/vendors libraries and framework not in package manager, might be modified

--

Folder Structure: Base

  • /static/css/layout general layout css rules (grid, main container)
  • /static/css/utilities small reusable css rules (hiding)
  • /static/css/helpers less mixins and variables
  • /static/css/elements UI pieces that are re-used across the apps

--

Folder Structure: Apps

  • /static/css/deprecated-apps older apps css
  • /static/css/apps tight to apps in /static/js/apps
  • /static/js/apps/**/*.less

--

Existing Approaches

--

OCSSS (Object Oriented CSS)

  • Goals
    • Remove code duplications by creating set of CSS
    • Re-use existing styles as much as possible
    • Apply them as lego, Single Responsability Principle
    • Keep structure and theme separated (Position, Structure, Theme)
<a class="float-left warning margin-10">Maxime</a>

--

OCSSS

  • Problems
    • Bloated markup
    • Difficult to maintenance => lot of changes
    • Difficulties for responsive UI
<a class="float-left warning margin-10 media-small-margin-5">Maxime</a>

--

OCSSS

<div class="media margin">
    <a href="#" class="img">
        <img class="round" src="mini.jpg" />
    </a>
    <div class="small-text warning">@Stubbornella 14 minutes ago</div>
</div>
.img {display: block;}
.img .round {border-radius: 4px;}
.margin {margin: 10px;}
.media .img {padding: 5px;}
.small-text {font-size: 11px;}
.warning {color: red;}

--

ACSS (AtomicCSS)

  • Atoms, Molecules, Organisms, Templates, Page
  • OOCSS pushed to the extreme!
  • Made of only use reusable classes
  • One declaration by selector
.mt-20 {margin-top: 20px;}
.fl {float: left;}
.red {color: red;}
<a class="mt-20 fl red">error</a>

--

SMACSS (Scalable and Modular Architecture for CSS)

  • Similar to OOCSS, pretty vague...
  • Use #ids, html elements
  • Opiniated with folder structures
    • Base
    • Layout
    • Module
    • Themes
    • State (.is-)

--

BEM (Block Element Modifier)

  • .block__element--modifier
  • Part of the UI can be defined as blocks
<div class="media">
    <a href="#" class="media__img">
        <img class="media__headshot" src="mini.jpg" />
    </a>
    <div class="media__detail media__detail--warning">@Stubbornella 14 minutes ago</div>
</div>
.media {margin: 10px;}
.media__img {display: block; padding: 5px;}
.media__headshot {border-radius: 4px;}
.media__detail {color: #666; font-size:11px;}
.media__detail--warning {color: red;}

--

BEM (Block Element Modifier)

  • Goals
    • Naming convention communicates relation between elements. (.media__headshot)
    • Only classes, no IDs, no html: all elements have same specificity
  • Problems
    • Can be very verbose

--

ECSS (EnduringCSS)

  • Based on BEM
  • namespace-ModuleOrComponent_ChildNode-variant
  • No HTML elements, no IDS
  • Selectors are defined only once
  • Changes to components are handled via overrides

--

ECSS (EnduringCSS)

<div class="Media">
    <a href="#" class="Media_Img">
        <img class="Media_Headshot Media_Headshot-round" src="mini.jpg" />
    </a>
    <div class="Media_Detail Media_Detail-warning">@Stubbornella 14 minutes ago</div>
</div>
.Media {margin: 10px;}
.Media_Img {display: block; padding: 5px;}
.Media_Headshot {border-radius: 4px;}
.Media_Detail {color: #666; font-size:11px;}
.Media_Detail-warning {color: red;}

--

ECSS (EnduringCSS)

  • Embracing repetitions
    • components are isolated
    • start from scratch
    • gzip is efficient at compressing repetitive string
    • can use preprocessors and postprocessors to keep consistency in repetition
.warning {color: red;}
.objective-title--warning {color: red;}
.objective-description--warning {color: red;}

--

Best Practices

--

What is a CSS Rule

// this is a css rule
// it's made of selectors

.classSelector, #idSelector {
  // declaration block, list of declarations
  // property: value;
  color: red;
}

--

Specificity

--

Specificity

<div id="content">
    <div class="row">
        <p class="first">first</p>
        <p class="second">second</p>
    </div>
</div>
#content {
    color: black;
}
#content .row p {
    color: red;
}
.row p.first {
    color: blue;
}
#content .second {
    color: green;
}

What will be the color of first and second?

--

Specificity: Takeaways

  • Very problematic when using different types of selector
  • => Use no IDs, no element selectors, only classes
  • => Handle changes via overrides not by specificity
.title {
  color: black;
}
.title--warning {
  color: red;
}

--

Avoid markup in selectors

<div class="navbar">
  <ul>
    <li><a>item 1</a></li>
    <li><a>item 2</a></li>
    <li>
      <ul>
        <li><a>sub item 1</a></li>
      </ul>
    </li>
  </ul>
</div>
.navbar ul > li a {
  color: red;
}
.navbar ul > li > ul li a {
  color: green;
}

--

Avoid markup in selectors

  • Makes the selectors very specific
  • Maintainability difficult if you need to change markup
  • Difficult to re-use this declaration block: markup matching
  • Give a class name to each element: .navbar__item, .navbar__sub-item.

--

Avoid using additional specificity

h1.my-title {
  color: black;
}
  • add unwanted specificity
  • harder to then overrides in the future
  • KISS

--

How to name your selectors

  • Name the selector for what it represents
  • Not for how the css rule is going to affect the selector
.objective-title {
  color: black;
}
.red {
  color: red;
}
<a class="objective-title red">Due Objective</a>

--

How to name your selectors

.objective-title {
  color: black;
}
.objective-title--due {
  color: red;
}
<a class="objective-title--due">Due Objective</a>

--

Let's Practice!

--

Writing more efficiently with less

.objective {
    background: grey;
    &__name {
        color: blue;
        &--error {
            color: red;
        }
    }
    .homepage & {
        background: white;
    }
}

--

Don't nest!

<div class="video">
  <a class="video__title">Video Title</a>
</div>
.video {
    width: 200px;
    .video__title {
        font-weight: bold;
    }
}

will compile to

.video {
    width: 200px;
}
.video .video__title {
    font-weight: bold;
}

--

.video {
    width: 200px;
}
.video__title {
    font-weight: bold;
}
  • Additional specificity on .video__title (difficult to override)
  • Selector declaration block should be specific to their own rules and not contains other selectors' rules

--

Single Source of Truth

  • A selector should be mentionned only once in the css
    • easier to search for it
    • all the rules will be contained in that declaration block
  • Use & for nesting and referencing
.selector {
    width: 100%;
    .sidebar & {
        width: 50%;
    }
}

--

!important

  • Never use it! Especially to override another css rule.
  • Except for immutable css
.float-left {
  float: left!important;
}

--

What's next?

--

Folder structure

  • Where do we put things?
    • helpers/utilities => static/css/helpers where they be use as less mixins.
  • Create overrides folder (potentially put static/css/vendors files in it)
  • Move apps css in their application folder
  • Move /static/css/utilities/ to /static/css/helpers as less mixins
  • Clean /static/css/layouts/, lot of redundancies, move to elements

--

Linting

  • pre-commit lint
  • Lint BEM
  • Detect multiple selectors declaration blocks
  • Reduce IDs, most identifier selectors

--

No vendor prefixes in the css

  • Makes CSS more difficult to read
  • Managed by the postcss processor autoprefixer

--

Namespace Apps CSS Rules

.app-name__ {
  &ui-element-name {

  }
}

--

Takeaways

  1. Remove IDs and html elements => use .class
  2. Avoid markup structure in CSS => KISS
  3. Remove overqualified selectors => KISS
  4. Name selectors for what they represent
  5. Use &
  6. Don't nest
  7. Only one selector = one source of truth (easy to CRUD)
  8. Don't use !important

--

Resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment