#
Syntax & Formatting
Syntax and formatting are keys to a maintainable project. By keeping our code style consistent, we not only help ourselves debug faster but we're also lessening the burden on those who will have to maintain our code (maybe ourselves too!).
#
BEM Methodology
Entermedia uses a variation of the BEM methodology (Block, Element, Modifier) for standarizing class names. BEM’s strict naming rules can be found here.
Example component using the BEM methodology:
/* Block */
.block {
display: block;
}
/* Element */
.block__title {
font-weight: bold;
}
/* Block Modifier */
.block--modifier {
background-color: yellow;
}
.block--modifier .block-title {
font-size: 2rem;
}
#
Coding Standards
Entermedia uses stylelint to help developers avoid errors and enforce conventions in your styles. Use the configuration file below when setting it up in a new project (if needed).
{
"extends": "stylelint-config-sass-guidelines",
"plugins": ["stylelint-order", "stylelint-scss"],
"rules": {
"order/properties-alphabetical-order": true
}
}
Class names should only include one element level.
Don't
.block__title__subtitle {} .block__media__image {}
Do
.block__title {} .block__subtitle {} .block__media {} .block__media-image {}
Avoid camelcase class names.
Don't
.block__mediaImage {}
Do
.block__media-image {}
#
CSS Syntax
CSS syntax is not strict and will accept a lot of variations, but for the sake of legibility and fast debugging, we follow basic code styles:
- Write one selector per line
- Write one declaration per line
- Closing braces should be on a new line
Don't
.class-1, .class-2,
.class-3 {
width: 10px; height: 20px;
color: red; background-color: blue; }
Do
.class-1,
.class-2,
.class-3 {
background-color: blue;
color: red;
height: 20px;
width: 10px;
}
- Include one space before the opening brace
- Include one space before the value
- Include one space after each comma-separated values
Don't
.class-1,.class-2{
width:10px;
box-shadow:0 1px 5px #000,1px 2px 5px #ccc;
}
Do
.class-1,
.class-2 {
width: 10px;
box-shadow: 0 1px 5px #000, 1px 2px 5px #ccc;
}
- Try to use lowercase for all values, except for font names
- Zero values don't need units
- Always add
0
to units smaller than 1, i.e.0.5rem
- End all declarations with a semi-colon, even the last one, to avoid errors
- Use double quotes instead of single quotes
Don't
section {
background-color: #FFFFFF;
font-family: 'Times New Roman', serif;
margin: 0px
padding: .5rem;
}
Do
section {
background-color: #fff;
font-family: "Times New Roman", serif;
margin: 0;
padding: 0.5rem;
}
If you don't need to set all the values, don't use shorthand notation.
Don't
.header-background {
background: blue;
margin: 0 0 0 10px;
}
Do
.header-background {
background-color: blue;
margin-left: 10px;
}
#
Declaration Ordering
Declarations should be ordered alphabetically or by type (Positioning, Box model, Typography, Visual). Whichever order is chosen, it should be consistent across all files in the project.
If you're using Sass, use this ordering:
@extend
- Regular styles (allows overriding extended styles, alphabetical order)
@include
(to visually separate mixins and placeholders) and media queries- Nested selectors
#
Nesting
Nesting has changed the lives of many, but like everything in life, abusing good things will ultimately be bad. Nesting makes the code more difficult to read and can create confusion. Too much nesting also adds unnecessary specificity, forcing us to add the same or greater specificity in overrides. We want to avoid selector nesting and over-specificity as much as possible.
If you're using PostCSS or Sass nesting is required in the following cases, because it will make the code easier to read:
- pseudo-classes
- pseudo-elements
- component states
- media queries
#
Selector Naming
Selectors should be lowercase, and words should be separated with hyphens. Please avoid camelcase, but underscores are acceptable if they're being used for BEM or another syntax pattern that requires them. The naming of selectors should be consistent and describe the functional purpose of the styles they're applying.
Don't
.btnRed {
background-color: red;
}
Do
.btn-warning {
background-color: red;
}
For components that could possibly conflict with plugins or third-party libraries, use vendor prefixes. Don't use names that can be blocked by adblockers (e.g. “advertisement”). When in doubt, you can check a class name against this list to see if it's likely to be blocked.
#
Documentation
Code documentation serves two purposes: it makes maintenance easier and it makes us stop and think about our code. If the explanation is too complex, maybe the code is overly complex too. Documenting helps keep our code simple and maintainable.
#
Commenting
We follow WordPress official commenting standards. Do not hesitate to be very verbose with your comments, especially when documenting a tricky part of your CSS. Use comment blocks to separate the different sections of a partial, and/or to describe what styles the partial covers:
/**
* Section title
*
* Description of section
*/
For single selectors or inline comments, use this syntax:
/* Inline comment */
Make sure to comment any complex selector or rule you write. For example:
/* Select list item 4 to 8, included */
li:nth-child(n+4):nth-child(-n+8) {
color: red;
}
#
Performance
#
Network Requests
- Limit the number of requests by concatenating CSS files and encoding sprites and font files to the CSS file
- Minify stylesheets
- Use GZIP compression when possible Automate these tasks with a PHP or/and JavaScript build process
#
CSS Specificity
Stylesheets should go from less specific rules to highly specific rules. We want our selectors specific enough so that we don't rely on code order, but not too specific so that they can be easily overridden.
For that purpose, classes are our preferred selectors: pretty low specificity but high reusability.
Avoid using !important
whenever you can. Use efficient selectors.
Don't
div div header#header div ul.nav-menu li a.black-background {
background: radial-gradient(ellipse at center, #a90329 0%,#8f0222 44%,#6d0019 100%);
}
#
Inheritance
Fortunately, many CSS properties can be inherited from the parent. Take advantage of inheritance to avoid bloating your stylesheet but keep specificity in mind.
Don't
.sibling-1 {
font-family: Arial, sans-serif;
}
.sibling-2 {
font-family: Arial, sans-serif;
}
Do
.parent {
font-family: Arial, sans-serif;
}
#
Reusable Code
Styles that can be shared, should be shared (aka DRY, Don't Repeat Yourself). This will make our stylesheets less bloated and prevent the browser from doing the same calculations several times. Make good use of Sass placeholders. (also see
#
CSS Over Assets
Don't add an extra asset if a design element can be translated in the browser using CSS only. We value graceful degradation over additional HTTP requests.
Very common examples include gradients and triangles.
#
Animations
It's a common belief that CSS animations are more performant than JavaScript animations. A few articles aimed to set the record straight (linked below).
- If you're only animating simple state changes and need good mobile support, go for CSS (most cases).
- If you need more complex animations, use a JavaScript animation framework or
requestAnimationFrame
.
Limit your CSS animations to 3D transforms (translate, rotate, scale) and opacity, as those are aided by the GPU and thus smoother. Note that too much reliance on the GPU can also overload it.
Don't
#menu li{
left: 0;
transition: all 1s ease-in-out;
}
#menu li:hover {
left: 10px
}
Always test animations on a real mobile device loading real assets, to ensure the limited memory environment doesn't tank the site. Note: WCAG 2.1, Guideline 2.3.2 Motion from Animation dictates that, “Motion animation triggered by interaction can be disabled, unless the animation is essential to the functionality or the information being conveyed.”
#
Futher Reading
- CSS animations performance: the untold story
- Myth Busting: CSS Animations vs. JavaScript
- CSS vs. JS Animation: Which is Faster?
- Why Moving Elements With Translate() Is Better Than Pos:abs Top/left
- CSS vs JavaScript Animations
- requestAnimationFrame