Dropbox (S)CSS Style Guide
“Every line of code should appear to be written by a single person, no matter the number of contributors.” —@mdo
General
Don’ts
- Avoid using HTML tags in CSS selectors
- E.g. Prefer
.o-modal {}
overdiv.o-modal {}
- Always prefer using a class over HTML tags (with some exceptions like CSS resets)
- E.g. Prefer
- Don't use ids in selectors
#header
is overly specific compared to, for example.header
and is much harder to override- Read more about the headaches associated with IDs in CSS here.
- Don’t nest more than 3 levels deep
- Nesting selectors increases specificity, meaning that overriding any CSS set therein needs to be targeted with an even more specific selector. This quickly becomes a significant maintenance issue.
- Avoid using nesting for anything other than pseudo selectors and state selectors.
- E.g. nesting
:hover
,:focus
,::before
, etc. is OK, but nesting selectors inside selectors should be avoided.
- E.g. nesting
- Don't
!important
- Ever.
- If you must, leave a comment, and prioritise resolving specificity issues before resorting to
!important
. !important
greatly increases the power of a CSS declaration, making it extremely tough to override in the future. It’s only possible to override with another!important
declaration later in the cascade.
- Don’t use
margin-top
.- Vertical margins collapse. Always prefer
padding-top
ormargin-bottom
on preceding elements
- Vertical margins collapse. Always prefer
- Avoid shorthand properties (unless you really need them)
- It can be tempting to use, for instance,
background: #fff
instead ofbackground-color: #fff
, but doing so overrides other values encapsulated by the shorthand property. (In this case,background-image
and its associative properties are set to “none.” - This applies to all properties with a shorthand: border, margin, padding, font, etc.
- It can be tempting to use, for instance,
Spacing
- Four spaces for indenting code
- Put spaces after
:
in property declarations- E.g.
color: red;
instead ofcolor:red;
- E.g.
- Put spaces before
{
in rule declarations- E.g.
.o-modal {
instead of.o-modal{
- E.g.
- Write your CSS one line per property
- Add a line break after
}
closing rule declarations - When grouping selectors, keep individual selectors on a single line
- Place closing braces
}
on a new line - Add a new line at the end of .scss files
- Trim excess whitespace
Formatting
- All selectors are lower case, hyphen separated aka “spinal case” eg.
.my-class-name
- Always prefer Sass’s double-slash
//
commenting, even for block comments - Avoid specifying units for zero values, e.g.
margin: 0;
instead ofmargin: 0px;
- Always add a semicolon to the end of a property/value declaration
- Use leading zeros for decimal values
opacity: 0.4;
instead ofopacity: .4;
- Put spaces before and after child selector
div > span
instead ofdiv>span
Sass Specifics
Internal order of a .scss file
- Imports
- Variables
- Base Styles
- Experiment Styles
Example:
//------------------------------
// Modal
//------------------------------
@import "../constants";
@import "../helpers";
$DBmodal-namespace: "c-modal" !default;
$DBmodal-padding: 32px;
$DBmodal-background: #fff !default;
$DBmodal-background-alt: color(gray, x-light) !default;
.o-modal { ... }
// Many lines later...
// EXPERIMENT: experiment-rule-name
.o-modal--experiment { ... }
// END EXPERIMENT: experiment-rule-name
Variables
- Define all variables at the top of the file after the imports
- Namespace local variables with the filename (SASS has no doc level scope)
- eg
business_contact.scss
→$business_contact_font_size: 14px;
- eg
- Local variables should be
$snake_lowercase
- Global constants should be
$SNAKE_ALL_CAPS
Color
- Use the defined color constants via the color function
- Lowercase all hex values
#fffff
- Limit alpha values to a maximum of two decimal places. Always use a leading zero.
Example:
// Bad
.c-link {
color: #007ee5;
border-color: #FFF;
background-color: rgba(#FFF, .0625);
}
// Good
.c-link {
color: color(blue);
border-color: #ffffff;
background-color: rgba(#ffffff, 0.1);
}
Experiments
Wrap experiment styles with comments:
// EXPERIMENT: experiment-rule-name
.stuff { ... }
// END EXPERIMENT: experiment-rule-name
Rule Ordering
Properties and nested declarations should appear in the following order, with line breaks between groups:
- Any
@
rules - Layout and box-model properties
- margin, padding, box-sizing, overflow, position, display, width/height, etc.
- Typographic properties
- E.g. font-, line-height, letter-spacing, text-, etc.
- Stylistic properties
- color, background-*, animation, border, etc.
- UI properties
- appearance, cursor, user-select, pointer-events, etc.
- Pseudo-elements
- ::after, ::before, ::selection, etc.
- Pseudo-selectors
- :hover, :focus, :active, etc.
- Modifier classes
- Nested elements
Here’s a comprehensive example:
.c-btn {
@extend %link--plain;
display: inline-block;
padding: 6px 12px;
text-align: center;
font-weight: 600;
background-color: color(blue);
border-radius: 3px;
color: white;
&::before {
content: '';
}
&:focus, &:hover {
box-shadow: 0 0 0 1px color(blue, .3);
}
&--big {
padding: 12px 24px;
}
> .c-icon {
margin-right: 6px;
}
}
Nesting
- As a general rule of thumb, avoid nesting selectors more than 3 levels deep
- Prefer using nesting as a convenience to extend the parent selector over targeting nested elements. For example:
.block { padding: 24px; &--mini { padding: 12px; } }
Nesting can be really easily avoided by smart class naming (with the help of BEM) and avoiding bare tag selectors.
BEM
Block: Unique, meaningful names for a logical unit of style. Avoid excessive shorthand.
- Good:
.alert-box
or.recents-intro
or.button
- Bad:
.feature
or.content
or.btn
Element: styles that only apply to children of a block. Elements can also be blocks themselves. Class name is a concatenation of the block name, two underscores and the element name. Examples:
.alert-box__close
.expanding-section__section
Modifier: override or extend the base styles of a block or element with modifier styles. Class name is a concatenation of the block (or element) name, two hyphens and the modifier name. Examples:
.alert-box--success
.expanding-section--expanded
BEM Best practices
Don't @extend
block modifiers with the block base.
- Good:
<div class="my-block my-block--modifier">
- Bad:
<div class="my-block--modifier">
Don't create elements inside elements. If you find yourself needing this, consider converting your element into a block.
- Bad:
.alert-box__close__button
Choose your modifiers wisely. These two rules have very different meaning:
.block--modifier .block__element { color: red; }
.block__element--modifier { color: red; }
Selector Naming
- Try to use BEM-based naming for your class selectors
- When using modifier classes, always require the base/unmodified class is present
- Use Sass’s nesting to manage BEM selectors like so:
.block { &--modifier { // compiles to .block--modifier text-align: center; } &__element { // compiles to .block__element color: red; &--modifier { // compiles to .block__element--modifier color: blue; } } }
Namespaced Classes
There are a few reserved namespaces for classes to provide common and globally-available abstractions.
.o-
for CSS objects. Objects are usually common design patterns (like the Flag object). Modifying these classes could have severe knock-on effects..c-
for CSS components. Components are designed pieces of UI—think buttons, inputs, modals, and banners..u-
for helpers and utilities. Utility classes are usually single-purpose and have high priority. Things like floating elements, trimming margins, etc..is-, .has-
for stateful classes, a la SMACSS. Use these classes for temporary, optional, or short-lived states and styles.._
for hacks. Classes with a hack namespace should be used when you need to force a style with!important
or increasing specificity, should be temporary, and should not be bound onto..t-
for theme classes. Pages with unique styles or overrides for any objects or components should make use of theme classes.
Separation of Concerns (One Thing Well™)
You should always try to spot common code—padding, font sizes, layout patterns—and abstract them to reusable, namespaced classes that can be chained to elements and have a single responsibility. Doing so helps prevent overrides and duplicated rules, and encourages a separation of concerns.
// Bad code
// HTML:
// <div class="modal compact">...</div>
.modal {
padding: 32px;
background-color: color(gray, x-light);
&.compact {
padding: 24px;
}
}
// Good code
// HTML:
// <div class="c-modal u-l-island">...</div>
// <div class="c-modal u-l-isle">...</div>
// components/_modal.scss
.c-modal {
background-color: color(gray, x-light);
}
// helpers/_layout.scss
.u-l-island {
padding: 32px;
}
.u-l-isle {
padding: 24px;
}
Media Queries
Media queries should be within the CSS selector as per SMACSS
.selector {
float: left;
@media only screen and (max-width: 767px) {
float: none;
}
}
Create variables for frequently used breakpoints
$SCREEN_SM_MAX: "max-width: 767px";
.selector {
float: left;
@media only screen and ($SCREEN_SM_MAX) {
float: none;
}
}