Maintaining CSS
Keenan Bailles
Atomic CSS, BEM, Suit CSS, SMACSS, OOCSS, Enduring CSS, Systematic CSS, PostCSS, DoCSSa, Constraint CSS, AMCSS
“Writing CSS is easy. Maintaining CSS is hard.”
Talking Points
Two Competing Problems
Everyone Agrees on These
Suggested Conventions
CSS Tips
You can either make things
DRY
or
Reduce Coupling
DRY
- Reduced size of CSS (both in lines and size)
- No need to worry about HTML structure
- Classes highly reusable
DRY
- Very difficult to remove styles
- High barrier to entry. Does the class I need already exist? What classes are available to me?
DRY
Example using Atomic CSS:
@std-margin: 16px;
.mt-1 { margin-top: @std-margin; }
.mr-1 { margin-right: @std-margin; }
.mt-2 { margin-top: 2*@std-margin; }
.ov-h { overflow: hidden; }
.d-b { display: block; }
.va-m { vertical-align: middle; }
.fl-st { float: @float-start; }
.fl-nd { float: @float-end; }
.fw-b { font-weight: bold; }
.fs-i { font-style: italic; }
.headshot {
width: @headshot-dimension;
}
Reduce Coupling
- Easily remove unused styles
- Modify styles without fear
- No barrier to entry
Reduce Coupling
- Almost no code reuse
- Increased size of CSS (both in lines and size)
Everyone Agrees on These
- Enforce some kind of naming convention
- Organize your files into sensible places
- Use a CSS pre-processor that supports variables, basic math functions, and allows stylesheet composition
- Do not write vendor prefixes. Use a build tool such as Autoprefixer
- Stay away from specificity wars
- Rarely use location dependent styles
- Compress and minify your CSS
General
- DRY structure (box-sizing, float, height, margin, position, width, etc)
- Decouple skin (background, color, border, text-size, etc)
- Avoid nesting styles if possible (Overriding libraries is certainly an exception)
- Do not write vendor prefixes
- Avoid styling elements (eg h1 {})
- Besides general styles all styles should be connected to a class
- Take care in adding new utility classes
Naming Conventions
- Spinal casing for structure
- BEM for skin
Intro to BEM
BEM is a naming convention to do away with nesting selectors and increase awareness of the elements that are receiving styles. There are three categories in BEM:
Note: Under BEM methodology no style should be attached to an element.
Usual HTML/CSS Example:
.ul {}
.ul > li {}
.ul > li > a {}
BEM HTML/CSS Example:
.menu {}
.menu__item {}
.menu__link {}
File Organization
Organize files according to the UI design structure
Build Tasks
- Utilize Autoprefixer
- Use a CSS linter to catch unwanted rules
How the Browser Interprets CSS
Browsers read CSS right to left. Because of this, the rightmost selector is often called the "key selector"
There are four kinds of "key selector's": Id -> class -> tag -> universal. The order here is also the order of efficiency. Id's are much faster to process than a universal selector.
CSS Specificity
If two selectors target the same element the one with the higher specificity will win. If they have the same specificity then cascade.
Greatest specificity to lowest is: Inline -> Id -> Class/Psuedo-Class/Attribute -> Element/Psuedo-Elm. !important trumps everything. !important is only overridden with !important. That is why you should not use it.
Calculating Specificity
Selector
Value
Inline
1000
Id
100
Class/Psuedo-Class/Attribute
10
Element/Psuedo-Elm
1
Note: These do not operate as base 10 values. Each level is infinitely more specific than the next. This means, for example, no amount of classes can outweigh an Id.
Calculating Specificity
Example 1
ul#Nav li.active a {}
This selector contains 1 Id, 1 class/psuedo-class/attribute, and targets 3 elements. It's specificity would be: 0, 100, 10, 3.
Calculating Specificity
Example 2
#footer *:not(nav) li {}
This selector contains 1 Id, 0 class/psuedo-class/attribute (:not is a unique psuedo class in that it adds no specificity. What's inside the parens is what adds to the specificity), and targets 2 elements (Universal selector has a no specificity value). It's specificity would be: 0, 100, 0, 2.
General Tips
- Descendant selectors are the most expensive kind of selector
- As soon as a selector fails to match it stops trying. A descendant selector that has no match will be faster if the match fails on the "key selector"
- CSS is a render blocking resource (there are a few exceptions)
- All styles will be recalculated for each stylesheet downloaded and parsed by the browser, even if it has been cached
Maintaining CSS
Keenan Bailles