There’s more to writing good front-end code than knowing every HTML tag, CSS selector, or the latest front-end features and techniques. And as I mentioned in a recent blog post, writing good code takes a lot of patience and practice. But how do you know if you’re writing good code, especially if you’re just learning how to code?
Using real-world examples found on several websites, let’s take a look at common “red flags” to look for when writing code and evaluating its quality.
Contents
Complex, Overqualified Selectors
Look out for complex CSS selectors. For example:
.wrapper .main .post a {...}
These are one of the most “expensive” selectors in CSS because browsers have to parse a lot of extra elements and selectors. Try to make your selectors as lean as possible:
.post a {...}
Instead of having an overly specific selector, it’s usually best to create a class for a particular element:
.continue {...}
Qualifiers in selectors should also be avoided, as they are not reusable, too specific, and create more work for the browser. The nav
and p
qualifiers in the following selectors are an example of this:
nav.social { float: left; } p.intro { font-weight: bold; }
What if at some point you need to use the .social
class in a ul or the .intro
class in a span? Avoid having to dig through your CSS to fix what you should have done correctly from the get-go, or worse, rewriting the rules unnecessarily.
Relying on Parent Selectors
A parent selector lowers the specificity of a child element. Sometimes you can’t avoid them (with anchor elements, for example), but if you have selectors like the following:
.sidebar { ... } .sidebar .title { ... }
a better approach is using a namespace as a modifier.
.sidebar { ... } .sidebar-title { ... }
This keeps sidebar-title
self-contained and modular — it doesn’t rely on the parent selector and can be used anywhere.
Repeating CSS
Avoid repeating the same chunks of code. Look for property/value pairs that are repeated multiple times throughout the stylesheet, then logically group them so that there’s only one occurrence of that block of code.
.label { display: inline-block; } .button { display: inline-block; border-radius: 10px; } .field { display: inline-block; border-radius: 10px; padding: 5px; }
Always think “DRY”(Don’t Repeat Yourself):
.label, .button, .field { display: inline-block; } .button, .field { border-radius: 10px; } .field { padding: 5px; }
Resetting and Forcing CSS Values
Keep an eye out for rules where you are rewriting CSS properties or setting them back to their initial values. For example:
h2 { font-size: 1.2em; font-weight: 700; padding-bottom: .5em; border-bottom: 1px solid; }
h2
styles are then reset further down in another rule:
.post h2 { font-weight: 500; padding-bottom: 0; border-bottom: none; }
When adding new components, you shouldn’t need to recode or undo patterns and problems you’ve already solved with existing CSS. Instead, a better solution would be to create the following rules:
h2 { font-size: 1.2em; } ... .secondary-headline { font-weight: 700; padding-bottom: .5em; border-bottom: 1px solid; } .post-title { font-weight: 500; }
Also, !important
declarations should never be used to force a CSS value –– avoid using them unless absolutely necessary.
.last { border: none !important; }
!important
breaks the natural order of the cascade and, when abused, can lead to maintenance and specificity nightmares. There are few use cases for !important
, for example: temporarily testing or debugging CSS issues, overriding certain inline styles when you have no control over the HTML, and aiding accessibility –– just be careful with it.
Excessive Markup
Look for unnecessary use of HTML tags being used for layout:
<p><h4>UX - User Experience Design</h4></p>
There’s no need to wrap the block-level h4
in a p
. If you’re using the <p>
to give the <h4>
extra margins or padding, that needs to be solved in the CSS instead.
IDs Instead of Classes
Avoid using an ID wherever you can use a class. IDs are heavy on specificity and cannot be reused. The nav ID shown below can only be used once in a page.
<ul id="nav"> ... </ul>
What if you need to add a nav component? Use classes instead:
<ul class="main-nav nav"> ... </ul> ... <ul class="footer-nav nav"> ... </ul>
.nav a { display: block; color: white; padding: 5px; } .main-nav a { border-bottom: 1px solid; font-size: 1.1em; } .footer-nav a { border-bottom: 1px dotted grey font-size: .85em; }
It’s best to use IDs as JavaScript hooks or as fragment identifiers in a page. Certainly avoid using one ID for styling, JavaScript, and as a fragment identifier. Doing so will make your architecture fragile because you’re setting up dependencies among CSS, JavaScript, and the fragment identifier.
Closing Thoughts
Front-end code that is poorly thought-out can be a strain on maintenance and development in the long run. When writing code, your goal should be making sure that it’s reusable, maintainable, and scalable. Your CSS should also be predictable, so if you need to update or add new components, they shouldn’t affect other parts of your site.
Keep in mind that at some point your site or application will need to scale, which might require more developers working on and maintaining the code. That’s why it’s important to write code that can be easily managed by designers and developers who are looking at our code for the first time.
Very helpful article. Thanks.
Serkan
good, very easy, thanks guil
The suggestion to not use qualifiers is anything but substantial.
Awesome article, hopefully more front end devs will take note on some of these. I know I still make a few of these mistakes when coding (like repeating css). One of my biggest pet peeves though is excessive mark up like tags and empty paragraph tags.
“Avoid using an ID wherever you can use a class. ”
I don’t know if this is sound advice. The drawbacks you mentioned are also the strengths of id selectors.
While ID selectors definitely have their place, I think this post is focussing more on making your code “reusable, maintainable and scalable”. And using classes is definitely a much better way of achieving this goal than IDs.
Depends entirely on how you use IDs. Some things SHOULD only exist once on the page, for example. Using IDs with such things actually helps keeping code “reusable, maintainable and scalable”.
Even the “issues” the writer mentions with parent selectors (that something defined with a parent selector only affects items in that parent) is a strength of doing so. Lets you narrow a scope. Also lets you set things up so the client can just add or change content in the WYSIWYG editor and have things display properly.