CSS is arguably one of our most used languages at Old Town Media and the performance and technical debt of each site we build is largely dependent on how well it's written. Stylization and organization are very important aspects of this and are heavily discussed here.

Syntax

CSS Syntax is important for readability and for future maintainability. We have to be able to read and easily understand each others' code and adhering to these best practices will help both of those.

  • Write one selector per line
  • Write one declaration per line
  • Closing braces should be on a new line
  • Adjacent and child selectors should have a line above them

Avoid

.class-1, .class-2,
.class-3{
width: 10px; height: 20px;
color: red; background-color: blue; }
.class-4{ width:100%; }

Prefer:

.class-1,
.class-2,
.class-3{
    width: 10px;
    height: 20px;
    color: red;
    background-color: blue;
}

.class-4{
    width: 100%;
}
  • Include one space before each value
  • Include one space after each comma in separated calls

Avoid

.class-1,.class-2{
    width:10px;
    box-shadow:0 1px 5px #000,1px 2px 5px #ccc;
    color:rgba(0,0,0,.5);
}

Prefer:

.class-1,
.class-2{
    width: 10px;
    box-shadow: 0 1px 5px #000, 1px 2px 5px #ccc;
    color: rgba( 0, 0, 0, .5 );
}
  • Try to use lowercase for all values, except for font names
  • Zero values don't need units
  • End all declarations with a semi-colon, even the last one, to avoid error
  • Use double quotes instead of single quotes

Avoid

.class-1{
    background-color: #FFFFFF;
    font-family: 'Times New Roman', serif;
    margin: 0px
}

Prefer:

.class-1{
    background-color: #fff;
    font-family: "Times New Roman", serif;
    margin: 0;
}
  • If you only need to set one value, don't use the shorthand notation.
  • However, If you need to set three or more values, do use the shorthand notation.

Avoid

.header-background{
    background: blue;
    margin: 0 0 0 10px;
    font-family: "Arial Bold";
    font-size: 16px;
    line-height: 1;
    font-weight: 400;
}

Prefer:

.header-background{
    background-color: blue;
    margin-left: 10px;
    font: 400 16px/1 "Arial Bold";
}
  • Use indenting to signify child status
  • Use 4-space tabbed indents for consistency

Avoid

.header{
}

.contactinfo{
}

.phone{
}

Prefer:

.header{
}

    .contactinfo{
    }

        .phone{
        }

Selector naming & specificity

Selectors should be named descriptively and classes should be used whenever possible.

Styles should avoid being over specified. When you over-specify styles it becomes difficult to override them in the future and affects maintainability. See here for more information on calculating specificity.

Use classes, avoid IDs unless absolutely necessary, and don't over-qualify selectors by using elements adding-on to your classes.

Avoid

html body div#pagewrap ul#summer-drinks li.favorite{}
.staff-listing .staff{}

Prefer:

.favorite{}
.staff-listing{}
.staff{}

Commenting

Comments should be used liberally to describe each individual section of CSS with at least a title describing it. For more complex sections, a small explanation of the code is also encouraged.

/**********************\
     Section title

Description of section (if necessary)
\**********************/

For single selectors or inline comments, use this syntax:

// Inline comment

Inline styles

Don't inline styles. Not kidding.

Seriously, don't do it.

Sass

At Old Town Media we use the sass library to make writing css quicker and more efficient. We use local compilers to concatenate/minify files and run libraries such as auto-prefixer upon compilation. This allows us to keep our stylesheets to one request while organizing the code in an easy-to-read and efficient way.

File Organization

We follow a basic file structure at Old Town Media that makes our projects easier to work on.

/styles
 -- main.scss
 -- ie8.scss
 -- ie9.scss
 -- editor-styles.css
 -- login.css
 /sass
    -- _sanitize.scss   // Normalization/reset 
    -- _wp-base.scss    // WordPress styles & OTM resets
    -- _cpts.scss       // Custom Post Types
    -- _menus.scss      // Navigation Items (main & mobile)
    -- _forms.scss      // Forms
    -- _print.scss      // Print-specific styles

Main.scss compiles all of the sheets in /sass in addition to the styles in the file. General styles reside in the main.scss file, with specialized content going in the /sass folder files along with any additional files.

The other stylesheets in the main /styles folder hold specific uses and cannot be combined into the main.scss file.

Breaking code into blocks

The main layout file should be organized in a top-down layout - starting with the header and ending with the footer. Other module-based stylesheets should be organized by module type or section. For example organizing a stylesheet by the custom post type or an eCommerce sheet starting with product listing, then individual product, then cart, etc.

Variables

Variables should all be defined in the main.scss file and should be named in a way that's recognizable to another developer/designer. All colors and font-families used more than once should be defined as variables to make organization easier.

Avoid

$luscious-nectar: #FFDAB9;
$midnight: #191970;

Prefer:

$peach: #FFDAB9;
$dark-blue: #191970;
Color Scheme declarations

During a project's lifecycle, it can be beneficial to declare all colors associated with the project not only with a descriptive name of the color, but also with a name that pertains to the color's function to the design.

Example:

$peach: #FFDAB9;
$dark-blue: #191970;

$highlight: $peach;
$brand: $dark-blue;

This enables a waterfall effect of styling, and allows for easy replacement of variables and identifiable use while building the project.

Mixins

Mixins should be defined at the head of the main SCSS file, or in a separate SCSS file to be imported at the beginning of main. Mixins should be accompanied with explanatory comments if necessary.

// Round Corners and add Padding
@mixin button($border-radius: 5px, $padding: 5px 15px){
  border-radius: $border-radius;
  padding: $padding;
}

When possible mixins should be declared with placeholders as an example of the mixins functionality. This improves readability.

Nesting

One of the best features of sass is that you can nest your selectors for easier readability. This is encouraged but should be used conservatively, lest we end up with a Woo-like nuclear-override selector. If you find yourself nesting more than 2 or 3 levels, re-evaluate the specificity required and your methodology. The items can likely be broken into lighter-specificity selectors.

There are times when more specificity is necessary, so use your best judgement.

Compiling

We cover general compilation more on the General page, but in general compiling should be done with a pre-processor on your workstation, triggering an auto-prefixer and minifying the outputted css. SCSS files should be concatenated into a single served css file and if the project is of appropriate scope, critical CSS tools should also be used with your compiler.

Performance

While not as important as images, render-blocking elements, or javascript performance, CSS can still have a dramatic impact on a page load time and perceived performance. Follow the below rules to keep CSS performant.

Using images as background images instead of a new request

Whenever possible, images should be defined as background images - especially when they can be eliminated no the mobile side. If images are included in the css - they will only be loaded when the element is actually used instead of loaded at page load.

Use CSS sprites

CSS sprites are a perfect way to reduce the number of HTTP requests being loaded on a page. Sprites should be used with small, repeatable images and must be referenced in the CSS of the page.

Network Requests

Stylesheets should all be compiled on the local side into one stylesheet. If you find yourself using a third-party library, it should be included using an @import statement in the pre-compiled scss in the appropriate section to be compiled. This keeps css network requests to a minimum.

More general rules

  • Keep your CSS as small as possible with as few selectors as possible.
  • Avoid using complex selectors
  • Avoid using non-performant selectors such as :not()

Mobile-first Responsive

We build our websites mobile first. Unless a design does not support it we use min-width media queries almost exclusively. Min-width queries allow us to be more flexible in building sites and results in using significantly less code with the same result. This also results in much faster mobile sites because the majority of the load is placed on larger screens, which generally have larger processors and faster Internet connections.

Min-width media queries

Min-width media queries should be used almost exclusively and should all point in the same direction to avoid confusion. Min-width media queries follow the principle of progressive enhancement which puts the greater burden of styles and paints on desktops and larger devices. It also reduces the amount of code used and makes it easier to modify later.

Example:

p{
  color: blue;
}

@media screen and (min-width:800px){
  p{
    color: red;
  }
}

On devices with a viewport smaller than 800px, text color in paragraphs will be blue. Once the viewport exceeds 800px, the color of the text will be red.

Breakpoints

Use a media query break when it starts to suck.

Generally, breakpoints should be defined as the content on the page no longer fills the needs of the space provided. For example, a grid system of products will most likely be vertically oriented on a mobile device. Once the viewport becomes larger, there will likely be a moment where it is more suitable to switch the layout to rows rather than columns.

Media queries placement

Media queries should be inlined with the appropriate selector block. As few queries as possible should be used, so group the queries with sections instead of individual selectors. Begin with the smallest media query (i.e.: immediately above mobile) and work your way up if necessary.

.trigger{
    display: block; 
}

.click-toggle-menu-off{
    position: fixed;
}

@include mq( $tablet ){
    .trigger,
    .click-toggle-menu-off,
    .offcanvas-nav{
        display: none;
    }
}

IE8 and older browser support

We use an ie8-specific and ie8-specific (to fix flexbox) stylesheet triggers with an html IF comment targeting those browsers older than IE9. This method allows us much more flexibility and the potential to fix older IE quirks without muddying up our modern browser CSS.

<!--[if lte IE 8]>
    <link rel="stylesheet" type="text/css" href="<?php echo get_template_directory_uri(); ?>/styles/ie8.css" />
<![endif]-->