title: Writing CSS at 7Geese author: name: Maxime Parmentier twitter: maxparm url: http://maximeparmentier.com output: basic.html controls: true
--
--
- 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
--
- 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
--
- Large codebase
- Daily updates
- CSS becomes unruly
- Difficult to maintain and iterate on
- Lack confidence to edit
- Contributors will add new rules instead of amending existing code
- Bloated CSS/redundant rules
- Increase of side effects
--
- 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
--
- Use BEM with LessCSS
- 117 css files in
static/css
- 379 with
static/components
- StyleStats
- Complex folders structure
--
/static/components
&/node_modules/**
package manager libraries and framework/static/css/vendors
libraries and framework not in package manager, might be modified
--
/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
--
/static/css/deprecated-apps
older apps css/static/css/apps
tight to apps in/static/js/apps
/static/js/apps/**/*.less
--
--
- 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>
--
- 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>
--
<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;}
--
- 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>
--
- Similar to OOCSS, pretty vague...
- Use #ids, html elements
- Opiniated with folder structures
- Base
- Layout
- Module
- Themes
- State (.is-)
--
.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;}
--
- Goals
- Naming convention communicates relation between elements.
(
.media__headshot
) - Only classes, no IDs, no html: all elements have same specificity
- Naming convention communicates relation between elements.
(
- Problems
- Can be very verbose
--
- Based on BEM
namespace-ModuleOrComponent_ChildNode-variant
- No HTML elements, no IDS
- Selectors are defined only once
- Changes to components are handled via overrides
--
<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;}
--
- 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;}
--
--
// this is a css rule
// it's made of selectors
.classSelector, #idSelector {
// declaration block, list of declarations
// property: value;
color: red;
}
--
- IDs, classes, elements are interpreted differently by browser according to W3C
- Determines which CSS rule is applied
- Highest specificity wins
- Inline Style > #ID > .class > element
- CSS specificity: things you should know
- Specificity Calculator, CSS Specificity Star Wars
--
<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?
--
- 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;
}
--
<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;
}
--
- 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
.
--
h1.my-title {
color: black;
}
- add unwanted specificity
- harder to then overrides in the future
- KISS
--
- 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>
--
.objective-title {
color: black;
}
.objective-title--due {
color: red;
}
<a class="objective-title--due">Due Objective</a>
--
--
.objective {
background: grey;
&__name {
color: blue;
&--error {
color: red;
}
}
.homepage & {
background: white;
}
}
- The power of
&
- Output
--
<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
--
- 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%;
}
}
--
- Never use it! Especially to override another css rule.
- Except for immutable css
.float-left {
float: left!important;
}
--
--
- 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
--
- pre-commit lint
- Lint BEM
- Detect multiple selectors declaration blocks
- Reduce IDs, most identifier selectors
--
- Makes CSS more difficult to read
- Managed by the postcss processor autoprefixer
--
- Avoid side effects
- WIP with react and css modules
.app-name__ {
&ui-element-name {
}
}
--
- Remove IDs and html elements => use
.class
- Avoid markup structure in CSS => KISS
- Remove overqualified selectors => KISS
- Name selectors for what they represent
- Use
&
- Don't nest
- Only one selector = one source of truth (easy to CRUD)
- Don't use !important
--