CSS Coding Style Guidelines

Like other languages, the idea behind these guidelines is to ensure:

  1. Your CSS is quickly comprehensible to other developers.
  2. 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!

Table of Contents

High-level design considerations

  • CSS preprocessors liks SCSS, SASS, and LESS are discouraged unless there are very specific features that you cannot accomplish with CSS. Most of their primary selling points (like nesting and variables) are now a part of base CSS.
  • 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

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: var(--blackish);
--color-accent: var(--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

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.