10 CSS mistakes every web designer must avoid



In CSS, we’ve come a long way from using the CSS Zen Garden to convince the web to go table-less. But, as our websites get bigger, more interesting and use new, vendor-prefix-laden attributes, more people are interested in levelling up their CSS skills. Yet, where to start? How does a web developer learn good habits? What does ‘bad’ CSS look like, and what can you do about it? I’ll share 10 habits in CSS that you can work to eliminate from your codebase, and how.

The bad habits can be divided into a few distinct categories to help you better understand them: overspecificity, workflow and the ‘you know better’s.


Symptoms of overspecificity

The trouble with bad CSS is that it generates more bad CSS. You’ve probably needed to fix a CSS bug, only to find that you needed to trump a long selector, a selector using ids – or worse, found some inline styles and had to resort to !important as a (literal) last resort. What all these examples have in common is that they’re symptoms of a big issue: overspecificity.

Specificity in CSS is how specific you are when you’re defining your CSS declarations:


If you’re reading this selector from left to right, you would read, ‘In the layout area, in the header area, in the title area, in the logo area, for any link (a tag)’. You can see that it’s a pretty specific need. Very rarely would you need to get that specific. Overspecificity makes your CSS less maintainable and readable. Let’s look at some bad habits that fall in the overspecificity category.


01. Using ids

One of the layers of specificity is the kind of selector you have constructed: ids versus classes versus tags. For example:



The red id declaration trumps the other one


Because the first one is using an id, it’s the most specific of the three. Because ids can only be used once per page, it ‘wins’. If we had a link written like:


    1. <a href=“#” id=“my-link” class=“my-link”>Our example link</a>


What colour would the text be, assuming no other styles? The text will be red. Following CSS specificity, the next most specific style is the class, and then the tag, as you can see in the web inspector. The problem with using ids in your code is that we rarely see the example above, with one id/class/tag selector on an item. More often, we’ll see ids used as context:


Let’s imagine that this is in a project. Later, we decide we don’t want one of the links in the header to have this dashed border. We quickly write to undo the style (another bad habit) …


… and give our special link that class. Problem solved, right? No. Ids are so specific in CSS, it takes a lot more than that to trump it. In order to beat our initial selector, we need to write:


Imagine this scenario repeating over various iterations. What if you have another link that needs different styles than the region?


Even with the special-link class, we have a border


This is why using ids in CSS is such a bad habit; because once ids are there, the problem perpetuates itself. Most ids in your CSS are easily changed to classes.


02. Long selectors


Not only is this selector using ids, it’s also long. Just like ids, if you’re using long selectors (that are greater than three levels deep) you’re increasing specificity. As a result, you’ll be compounding the problem over time as regular maintenance and updates occur.

The solution? Don’t write long selectors! For our previous example, was there any reason that using .logo by itself wouldn’t suffice? Probably not. In general, your selectors should be only two levels deep, or three at the most.


03. Inline styles

Inline styles are crimes of specificity and also violate the cardinal reason we use CSS: to separate style from structure. When the development community stopped using tables for layout and embraced CSS in external stylesheets, we also stopped mixing our styles in with our structural elements (and of course, stopped using structural elements to generate style).

From a specificity perspective, an inline style can only be overridden by an !important flag. Generally, that means if someone’s writing a style on that element and using the !important flag, they’re doing so as a reactive rather than proactive action. !important can be very handy in your CSS, but it must be used wisely rather than as a crutch.

Here’s how we might remove an inline style:


    1. <a href=“#” style=“text-decoration: underline; color: yellow;”>Link</a>


  • <a href=“#” class=“hazard-link”>Link</a> .hazard-link { text-decoration: underline; color: yellow; }



We simply abstract the inline CSS to a class.


Increased specificity to remove the border



04 Top-down CSS

Now we’re moving out of specificity to talk more about bad habits that may have made it into your workflow. Let’s imagine that we’ve received a design comp and are beginning to add styles to it once we’ve written out basic structure in HTML.

The problem with some CSS is that you can tell that it’s written in the top-down style. It mimics the HTML layout rather than abstracting the design elements, often using ids for context, such as #header, #content. This usually results in long selectors (how many times have you seen .menu ul li a {} ?), and the code is going to be really rough to debug and do maintenance on. To fix this CSS, you’ll need to work on abstracting design components from the page, which will also help you remove redundancy in your code.


05. Redundancy/DRY violations

Redundancy means you have a tendency to repeat yourself in CSS. In other languages on the web and in programming, it’s understood that if you repeat yourself, you’re wasting time, hence the maxim, DRY (don’t repeat yourself). So why would you repeat yourself in CSS? An example:


We can group these together:


You could also use a common name for them and add a modifier class to go with the title to show that it’s a different colour:


    1. <h3 class=“some-title pop”>My title</h3>


That’s more of an object-oriented CSS approach, so do what makes the most sense for your project and team. You may prefer using Sass @extend.


Sass is used to import a hack.scss partial, where comments will be hidden when compiled in production mode


In Sass, you can keep the separately named selectors and prevent having to remember where you put them with comma-separated combos, which makes it handy for abstracting design components. Our simple example would look like:


When the code is run through the preprocessor to convert from .scss to .css, the end product is:


This will generate the same display as if you had been repeating yourself in your CSS. DRYing up your CSS is best done by having a plan. Plan your components, strategise how they relate to each other and write better CSS by writing less of it.


06. Frittering with your units

If your stylesheet has a mixture of px, em, and rem for no particular reason, it’s time to do something about it. Rachel Nabors, a developer best known for her impressive CSS animations, is an advocate of em adoption for text, saying, “The first thing I notice in someone’s style sheets are the font-sizes. I replace all font-size pixel units with ems. With pixel density becoming one of the last things you can rely on with user devices, em-based units of measurement put the user back in control of legibility.”

If you feel like you should be adopting ems but need to get a better grasp on them, Ethan Marcotte’s classic book, Responsive Web Design, includes a great primer on the topic.

And, if you really aren’t a fan of ems and their nested qualities, rems (‘root em’ units) remain relative to the root element (which is usually the <html> element). The war over the various units of the web is ongoing, but having a course of action is essential for maintainability.

Now we’ve reach the third and final section of this article: the ‘you know better’ bad habits. Habits in this category include adding unnecessary clutter, mistakes, or plain lazy CSS…


07. Fallbacks and invalid declarations

If you’re lucky enough to get to use some of the fun, less-supported CSS3 attributes, rejoice! However, if you’re developing on the shiniest new machine on Chrome Canary, chances are some of your users are going to need fallbacks for those features. A very common bad habit is forgetting fallbacks completely.

If you used rgba(), do you have a fallback for that? Hopefully you do, otherwise don’t expect your IE8 users to see it. Have you covered all your vendor prefixes that you need? Later on, do you have a plan for removing some of those prefixes once they’re no longer needed? This is where a preprocessor can help with only writing once and using everywhere.

Along with misusing fallbacks, I’ve seen invalid declarations way too often. This CSS doesn’t do anything and doesn’t pass CSS Lint (or shouldn’t).

CSS Lint can help you out with this problem, and a general awareness goes a long way. If you spot something that doesn’t look right when you’re in the developer tools, delete it!


CSS Lint examines your CSS for bad habits and errors



08. Undoing styles

Harry Roberts’s article on when code ‘smells’ is a great chronicle of bad habits in CSS. He gives the following example of the problem with undoing styles with a ‘bad’ declaration followed by an improved solution. It practically speaks for itself:


Roberts’s suggested refactor (note that the 0 and none are removed):


The idea is that, if you wrote styles that you now have to essentially rewrite, there’s a problem. As Roberts says in his article, the chief problem with this habit is that “you’ll end up writing more CSS to achieve less styling”. If you’re abstracting your design components well, then you should be able to prevent this problem.


Developer Harry Roberts is author of the inuit.css framework



09. Cheater styles

Negative margins, !important, position: absolute combined with a specific pixel value: we all know these too well. They’re the ‘cheater’ styles, or anything where if asked to explain it, you could say ‘it just works’.

While plenty of us are guilty of this bad habit, a common solution in the field is to put hacks in a hack.css stylesheet.

Essentially, any time you’re writing a rule that you’re aware is a hack, it goes straight in this stylesheet, or partial. The partial is a particularly good idea because it will be hidden from the end user post-compilation.

Over time, it will become clear when some of these hacks are being written, which will help provide context for how to prevent being forced into them in the future. Did that feature lack requirements gathering, and cause a panic near the end of the sprint? Did the designer forget about edge CSS functionality on mobile when they made the feature? There are plenty of reasons we write hacks, but if we don’t remember when we write them, it can be hard to learn from our mistakes.


10. Not creating adequate documentation

Documentation is the least interesting, but most important (in terms of maintainability), aspect of your codebase, and it helps you understand and learn from your CSS. In most languages now, developers are putting their documentation right into their code.

Nabors says, “I try to write all my CSS as though I won’t wake up the next morning and someone else will have to finish my project. If it’s not immediately apparent what something does, try making the selector clearer, or if you can’t, add a clear commented explanation.”

The first step is to be wise about commenting and documenting within your CSS. The next step would be to adopt an engine that pulls out those comments into a living documentation guide. css_ doc and KSS are the current libraries commonly used in CSS documentation.

css_doc is very similar to JavaDoc, and is based on the CSSDOC convention. KSS, or Knyle Style Sheets, is a documentation specification, but also allows you to generate living style guides from your documentation, which is uniquely valuable in CSS to both the development and the design teams.



Now that we’ve gone over some of the bad habits that you may need to unlearn in your CSS, there are a few key points to remember. Doing something is always better than nothing. Having a strategy is often the best defence.

Leave a Reply