💡 This page contain affiliate links. By making a purchase through them, we may earn a commission at no extra cost to you.
10 Best Practices for Quickly Improving Your CSS

10 Best Practices for Quickly Improving Your CSS

Building scalable and manageable stylesheets
Ferenc AlmasiLast updated 2021 November 11 • Read time 13 min read
CSS has its own nuances that can make or break your design. Here are 10 tips for CSS :  best practices that can help you bring out the best from your styles.
  • twitter
  • facebook
CSS

CSS may seem like a pretty straightforward language, one that’s hard to make mistakes in. You just add your rules to style your website and you’re done, right? With small sites that require only a couple of CSS files, this might be the case. But in large applications, styles can quickly spiral out of control. How do you keep them manageable?

The reality is that, just as with any other language, CSS has its own nuances that can make or break your design. Here are 10 tips for CSS — best practices that can help you bring out the best from your styles.


1. Do You Really Need a Framework?

First of all, decide whether you really need to use a CSS framework. There are now many lightweight alternatives to robust frameworks. Usually, you won’t be using every selector from a framework, so your bundle will contain dead code.

If you’re only using styles for buttons, outsource them to your own CSS file and get rid of the rest. Also, you can identify unused CSS rules using code coverage in DevTools.

Looking for dead code using the code coverage tool

To open it, search for Coverage in the Tools panel. You can open the Tools panel by clicking Ctrl + Shift + P. Once open, start recording by clicking on the reload icon. Everything shown in red is unused.

You can see that in the example above, it says that 98% of the CSS is not used. Note that this is not actually true — some CSS styles are only applied after the user interacts with the site. Styles for mobile devices are also flagged as unused bytes. So before you remove everything, make sure you verify that it is indeed not used anywhere.


2. Prefer Using a CSS Methodology

Consider using a CSS methodology for your project. You can use CSS methodologies to create consistency in your CSS files. They help in scaling and maintaining your projects. Here are some popular CSS methodologies that I can recommend.

BEM

BEM —Block, Element, Modifier — is one of the most popular CSS methodologies out there. It’s a collection of naming conventions you can use to easily craft reusable components. The naming conventions follow this pattern:

Copied to clipboard!
.block { ... }
.block__element { ... }
.block--modifier { ... }
bem.css
  • .block: Blocks represent a component. They’re standalone entities and are meaningful on their own.
  • .block__element: These are parts of a .block. They have no standalone meaning and must be tied to a block.
  • .block--modifier: These are used as flags on blocks or elements. We can use them to change the appearance, behavior, or state of elements. For example, to use a hidden flag, we could say .block--hidden.

ITCSS

Inverted Triangle CSS helps you better organize your files by introducing different layers to different specificities. The deeper you go, the more specific.

The 7 layers of ITCSS
The 7 layers of ITCSS

OOCSS

Object-oriented CSS, or OOCSS, has two main principles.

Separating structure and skin
This means you want to define visuals separately from structural code. What does this mean in practice?

Copied to clipboard! Playground
/* Instead of  */
.box {
    width: 250px;
    height: 250px;
    padding: 10px;
    border: 1px solid #CCC;
    box-shadow: 1px 2px 5px #CCC;
    border-radius: 5px;
}

/* Do */
.box {
    width: 250px;
    height: 250px;
    padding: 10px;
}

.elevated {
    border: 1px solid #CCC;
    box-shadow: 1px 2px 5px #CCC;
    border-radius: 5px;
}
structure-and-skin.css

2. Separating container and content
This means you don’t want any element to depend on its location. The same elements should look the same regardless of where they are on the page.

Copied to clipboard! Playground
/* Instead */
.main span.breadcumb { ... }

/* Do */
.breadcrumb { ... }
container-and-content.css
Looking to improve your skills? Master CSS from start to finish.
Master CSSinfo Remove ads

3. Set Up a Pre-Processor

Setting up a pre-processor can benefit you in various ways. A pre-processor is a tool that lets you use advanced features that don’t exist in CSS. These can be things like variables for loops, or even functions.

There are plenty of pre-processors out there. Probably the most famous three are Sass, Less, and Stylus. I recommend using Sass because of it’s thriving community and the extensive documentation you can find for it on the web.

So, how can pre-processors help you?

Organize your styles better

Pre-processors help you organize your styles better. They have the ability to break down your files into smaller, reusable pieces. You can import them into each other, or later separately into your application.

Copied to clipboard!
// Import different modules into one SCSS file
@import 'settings';
@import 'tools';
@import 'generic';
@import 'elements';
@import 'objects';
@import 'components';
@import 'trumps';
index.scss

Nest your selectors

Another great way to enhance readability is by nesting your selectors. This is a simple, powerful feature that CSS lacks.

Copied to clipboard!
.wrapper {
    .sidebar {
        &.collapsed {
            display: none;
        }
        
        .list {
            .list-item {
                ...
                
                &.list-item--active {
                    ...
                }
            }
        }
    }
}
nesting.scss

The hierarchical structure makes it easier to visualize how different elements tie together.

Automatically vendor prefix your rules

Some nonstandard or experimental features are prefixed in CSS. Different browsers use different prefixes for them, such as:

  • -webkit-: used for WebKit based browsers such as Chrome, Safari, or newer versions of Opera.
  • -moz-: for Firefox.
  • -o-: is for older versions of Opera.
  • -ms-: for IE and Edge.

To support all major browsers, we have to define certain properties multiple times.

Copied to clipboard! Playground
.gradient {
    background: rgb(30,87,153);
    background: -moz-linear-gradient(top, rgba(30,87,153,1) 0%, rgba(41,137,216,1) 50%, rgba(32,124,202,1) 51%, rgba(125,185,232,1) 100%);
    background: -webkit-linear-gradient(top, rgba(30,87,153,1) 0%, rgba(41,137,216,1) 50%, rgba(32,124,202,1) 51%, rgba(125,185,232,1) 100%);
    background: linear-gradient(to bottom, rgba(30,87,153,1) 0%, rgba(41,137,216,1) 50%, rgba(32,124,202,1) 51%, rgba(125,185,232,1) 100%);
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#1e5799', endColorstr='#7db9e8', GradientType=0);
}
vendors.css

Pre-processors help us tackle this with mixins — functions that can be used in place of hard-coded values.

Copied to clipboard!
@mixin gradient() {
    background: rgb(30,87,153);
    background: -moz-linear-gradient(top, rgba(30,87,153,1) 0%, rgba(41,137,216,1) 50%, rgba(32,124,202,1) 51%, rgba(125,185,232,1) 100%);
    background: -webkit-linear-gradient(top, rgba(30,87,153,1) 0%, rgba(41,137,216,1) 50%,rgba(32,124,202,1) 51%, rgba(125,185,232,1) 100%);
    background: linear-gradient(to bottom, rgba(30,87,153,1) 0%, rgba(41,137,216,1) 50%,rgba(32,124,202,1) 51%, rgba(125,185,232,1) 100%);
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#1e5799', endColorstr='#7db9e8', GradientType=0);
}

.gradient {
    @include gradient();
}
vendors.scss

Instead of writing out the same thing over and over again, you can just include mixins whenever you need them.

Using post-processors

An even better option is a post-processor. A post-processor can run additional optimization steps once your CSS is generated by a pre-processor. One of the most popular post-processors is PostCSS.

You can use PostCSS to automatically prefix your CSS rules, so you don’t have to worry about leaving out major browsers. They use values from Can I Use, so it’s always up to date.

Another great post-processor is autoprefixer. With autoprefixer, when you want to support the last four versions — you’re all done without having to write any vendor prefixes in your CSS files!

Copied to clipboard! Playground
const autoprefixer = require('autoprefixer')({
    browsers: [
	'last 4 versions',
	'not ie < 9'
    ]
});
autoprefixer.js

Use configs for consistent designs

Apart from mixins, you also have the option to use variables. In conjunction with a linter, you can enforce design rules.

Copied to clipboard!
// Font definitions
$font-12: 12px;
$font-21: 21px;

// Color definitions
$color-white: #FAFAFA;
$color-black: #212121;
config.scss
You can use Husky to prevent commits that use other fonts or colors outside of the predefined ones (https://www.npmjs.com/package/husky)

4. Use Markup Instead of CSS

Now let’s move on to actual CSS. This is often overlooked. Usually, you can reduce the size of your CSS bundles by simply using the correct HTML elements. Say you have a heading with the following set of rules:

Copied to clipboard! Playground
span.heading {
    display: block;
    font-size: 1.2em;
    margin-top: 1em;
    margin-bottom: 1em; 
}
markup.css

You’re using a span element as a header. You override the default display, spacing or font style. This can be avoided by using an h1, h2, or h3 instead. By default, they have the styles you’re trying to achieve with other elements. You can immediately get rid of four unnecessary rules.


5. Use Shorthand Properties

To further reduce the number of rules, always try to go with shorthand properties. For the above example, we could have said:

Copied to clipboard!
.heading {
    margin: 1em 0;
}
heading.css

This is true for other properties such as paddings, borders, or backgrounds.

before and after using shorthand properties
Using shorthand properties can greatly reduce the weight of your CSS files

6. Reduce Redundancy

This goes hand in hand with the previous point. Sometimes it’s hard to spot redundancy, especially when repeating rules don’t follow the same order in both selectors. But if your classes differ in just one or two rules, it’s better to outsource those rules and use them as an extra class. Instead of this:

Copied to clipboard! Playground
<style>
    .warning {
        width: 100%;
        height: 50px;
        background: yellow;
        border-radius: 5px;
    }

    .elevated-warning {
        width: 100%;
        height: 50px;
        font-size: 150%;
        background: yellow;
        box-shadow: 1px 2px 5px #CCC;
        border-radius: 5px;
    }
</style>

<div class="warning">⚠️</div>
<div class="elevated-warning">🚨</div>
redundancy.html

Try to go with a similar approach:

Copied to clipboard! Playground
<style>
    .warning {
        width: 100%;
        height: 50px;
        background: yellow;
        border-radius: 5px;
    }

    .warning--elevated {
        font-size: 150%;
        box-shadow: 1px 2px 5px #CCC;
    }
</style>

<div class="warning">⚠️</div>
<div class="warning warning--elevated">🚨</div>
redundancy.html
Looking to improve your skills? Master CSS from start to finish.
Master CSSinfo Remove ads

7. Avoid Complex Selectors

There are two major problems with using complex selectors. First, your increased specificity will not only make it harder to later rewrite existing rules, but also increase the time it takes for the browser to match selectors.

Matching selectors

When your browser is trying to interpret selectors and decide which element it matches, they go from right to left. This is faster in terms of performance than doing the other way around. Let’s take the selector below as an example.

Copied to clipboard!
.deeply .nested .selector span {
    ...
}
matching.css

Your browser will first start from the span. It will match all the span tags then go to the next one. It will filter out the spans that are inside a .selector class, and so on.

I don't recommend to use tags for CSS selectors because it will match for every tag. While the difference can only be measured in a fraction of a millisecond, little things add up. More importantly, it’s good practice to reduce complexity for another reason.

Understanding the selector

It’s not only hard for machines to parse, but it’s also hard for humans to do so. Take the following as an example:

Copied to clipboard!
[type="checkbox"]:checked + [class$="-confirmation"]::after {
    ...
}
complex.css

When do you think the rule above will be applied? This can be simplified by making a custom class and switching it with JavaScript.

Copied to clipboard!
.confirmation-icon::after {
    ...
}
simple.css

Now it looks much more pleasant. If you still find yourself in need of an overly complicated selector and you believe you have no other option, please leave a comment below explaining your solution.

Copied to clipboard! Playground
/**
 * Creates a confirmation icon after a checkbox is selected.
 * Select all labels ending with a class name of "-confirmation"
 * that are preceded by a checked checkbox.
 * PS.: There's no other way to get around this, don't try to fix it.
 **/
.checkbox:checked + label[class$="-confirmation"]::after {
    ...
}
explanation.css

8. Don’t Remove Outlines

This is one of the most common mistakes developers make when writing CSS. While you may think there’s nothing wrong about removing the highlight that outlines create, in fact, you’re making the site inaccessible. It’s common practice to add this rule as a reset to your CSS.

Copied to clipboard!
:focus {
    outline: none;
}
outline.css

This way, however, users with only keyboard navigation will have no clue about what they’re focusing on your site.

The default outline when using keyboard navigation

If the default styling looks bad for your brand, create custom outlines. Just make sure there is some kind of indication when it comes to focusing elements.


9. Use Mobile First

When you have to deal with media queries, always use mobile-first. The mobile-first approach means you start writing CSS for small screen devices first and build from there. This is also called progressive enhancement.

This will ensure that you mostly add extra rules to cater for large screen devices, rather than rewriting existing CSS rules. This can reduce the number of rules you end up with.

How can you tell if you use mobile-first? If your media queries use min-width, you’re on the right track.

Copied to clipboard! Playground
/* Mobile-first media query, everything above 600px will get the below styles */
@media (min-width: 600px) {
    /* your CSS rules */
}

/* Non mobile-first media query, everything below 600px will get the below styles */
@media (max-width: 600px) {
    /* your CSS rules */
}
mobile-first.css

10. Compress

Lastly, compress your bundles to reduce their size. Compression removes comments and whitespaces so your bundles require less bandwidth to fetch.

before and after compressing a set of rules in CSS
before and after compressing a set of rules in CSS

If you haven’t already, enable compression on the server-side as well.

Another great way to further reduce the size of your CSS — and markup— is obfuscating class names.

reduce file size by obfuscating class names

To achieve this, you have a couple of options based on your project setup:

  • Webpack: for Webpack, you can use the css-loader module.
  • Gulp: for Gulp, you can use the gulp-minify-cssnames plugin.
  • Create your own: If you don’t have a dedicated package for your project setup, I have a tutorial that shows you how you can create your own implementation.
Looking to improve your skills? Master CSS from start to finish.
Master CSSinfo Remove ads

Summary

Following these 10 simple steps will help you to write CSS files that are:

  • more lightweight
  • easier to maintain
  • easier to scale

Not only that, but using utilities such as a predefined color palette or typography rules, will help you create more consistent designs. Your styles will also be more reusable, so you can save time on your next project.

What are some other CSS best practices you follow but were not mentioned in this article? Let us know in the comments!

Thank you for reading through, happy styling!

How to Create Skeleton Loaders in CSS
  • twitter
  • facebook
CSS
Did you find this page helpful?
📚 More Webtips
Frontend Course Dashboard
Master the Art of Frontend
  • check Access 100+ interactive lessons
  • check Unlimited access to hundreds of tutorials
  • check Prepare for technical interviews
Become a Pro

Courses

Recommended

This site uses cookies We use cookies to understand visitors and create a better experience for you. By clicking on "Accept", you accept its use. To find out more, please see our privacy policy.