author avatar
By James Garrett Front-end Engineer

*Views, thoughts, and opinions expressed in this post belong solely to the author, and not necessarily to SemanticBits.

There are many different approaches to writing and maintaining CSS within a project. My preferred approach is to keep it simple and clean while introducing the least amount of dependencies possible. If these approaches sound good to you, continue reading as we dive into directory structure, conventions/guidelines, scoped & global component styling, build tools, and frameworks (or lack of!).

Directory Structure

Keeping your CSS files organized into categories can help you quickly describe the intent of the styling, also allowing you to easily find what you are looking for. The following are suggested directories to get you started.

Base: The base directory is where styling for elements that are commonly used throughout an application live. For example, it’s common to have files named “button”, “form”, “type”, etc., which contain default CSS related to standard HTML elements.

Components: The components directory is where custom component styling is kept. This includes anything related to a specific section of the application. In many cases this directory can be omitted (Read the Scoped & Global Component Styling section).

Layout: The layout directory contains CSS files specifically related to styling re-usable layouts, such as grids, and commonly used structure styling, such as headers, footers and content sections.

Vendor: If required, this is where 3rd-party CSS would be kept.

Variables.css: CSS variables are kept in this file.

Style.css: This is the main CSS file where all other files are imported.

Conventions/Guidelines

Conventions and guidelines are what help keep CSS clean. The following are a few guidelines for keeping your CSS codebase clean and structured.

Class Naming

A popular class naming convention to follow is Block Element Modifier (BEM). Having a consistent naming convention is very helpful as your codebase grows. The BEM convention allows you to quickly follow the HTML structure by viewing your class names without having numerous selectors to define the structure. You can read more about this here.

The main concept with the BEM naming convention is that child elements of a class are separated with two underscores after the parent class. Modifier classes are separated with two dashes after the class.

Parent: parent-class

Child: parent-class__child

Child 2: parent-class__another-child

Modifier: parent-class__child--wide

For Example:

<div class="parent-class">

    <div class="parent-class__child"></div>

    <div class="parent-class__another-child"></div>

   <div class="parent-class__child parent-class__child--wide"></div>

</div>

This is extremely helpful if you do not like long selector strings.

For example:

.class1__class4 > p {}

is better than

.class1 .class2 .class3 .class4 > p {}

Guidelines

Listed here are a few recommended guidelines to follow in order to keep a clean codebase.

Selector count: Try not to use more than three selectors to target an element. With the BEM naming convention it is possible that you will rarely use more than one. There are other benefits to more concise selectors, which you can read here.

Nesting: Do not nest CSS unless it is for pseudo classes. Nesting CSS can often lead to a lot of messy code. It also adds to the selector count.

Mobile First: Write CSS for the smallest view first, then adjust using media queries as the page size grows.

Property Order: This guideline is more for sanity than anything else. There are numerous ways to order your properties so that you can quickly access what the class is doing because you’ll know the order. One common practice is to order the properties by what their intent is. Start with layout properties and end with type properties, while keeping border/background properties in the middle. Another great and popular alternative to this approach is ordering the properties in alphabetical order.

Example:

.classname {

    /* layout properties */

    position: relative;

    margin: 10px;

    display: block;

    /* border/background properties */

    border: 1px solid red;

    background-color: green;

     /* type/font properties */

    font-size: 1rem;

    color: blue;

}

Linting: Linting is a helpful tool for keeping a clean CSS codebase. Here is a popular CSS linting toolCheck it out!

Scoped & Global Component Styling

The concept of scoped CSS could really be its own article but let’s touch on the subject briefly.

At first, you may be hesitant to break your CSS out of the directory structure set aside specifically for CSS and place it with your Javascript. It seems strange to mix the two but after taking the time to understand the benefits scoped CSS offers, you may have a change of heart.

Here’s a super quick and short list of the pros and cons, based strictly on an Angular project.

PROS

Modifying CSS

Within your scoped CSS, you can modify a global class name and not worry about it changing everywhere within your application. In the following example, within your component, the color of the <p> element will be red, and everywhere outside of your component will remain blue.

Example:

Scoped

.my-component p {

    color: red;

}

Global stylesheet

.my-component p {

    color: blue;

}

Organization

Your CSS will be with the Javascript and HTML that it controls! No need to go searching through your CSS directory. Just find your component.

Re-usability

Because your CSS is scoped to the component, you can now use the component wherever you like, and it should look the same in any application.

CONS

Organization: There is now CSS all over the place!

Selectors: This may be different depending on the Javascript library you are using. For instance, using Angular, specifically, with the removal or pending removal of shadow piercing combinators (/deep/, >>>, and ::shadow), it’s slightly complicated to select nested component classes within the scoped CSS. If you find yourself using these deprecated selectors, it may be a better solution to move that styling to the global stylesheet or utilize :host-context() within the child component you are attempting to style.

Build Tools

I’ll keep this section brief and simply recommend using PostCSS because it only requires that you write good ole, regular CSS. Justifying the need for a pre-processor such as Sass or LESS is becoming more difficult. One of the main reasons to use Sass are variables. If you are supporting older browsers, I get it. If not, CSS has this covered! Also, check out this.

Learn more about PostCSS.

Frameworks

Try not to use frameworks. Are you ok with bringing in many, many, many lines of CSS that will never be used? There are some benefits of using a framework, like how it can speed up development. But, honestly, is it really that hard to write the CSS that a framework provides? Most frameworks are used for the quick implementation of grid layouts. Yet, with the introduction of css-grid and flexbox, there is no need to bring in an entire framework for layout purposes.

There you have it, a few topics to help you maintain a clean CSS codebase and be happy developers! Hope you enjoyed the article and that it encourages you to write better code!