CSS Coding Style Guidelines
Like other languages, the idea behind these guidelines is to ensure:
- Your CSS is quickly comprehensible to other developers.
- Definitions, properties, and structure are predictable to ensure specific styles can be rapidly located and modified.
Keep in mind that this guide isn’t about the design or appearance of what you’re trying to style: it’s how to write the styles themselves, which is just as important!
High-level design considerations
- SCSS is preferred over pure CSS, when available. SCSS or “sass” is a CSS preprocessor that supports advanced syntax not available in pure CSS. Note that Sass can come in two flavors:
.scss
and.sass
. Stick to.scss
, since it’s closer to pure CSS. However, remember that SCSS is not supported by browsers out of the box! It must be compiled with build tools like babel or webpack before use. Chances are, if you’re working in a stack that includes a javascript framework, your JS and CSS assets will be running through build tools already. - Styles should always be provided in a standalone
.scss
or.css
file, imported at the top of the document via
<link rel="stylesheet" type="text/css" href="stylesheet.css">
- For particularly large applications with a lot of content to style, it’s reasonable and acceptable to split stylesheets into multiple sub-stylesheets. Use
@import 'path/to/stylesheet.css';
to link stylesheets together. The ways you may sub-divide stylesheets is more subjective; some examples might include:- Putting variable definitions in their own stylesheet that’s imported in the main sheet(s).
- If different pages inherit common styles, put the common styles in a standalone stylesheet that can be imported into all others.
- Some frameworks (like React) provide sensible boundaries for stylesheets, by having one for each component.
Style formatting considerations
Use variable definitions to establish common color palette, font families, dimensions, etc
Note: this is a feature of SCSS, not CSS. If you’re using pure CSS, you’ll have to skip this section.
These keep definitions in a single, predictable location, and makes it easier to consistently apply styles to elements across your application. They should always be defined at the top of your stylesheet.
$blue-accent: #49afd7;
$blue-hover: #bdecff;
$shadow-dialog: 0px 3px 3px $gray;
$shadow-small: 0px 0px 2px $gray;
$shadow-small-highlight: 0px 0px 5px $gray;
$z-index-hidden: -1;
$z-index-default: 0;
$z-index-behind-cover: 5;
$z-index-background-cover: 10;
$z-index-dialog-background-cover: 75;
Additionally, remember that variables can be assigned to other variables. Consider:
$gold: #b7951a;
$special-gold: ##e9cc63;
$white: #ffffff;
$blackish: #050505;
$color-primary: $blackish;
$color-accent: $gold;
This allows you to pre-assign colors (as an example), then establish a series of variables that provide more context to the way the colors can be used.
Nested styles
**Note:** only available in SCSS.
Nested styles are always preferred relative to standard CSS specificity:
When possible, do this:
selector {
.class {
&.adjacent-class {
}
}
}
Not this:*
selector {
}
selector .class {
}
selector .class.adjacent-class {
}
Nesting styles yields clear and concise hierarchy that’s much easier to understand.
Organization
When possible, organize your style properties by type. This is tremendously useful when having to navigate a large amount of styles at a glance:
selector {
// position properties & z-index
z-index:
position:
// display properties & flexbox
display:
justify-content:
// box model properties like width, height, margin, padding
width:
height:
margin:
padding:
// border properties
border:
// background properties & box-shadow
background:
// font properties
font-family:
color:
font-weight:
// other properties - text-alignment, cursor, etc
cursor:
// pseudoselectors applied to the same selector
&:hover {
}
&:focus {
}
// adjacent class selectors
&.other-selector {
}
// child selectors
.child-element {
}
}
Apply styles to the least specific selector possible, to avoid redundancy
Consider the following example:
.selector {
p {
&.special {
font-family: 'Lato', sans-serif;
}
&.error {
font-family: 'Lato', sans-serif;
}
&.highlight {
font-family: 'Lato', sans-serif;
}
}
}
Applying the same style to numerous sub-elements isn’t necessary, when the style can be applied once to a less specific selector:
.selector {
p {
font-family: 'Lato', sans-serif;
&.special {
// styles specific to the special class
}
&.error {
// styles specific to the error class
}
&.highlight {
// styles specific to the highlight class
}
}
}
Condensed notation is awesome sometimes
Certain properties like padding
and margin
accept shorthand notation that condenses multiple properties into one line. For example, this set of properties:
.selector {
margin-top: 10px;
margin-bottom: 8px;
margin-left: 12px;
margin-right: 12px;
}
Can be condensed into:
.selector {
margin: 10px 12px 8px 12px;
}
There are two variations of the shorthand property notation that can be used here, depending on whether the properties are symmetric:
// all four sides have different dimensions, or one dimension is different
margin: <top> <right> <bottom> <left>;
// horizontal and vertical dimensions are mirrored
margin: <vertical> <horizontal>;
Be aware that these sorts of condensed styles can lead to gotchas. Consider, for example:
p.selector {
margin: 10x 5px 5px 8px;
}
p {
margin-left: 12px;
}
Two different selectors are applying a left margin in two different ways. This makes it difficult to determine which selector may actually be applied.
Don’t use float
float
used to be one of the bread-and-butter properties in CSS styling, enabling advanced positioning beyond the standard box model. There are better options out there now, especially Flex Box. Seriously, that reference page is amazing. Bookmark it.
Don’t overuse absolute positioning
Using position: absolute
is an incredibly powerful tool, giving you complete control over an element’s position on the page. However, it can cause considerable issues with responsive designs, where the normal flow of elements on the page won’t be accounted for. Therefore, ensure you’re only leveraging absolute positioning when it’s actually necessary to do so.
Don’t use !important
!important
overrides CSS specificity rules by ensuring the style it’s applied to is the highest priority. However, it’s easy to abuse, and there are rarely legitimate reasons to use it. If you’re tempted to use !important
to solve a specificity problem, reconsider: it’s worth the extra time to format your styles in a way that allows lets you avoid it. Future you, and your coworkers, will thank you.
The Browser Inspector is Your Best Friend
Every modern browser has developer tools built-in, and most will have an Inspect
option available in the context menu when right-clicking an element on the page. Learning how to use the content inspector will save you hours and hours of frustration. When styling content, the inspector allows you to:
- View the styles being applied to an element, where they are sourced from, and whether they are being overridden by rules elsewhere.
- Modify styles in real-time, or apply new ones. These aren’t saved, but you have the opportunity to experiment quickly without going through the trouble of editing your stylesheets, saving, recompiling, reloading the page, and getting the page back into the state needed to view the elements in question.
- View the box model for a given element, to better determine properties like width, height, padding, and margin.