CSS Best Practices

Creating efficient, maintainable, and scalable CSS/SCSS is essential for building robust web applications. In this lecture, we'll go over some best practices in writing CSS. These guidelines will help you write CSS that is efficient, maintainable, and easy to understand.

Desired Outcomes

By the end of this lecture, you should be able to:

  • Write clear and efficient CSS.
  • Follow guidelines for maintaining a well-structured CSS codebase.

Comment Your Code

Comments can help you and others understand the purpose and functionality of your code. In CSS, you can add comments like this:

/* This is a comment */

Good Practice:

Use comments to explain why certain decisions are made, especially for workarounds or hacks.

// Using z-index here to fix a stacking context issue
.modal { z-index: 1000; }

Bad Practice:

Sparse or no comments, leaving the rationale behind certain styles unclear.

.modal { z-index: 1000; } // No explanation

Comments in your CSS files are crucial for explaining why certain decisions were made, especially for complex or non-obvious solutions. This is invaluable for team collaboration and future maintenance.

Use a CSS Reset

Different browsers have different default styles. By using a CSS reset, you can ensure that your webpage looks consistent across all browsers.

Here are examples of CSS reset files:
https://meyerweb.com/eric/tools/css/reset/

https://necolas.github.io/normalize.css/

Follow a Naming Convention

A consistent naming convention can make your CSS easier to read and understand. There are several popular methodologies like BEM, OOCSS, SMACSS and GPS.

Semantic class names describe the purpose or function of an element rather than its appearance. This makes the code more readable and maintainable, especially in a team environment. It also helps with SEO and accessibility.

Good Practice:

Use descriptive and meaningful class names that reflect the element's purpose, not its appearance.

.btn-primary { ... }
.nav-item { ... }
.footer-links { ... }

Bad Practice:

Avoid non-semantic, presentational class names that describe the look rather than the purpose.

.big-red-text { ... }
.blue-button { ... }

Use Shorthand Properties

Shorthand properties allow you to set several properties at once. For example, instead of this:

margin-top: 10px;
margin-right: 30px;
margin-bottom: 40px;
margin-left: 20px;

You can write this:

margin: 10px 30px 40px 20px;

Organize Your Code

Keep your code organized. You could group related styles together or order them alphabetically. Find a system that works for you and stick to it.

This means keeping all styles related to a specific component or part of your application in one place. For instance, all styles related to headers, footers, and buttons are grouped together. This approach is particularly effective in component-based architectures like React or Vue.js.

Good practice:

// Header Styles
.header { ... }
.navbar { ... }
.dropdown-menu { ... }

// Footer Styles
.footer { ... }
.footer-links { ... }
.footer-credits { ... }

// Button Styles
.btn { ... }
.btn-primary { ... }
.btn-secondary { ... }

In this example, all styles related to specific components (header, footer, buttons) are grouped together, making it easier to find and manage related styles.

Bad practice:

// Header Styles
.header { ... }
.dropdown-menu { ... }

// Button Styles
.btn { ... }
.btn-primary { ... }

// Header Styles Continued
.navbar { ... }

// Footer Styles
.footer { ... }
.btn-secondary { ... }
.footer-links { ... }

Here, the styles are not consistently grouped. The header and button styles are interrupted and scattered, making the stylesheet confusing and hard to navigate.

An organized codebase is crucial for efficient development and maintenance. Whether you prefer grouping by related styles or alphabetical ordering, the key is consistency. Stick to your chosen method throughout the project to ensure your stylesheets remain clean, organized, and intuitive for anyone who works with them.

1 + 100 +10 + 1+ 10 = 122

Be Specific but Not Too Specific

Overly specific selectors can make it difficult to override styles and can lead to a higher CSS specificity, which can cause unexpected issues. Aim for a balance where your selectors are specific enough to target the elements you want without being overly restrictive.

Bad Practice:

Overly specific selectors that are hard to override and lack reusability.

div#main-content .profile-card div.username { ... }

Good Practice:

Use specific enough selectors to target elements without being overly specific.

.profile-card .username { ... }

Modularize with SCSS Partials

SCSS partials allow you to break your styles into smaller, more manageable pieces. This makes your stylesheets easier to navigate and helps avoid conflicts in larger projects.

Bad Practice:

Writing all styles in a single, monolithic file which becomes hard to maintain.

// In styles.scss
// Hundreds of lines of styles

Good Practice:

Break down styles into smaller, manageable partials like _buttons.scss, _nav.scss, and import them in a main file.

// In main.scss
@import 'partials/buttons';
@import 'partials/nav';

Nesting SCSS Selectors

While nesting is a powerful feature of SCSS, overdoing it can lead to highly specific selectors which are difficult to override and can lead to CSS bloat. Keeping nesting to a minimum (ideally no more than 3 levels) helps maintain readability and flexibility.

Bad Practice:

Excessively deep nesting which leads to specificity issues and harder maintenance.

.navbar {
  .nav-item {
    a {
      span {
        &:before { ... }
      }
    }
  }
}

Good Practice:

Nest selectors to a maximum of three levels to maintain readability and prevent overly specific selectors.

.navbar {
  .nav-item {
    a { ... }
  }
}

Use Variables for Consistency

Variables in SCSS provide a single source of truth for values that are used in multiple places. This makes your codebase more maintainable as changes can be made in one place and reflected everywhere.

Bad Practice:

Hardcoding values throughout the stylesheet which makes updates cumbersome and error-prone.

.header { background-color: #2980b9; }
.footer { color: #3498db; }

Good Practice:

Use variables for colors, fonts, and other reusable properties to maintain consistency and ease of updates.

$primary-color: #2980b9;
$secondary-color: #3498db;

Leverage Mixins for Reusability

Mixins allow you to define styles that can be reused throughout your stylesheet. They are especially useful for vendor prefixes, complex animations, and frequent patterns like media queries.

Bad Practice:

Repeating the same set of styles in multiple places.

.container { /* clearfix styles */ }
.footer { /* clearfix styles */ }

Good Practice:

Use mixins for repetitive patterns like clearfix, media queries, or animation keyframes.

@mixin clearfix { ... }
.container { @include clearfix; }

Utilize Functions and Operators

Functions in SCSS can perform calculations and complex operations, allowing for more dynamic and flexible styling. They can be used for things like converting pixels to rems or ems, color manipulations, etc.

Bad Practice:

Manual calculations or fixed units which are not dynamically responsive.

.element { margin-top: 30px; }

Good Practice:

Use functions for calculations and logical styling decisions.

$base-font-size: 16px;
@function rem($pixels) { @return $pixels / $base-font-size * 1rem; }

Organize Media Queries

Place media queries near their relevant blocks of styles to keep related styles together. Alternatively, use a consistent structure for media queries, such as keeping them at the bottom of your stylesheet or in a separate partial.

Bad Practice:

Scattering media queries all over the stylesheet, making them hard to find and manage.

// Base styles at the top
// Random media queries in the middle

Good Practice:

Place media queries close to their relevant selectors or use a consistent structure for them.

.sidebar {
  // base styles
  @media (max-width: $breakpoint-md) { ... }
}

Avoid Deep @import Chains

Deep @import chains can lead to confusion about where specific styles are coming from and can increase compilation times. Keeping your @import statements flat and simple helps maintain clarity.

Bad Practice:

Having multiple nested @imports which can slow down the compilation and make the dependency graph complex.

// In base.scss
@import 'reset';
@import 'typography';
// And so on...

Good Practice:

Keep @import chains shallow to reduce compilation time and complexity.

@import 'base';
@import 'components';

Prioritize Readability

Clear, consistent formatting in your SCSS files makes it easier for you and others to read and understand the code. Consistent indentation, spacing, and organization are key.

Bad Practice:

Cluttered and inconsistent formatting that makes the code hard to follow.

.header{background:$header-bg;.logo{width:rem(100);}}

Good Practice:

Write code in a readable and consistent format. Use indentation and spacing that makes the stylesheet easy to scan.

.header {
  background: $header-bg;

  .logo {
    width: rem(100);
  }
}

Scalability and Maintainability

Write your SCSS with future growth in mind. Use scalable patterns and structures that can be easily extended or modified. This helps when the project grows in complexity or when new developers join the project.

Bad Practice:

Writing styles in a way that doesn't consider future scalability or adjustments.

.button { ... }
.large-button { /* Duplicate styles from .button with modifications */ }

Good Practice:

Design your SCSS with scalability in mind. Use patterns and structures that can easily be expanded or modified.

.button { ... }
.button-large { @extend .button; ... }

Avoid Using !important

The !important rule can make debugging difficult because it disrupts the natural flow of the CSS cascade. Use it sparingly and only when necessary.

In some cases you might find it necessary to use !important, but try to avoid it as much as possible.

Conclusion

Writing clean, maintainable, and scalable CSS/SCSS is a skill that improves with practice and attention to detail.

Following these practices will help create a CSS/SCSS codebase that is easier to manage, more efficient, and adaptable to changes. Remember, the key to good CSS/SCSS is not just in how it looks but also in how maintainable and scalable it is in the long run.

-75%

Time remaining:
days 00: 00: 00

Learn to code HTML & CSS

From Zero to Hero

Check out this course on Udemy, now at 75% off! Inside this interactive course, I will teach you how to develop websites from scratch moving from beginner to advanced concepts. I take time to explain every detail and finish off by building some real-world websites.

HTML & CSS: From Zero to Hero
Learn to code HTML & CSS

-75%

Time remaining:
days 00: 00: 00

Learn to code JavaScript & jQuery

From Zero to Hero

Check out this course on Udemy, now at 75% off! Inside this interactive course, I will teach you how to develop components from scratch moving from beginner to advanced concepts. I take time to explain every detail and finish off by building some real-world reusable components.

JavaScript & jQuery: From Zero to Hero
Learn to code JavaScript & jQuery

-75%

Time remaining:
days 00: 00: 00

Learn Frontend Web Development

From Zero to Hero

Check out this course on Udemy, now at 75% off! A bundle of the previous two courses. Inside this interactive course, I will teach you how to develop websites from scratch moving from beginner to advanced concepts. I take time to explain every detail and finish off by building some real-world websites.

Frontend Web Development: From Zero to Hero
Learn Frontend Web Development