loading...

8 SCSS Best Practices to Keep in Mind

liaowow profile image Annie Liao ・3 min read

This past week I had an opportunity to browse through a company's coding guideline, some of which I found very useful not only in collaborative settings but also in developing personal projects.

Here are eight of SCSS best practices from the guideline that made me rethink the way I structure my CSS code:

Note: The following tips are geared toward SCSS, so some might not apply to pure CSS. Big thanks to @yzoja and @8detect for the great reminder!

1. Mobile First

When it comes to responsive design, it's common to prioritize the desktop version, which can make customizing for mobile a painful process. Instead, we should design to expand, not cram things to fit mobile.

Don't:

.bad {
  // Desktop code

  @media (max-width: 768px) {
    // Mobile code
  }
}

Do:

.good {
  // Mobile code

  @media (min-width: 768px) {
    // Desktop code
  }
}

2. Set Variables

Defining CSS variables and mixins should be part of the initial setup, which can make the project much more maintainable.

According to the guideline, here are some common properties that will benefit from variables:

  • border-radius
  • color
  • font-family
  • font-weight
  • margin (gutters, grid gutters)
  • transition (duration, easing) – consider a mixin

3. Avoid #id and !important

Both !important and #ids are considered overly specific and can mess with the order of CSS rendering especially when developing collaboratively.

Don't:

#bad {
  #worse {
     background-color: #000;
  }
}

Do:

.good {
  .better {
     background-color: rgb(0, 0, 0);
  }
}

4. Avoid Magic Numbers

Try not to set arbitrary numbers because they "just work"; other developers might not understand why the property has to be set in such particular numbers. Instead, create relative values whenever possible.

If you're interested, CSS Tricks have a clear explainer of why Magic Numbers are bad.

Don't:

.bad {
  left: 20px;
}

Do:

.good {
  // 20px because of font height
  left: ($GUTTER - 20px - ($NAV_HEIGHT / 2));
}

5. Descriptive Naming

It's easy to define CSS selectors according to the looks. It's better to describe the hierarchy.

Don't:

.huge-font {
  font-family: 'Impact', sans-serif;
}

.blue {
  color: $COLOR_BLUE;
}

Do:

.brand__title {
  font-family: 'Impact', serif;
}

.u-highlight {
  color: $COLOR_BLUE;
}

6. Zero Values and Units

This one might be up to personal choice or specific project style guide, but consistency is key. The rule below asks that you specify units on zero-duration times, but not on zero-length values. Also, add a leading zero for decimal places, but don't go crazy (more than three) on decimal places.

Don't:

.not-so-good {
  animation-delay: 0;
  margin: 0px;
  opacity: .4567;
}

Do:

.better {
  animation-delay: 0s;
  margin: 0;
  opacity: 0.4;
}

7. Inline Commenting

The best practice here is to comment on top of the property you're describing. Also, use inline commenting (//) instead of block-level comments (/* */), which is harder to uncomment.

Don't:

.bad {
  background-color: red; // Not commenting on top of property
  /* padding-top: 30px;
  width: 100% */
}

Do:

.good {
  // Commenting on top of property
  background-color: red;
  // padding-top: 30px;
  // width: 100%;
}

8. Nesting Media Queries

In order to easily locate media queries, it is recommended that you keep the media queries at the root of the declaration instead of nesting them inside each selector.

Don't:

.bad {

  &__area {
    // Code

    @media (min-width: 568px) {
      // Code
    }
  }

  &__section {
    // Code

    @media (min-width: 568px) {
      // Code
    }
  }
}

Do:

.good {

  &__area {
    // Code
  }

  &__section {
    // Code
  }

  @media (min-width: 568px) {
    &__area {
      // Code
    }

    &__section {
      // Code
    }
  }
}

These are by no means an exhaustive list of best coding practices, but they certainly play a vital role in designing readable, scalable web apps. Is there any CSS guideline that you follow as your north star? Let me know in the comments!

Posted on by:

liaowow profile

Annie Liao

@liaowow

Fresh Front-End Developer with full-stack skillset (React with Rails). Currently exploring d3 visualization and other front-end magic.

Discussion

markdown guide
 

I agree with all except on using IDs. IDs are meant to scope your following css rules nested on it, making it easier to find, adds scalability and performs much better regarding on how browsers render the views.

Also using IDs and adding !important statements are not equal in terms of specificity and priority. !important statements are priorized much more aggressively.

So you must add IDs on your styling for scoping code but not for adding properties that are likely to need an override. 😁

 

Cool, thanks for the tip Joel! I was a bit surprised too when I saw that the guideline advised against using IDs. I have been quite cautious about using !important statements though.

 

Some points on guides around here have their reasons that may not fit into your project or needs. Remember that html and css (or sass/scss) are not programming languages so there's no much point on getting "best practices" or "do this instead of that". They simply work or not, this tips are about increasing performance, readability or scalability.
With this in mind, there's tones of opinionated articles that didn't tested or benchmarked anything about the content, always test this tips by yourself 😁 assomeone else may go for performance and you want scalability or vice versa (some tips are contradictory depending on the tarjet), get that ones which fits best for you 😆

CSS is a programming language.

But even it it wasn’t, why would you say there’s no point in teams or developers formulating lists of best practice which are most suited to their needs?

CSS is NOT a programming language. CSS is a design language to define how HTML (which is a markup language and in fact, not a programming language) elements should be displayed.

Dev teams can of course define a list of best practices for a given project (not a generic one for all projects) depending on the goal they want to achieve. That's performance, accessibility, readability, compatibility (with old browsers) or scalability, or a mix of some or all of them. But you'll find some points where doing something could benefit a target and harm another.

For example, using multiple isolated classes can definitely benefit readability and scalability but can harm compatibility with old browsers ( I.E. 6 and older wasn't good managing multiple classes on a single html element).

So if you are into a project where you need compatibility, you must take the decision on doing one or another, you can't keep it all. That's why there's no much point on defining some things as "css best practices" globally or generically.

I wrote an article of css best practices by myself some weeks ago that you can check here:
dev.to/joelbonetr/css-and-scss-bes...
where I tried to explain what I do and why I do this, so you can discern if it fits into your code or not.

I'm not giving compatibility to old browsers because the users of my client's sites that use old browsers are less than 0,05%. I don't care much about accessibility on standard projects (clients usually does not want to pay the extra analysis and development for it) so I usually go for performance and scalability to make the modifications faster (and cheaper) to us, and getting better SEO due to mobile friendly and site low weight.

After all, everyone has to check all best practices, understand the details of every statement and check if each one can fit into their needs or not for a given project.

Why is CSS not a programming language?

HTML and CSS are not programming languages because HTML and CSS are not generally “executed” by a computer. They are parsed by an engine, and then algorithms stored in a renderer determine execution tasks.

When you write <h1>foo</h1> , you’re not programming that element. You are denoting a piece of data. You haven’t “instructed” the browser to execute a task.

Likewise with CSS, anyone who’s written it for longer than 5 minutes knows that even something as simple as float: left; may not do that just because you asked. The browser will parse your instruction, and follow a set of algorithms over which you have no control to determine if and how something floats.

By the way you can't do anything different from a static webpage with HTML and CSS only, so that's not too different to what you can achieve using photoshop or microsoft word (you'll get a static content as result).

*Static meaning you can not interact with this view for store, modify or delete anything; no login, no user profile, no custom theme, no personal data... You can only read (view) the result "as is".

CSS may not be executed directly, but it directly affects those algorithmically determined execution tasks. CSS is used to instruct, direct or modify the application's output.

You can certainly modify content with just HTML and CSS. CSS also has functions, variables, mathematical functions and boolean logic.

We can get pedantic about strict definitions of execution, runtime interpreters and the like if you wish, but why quibble?

That's not a matter of discussion usually. You can not code an application using plain CSS, you cannot add functionality, only describe how the information is painted and styled 🤷🏻‍♀️
If you add enough features on CSS (server calls and handling of responses for example) it can become a programming language but you already have JavaScript for that tasks, which is a programming language.

 

I think this article is very useful for the usage of IDs.

 

It lacks some usages that have been used in the industry for some years, i mean scoping styles (not necessarily for styling the element itself).
For example:

#products {
  //Selectors for child elements of products id
}

This avoid unnecessary overrides, or adding extra unneeded classnames to elements with boilerplate such products-content-block, then you simply scope content-block inside #products.

This is more efficient on parsing and painting terms as CSSOM will find an ID instead seeking for all classnames on the entire project and then apply to matching elements which happens without IDs.
It's also meant for scalability as you will be able to find and edit quickly (and without overrides) an element inside a given scope on your project (specially when it grows a lot).

It will make your styles applying to .content-block only work inside #products, it's true, so it's your job to define styles that apply to all .content-block on the project and scope those who are specific from products page. Then you have custom styles when needed and global styles when needed.

This could seem a little bit disappointing at the beginning or with the mind on a little project, but avoids tones of issues when on a big project or a project that growth much more than expected.

I'm actually maintaining and developing over an e-commerce that receives more than 100k views a day. It was made with a customized prestashop and we need to apply this to all the entire project (which weights 1Gb of code approximately) because it was impossible to handle.
The reason was the same than always with CSS... Overrides, overrides over overrides, conditionally overrides due to redesigns and more redesigns... Now with the css scoped using page IDs and few script tweaks, the performance increased 15 points on pagespeed, the loading times decreased in 6 seconds (wow) and the user experience is much better. We started creating components too (migrating to a microservice architecture) so we can perform this practices from the beginning, and all styling is scoped inside each view component id attribute. No one of us (senior devs) thank for a moment on not using them for this purpose and junior devs understood quickly why to use them (as they needed to modify things on the old project too) 😂

I think your CSS system is literally the reason why you have to use IDs. IMO, a redesign shouldn't be a big problem if your CSS system is strong and flexible. The IDs scoping may fasten the project of re-writing the CSS but it is just a temporary fix. As the project gets bigger, keep using IDs for scoping would result in a messy CSS base. I don't know exactly what is your product component looks like but for me, using some classes is enough to create various styles of the product component (BEM-like CSS naming does very well on handling these cases). In your example, the same result can be achieved using classes like .product .product__content-block {}. Thus, I don't think using ID, in this case, is a good idea. However, for frameworks like ReactJS where you can write CSS separately for each component, using IDs for scoping is understandable.

How many years of experience do you have on the industry?
When you make a project by yourself it's all nice, when you manage a project with 10+ devs, and during developments on it some left the company, some come in and so it's nearly impossible to keep all the code clean.
On the other hand BEM is nice but not perfect: lacks the ID scoping performance and make devs write more words for doing the same. Of course you can combine different methodologies into a single one which usually works better and it's more realistic.

It's the same situation on people developing microservices without thinking if it fits into their needs. Sometimes you'll need services, connected to microservices and maintaining a monolithic application that tbh could make no sense on refactoring it into a service/microservice architecture.

I asked you about your experience because juniors and students usually take the idea that those methodologies are meant to bring perfection and must be used "as is". Then, on a real world you can code the perfect architecture and methodology and when you end with your app the paradigm changed and you are outdated. This does not mean you need to recode all entire application to fit the trends, this mean you need to learn and understand deeply the reason to exist of this methodologies and discern which part could be useful for your project.

I've to remember a fact many times and I'm doing it again: IT is a science, this means try, combine, recombine, take conclusions and repeat.
It's like if you say me that water boils at 100°C and I could tell you well, this is approximately true at sea level but not on the everest or in a hole at 5km below sea level, also incorrect on other planet and so.
There's no perfection, there's no such a thing that works well everything, you always need context.

To conclude i need to answer your comments last part, BEM is understandable, but it olds bad on hughe projects. You will end with too large classnames and with multiline HTML declarations.

Also you don't need a js framework to build components, you can do it easily without js making a dispatcher and discerning where to show some html files (which has it's own css attached).

Moreover on some js frameworks you can make your css for being included on the same output element so it will make a non sense on scoping css using IDs because you already have your styling isolated. This is the only situation where i would not use IDs for scoping (because it's scoped already).

 

Some other things that I've picked up at my current place:

  • alphabetise properties. This ensures you always avoid things like background overriding background-image. The exception is when using prefixed properties (-webkit-*, -moz-*, etc), which should be grouped together.
  • avoid the shorthand if you're only setting a specific property. Using background: url(…); will override any existing background colour.
  • don't nest selectors too deep. A rough rule of 3 or so should be kept to unless absolutely necessary.
 

I like the alphabetization of properties, some people don't like it, but for me it works. With regards to prefixed properties, I would strongly suggest not doing that manually but defining autoprefixer rules.

 

I agree with that, although there are times when you might need to manually specify prefixed properties, e.g. to offer a slightly different experience to some browsers

 

Great hints, thanks for that!

One general note regarding 7.: Comments are for what they are meant for: Commenting code that’s unable to explain itself by good naming.

It should NEVER been used to disable parts of code and commit that. Just delete it, that’s what version control systems are for.

 

I agree with this bit about commenting out code. Except for some occasions in personal projects when I want to save a WIP and it breaks the rest of the project in its current state, then I might commit something with commented out code...

Of course this is not the best way to handle this and it would make more sense to put it in its own branch, but you know... personal projects :)

 

I agree with the sentiment of mobile first, its a good philosophy to follow. However, I've never seen the need to use min-width with desktop styles over max-width with mobile styles. At the end of the day, they accomplish the same thing and are almost identical, albeit a mirrored version of each other. As long as you keep your html structured in a way that will be possible to style for both, I think you're good.

However, I definitely wouldn't mix and match, especially not in the same stylesheet. That's just a headache waiting to happen.

 

I learned to avoid nesting like this the hard way... this can make searching for certain classes with "cmd+f" extremely difficult, and I've sometimes spent way too long pulling out my hair looking for certain selectors:

.good {

  &__area {
    // Code
  }
}

To make my code more searchable but at the expense of "less beautiful code" I've been doing this more often (sometimes I do break my rule though):

.good__area{}
.good__section{}

@media {
   .good__area{}
   .good__section{}
}
 

I always make the code desktop-only, then after finishing the desktop version I copy the desktop code into min-width media queries and start coding the mobile version because I don't know how I want the mobile version to look like.
Aren't media queries inside of selectors better because that way you don't have to scroll to the top to find the media query?

 

Pretty good article, but you’re mistaken about #ids. Using #ids is invariably dramatically more performant than using .classes when the downstream CSS is processed in the browser. Whatever you might subjectively gain in style in SCSS (I’d argue against that, too) will not come even close to matching what you’ll lose objectively in CSS processing/rendering time.

 

What's wrong with background-color: #000; ??

 

That one was not about colors, but using .class vs. #id, which is debatable, as you might notice from the comments. I should've kept the color code consistent, sorry for the confusion. That said, the guideline prefers RGB values, and here's their full explainer on colors: github.com/we-make-websites/wmw-co...

 

It makes sense, I never thought about the readability of rgb vs hex. Probably cause I've been using hex for years xD

 

Some nice tips here, most of them I agree with based on my experience.

  1. Performance is an lesser known benefit when using the mobile first approach. The browser can just ignore the media queries which results in faster css processing as well as less processing.

  2. Not sure if, with hierarchy, you meant to say html structure. I believe it's important to note for someone who may think this. I believe strongly we should not bind css classes to html hierarchy. Meaning if you do .teaser-content-title and then have to add another element between content and title, your css is inconsistent. I'm a proponent of using BEM and Atomic design which make the process of thinking about your classes much clearer.

  3. Nesting with &__section is quite troublesome with regards to reading, searching, and refactoring the code. Some find it useful and like the brevity, but autocompletion in most IDEs solves this non-issue.

 

I’m curious on the last one about where to put media queries. I’ve used both ways but have found that I prefer the first way as it keeps everything together. The processor takes care of optimizing the code from what I’ve read so performance isn’t a reason as far as I understand. The second way, the preferred way in the article, ends up becoming distracting to navigate back and forth. What are the reasons to push the media queries to the bottom like that and break up information about the same class in two places? I did the preferred way first for a number of years and after I switched to the first (non-preferred) way it ended up working much better for maintainability for me.

 

I find number 8 to be a struggle all the time, but I think it comes down to how many nested classes your mind has the capacity to remember. Personally anything more than 2 nested classes results in me scrolling longer than actually reading and apprehending the code.
The rest - totally agree. Very informative post!

 

Great article! I'm curious what others would say, but I found it useful to use !important for utility classes such as m-t-5 { margin-top: 5px !important; }.

 

Utility class with important is a place where important can indeed be used. The tricky bit is that in general you rarely would want to use utility class at all. At least that's the goal. It pretty much says "Design seems inconsistent, let's make our code inconsistent too".

 

I agree with most of the rules.
I disagree with leading zeros. You don't need them, so I don't use them. It's faster and easier to type.
Second one i disagree with is nesting media queries. The approach you've shown introduces a lot of repeating selectors in css. And if you search your code base for specific thing you will have a lot of unnecessary hits. Also, nesting media queries helps me to reduce actual nesting, because I tend to think more about it with this approach. Most of the code, with mobile first approach is in the root of the selector, and in the transition from mobile to larger screen, so I rarely have a lot of nested media queries, and if that happens I use approach that you've shown here. Only then, and that's rare.
Also, important rule can be very useful to prevent accidental override of certain layout rules. Definitely don't overuse, but it can be very useful.

 

Ah, I see. The guideline I was referring to also has a DRY (Don't Repeat Yourself) rule, which seems to contradict with the nested media queries problem you mentioned here 😅 Thanks so much for sharing your own experience! It's wonderful to see how different devs approach responsive design, as I have struggled with it at my (currently) early stages of front-end dev.

 

I must have missed DRY. My bad. Sry. Good article btw. Keep 'em commin'. As you've said, it's nice to see different approach and experience to responsive design.

No you were right, I didn't mention DRY here in my post, it was just stated in the guideline. I was merely echoing your comment that their Nested Media Queries rule was not so DRY after all lol. Again, thanks for the quick reply and encouraging comments :)

 

As for the leading 0s, I know many linters/formatters add them (automatically for me) so I keep them there for consistency. If they're added automatically it doesn't take any time anyway.

For the media queries, that one is pretty situationally dependent. Either you're repeating selectors or you're repeating media queries, so if you have a lot of media queries, you'll end up repeating yourself more if you nest those over selectors. I tend to agree with the author however, and keep my queries as their own blocks, I find it easier to keep track of personally.

 

For leading zeroes, I guess it depends on the linter settings. I didn't run into problems omitting them. IE adds them by itself for example. It's just a personal preference of mine.
As for media queries I tend to observe each selector as a self contained module. For example class navbar has all of its media queries nested in itself. This way I can easily extract each of those modules in separate files, or reposition them or nest them differently. I don't have to search for all occurrences across the file. Shortcoming of this approach is, as you've said, repetition of media queries. But so far, in my case, repetition of selectors was a lot bigger pain in the but, especially for large legacy code bases.
There is nothing wrong with either of these approaches. Use what works for you. Cheers

 

Inline comments in CSS? 😂

PLEASE, specify that you're using Sass or whatever, because at least few of those things are not working in pure CSS

 

Yeah the guideline has separate rules for inline and introductory commenting, which I never thought about. And thanks for pointing out the SCSS specificity. Just modified my title accordingly.

 

All good tips, but I have a different preference regarding the nested media queries definitions: I actually prefer nesting them separately inside each declaration. I find it easier to check what's happening and don't need to scroll much to find the changes for each media query.

Also, for better performance, it is a good practice to merge all media queries on processing the SCSS files, using something like github.com/SassNinja/postcss-combi..., for example

 
 

please notice ! your css syntax works for scss or something like styled component in react not pure css. Otherwise good post.

 

Great catch, just changed my title to specify SCSS. Thanks so much for letting me know!

 

Nice article, thanx! Can you please share the Guideline or other resources With best practices in css/sass?

 

Sure, this is the guideline I was referring to: github.com/we-make-websites/wmw-co...

As for other resources, frankly I just pick up things sporadically, although I tend to come across CSS-Tricks site a lot.

Let me know if you find anything helpful as well :)

 

Thank you 💖 this is super helpful🤩

 

Thanks for your nice posting
Look forward to your next post

 

This is really a great post ❤️
Can you please create a part 2 of this post discussing 8 another best practices?

Thanks for the post

 

Thanks for reading the post, Ram! As other commentators pointed out, I think I need to solidify my understanding of CSS vs. SCSS capabilities. Perhaps that would be my next post 😉