CSS Coding Conventions
After nearly 20 years writing CSS, this is what I consider best practice. I wish I could give credit to the people I learnt these things from, but for the most part I simply don't remember where or when I picked it up.
Sort properties alphabetically
Declarations should be ordered alphabetically. This speeds up locating a property and also improves compression if it is used. Any other ordering is less intuitive, needs to be learned and is in danger of being arbitrary.
Why make the effort of sorting at all? For one thing, you will avoid accidentally duplicating properties, such as padding in the following example. I have seen this done way too often.
.note {
position: absolute;
z-index: 2;
height: 50%;
padding: 2em;
color: black;
background-color: white;
font-family: cursive;
line-height: 1.8;
padding: 1em; }
However, the biggest advantage is when it comes to debugging code. Studying code and looking for individual properties is time-consuming and mentally taxing. You know after a single glance that the following code does not include a width because you know exactly where it should be if it was there. In the above code you would look twice to be sure and you still might have missed it.
.note {
background-color: white;
box-shadow: 1px 1px 5px rgba(0,0,0,0.2);
color: black;
font-family: cursive;
font-size: 90%;
height: 50%;
line-height: 1.8;
max-width: 50ch;
padding: 2em;
position: absolute;
z-index: 2; }
One of only a few people I have found who agree with sorting CSS properties alphabetically is Eric Bailey and he makes some very good additional points:
Alphabetical is easy enough to pick up and have an organization repeat as a convention without having to invest too much time on upskilling an entire team on CSS theory.
Or:
The last thing I want to do is set my client up to fail. It's difficult to recommend any approach that I don't think the organization has the ability to maintain after the engagement ends, even if I personally think the approach is better.
Name classes and ids semantically
Semantics don't just apply to HTML, but to CSS naming too, and even to naming variables in any programming language; we usually call it "naming conventions" though. Aim to write meaningful, reusable class names.
This is a controversial one! If you're familiar with Bootstrap then you'll be familiar with the exact opposite of semantically named classes. My opinion is that about 95% of Bootstrap classes are bad.
For example: never use .h1 or .title, use <h1>; never use .address, use <address>; never use .btn, use <button>; never use .pos-absolute, call it something that indicates why it is positioned absolutely, such as .hover-widget; never use .h-100, why is it 100 high? Call it that and avoid absolute units.
<div class="grid">
<h2 class="fontSize20 mid-grey">Web Developer</h2>
...
</div>
.grid-layout {
display: grid; }
.fontSize20 {
font-size: 20px; }
.mid-grey {
color: #555; }
<section class="hero">
<h2>Web Developer</h2>
...
</section>
section.hero {
display: grid; }
.hero > h2 {
font-size: 1.25em;
color: #555; }
In fact, if you do this right, you will hardly even need classes anyway. For example, look at the source code for this page.
Duplicate selectors, not properties
In order to create a consistent design, different elements will require the same styles. As a result, there will always be a certain amount of duplication in CSS code - either selectors or properties. In order to improve the maintainability of CSS code, you should prefer the duplication of selectors.
footer {
background-color: black;
color: white;
font-size: 0.9em;
padding: 1em; }
aside {
background-color: black;
color: white;
padding: 1em; }
aside,
footer {
background-color: black;
color: white;
padding: 1em; }
footer {
font-size: 0.9em; }
Use !important sparingly
!important should be avoided as much as possible. If used, there should be a comment to explain why it is needed.
.no-borders {
border-style: none !important; /* !important used for utility class */ }
.ui-button {
color: inherit !important; /* !important needed to override PF theme.css */ }
One selector per line of code
By all means, minify your code afterwards but don't write code in minified form.
h1, h2, h3, h4, h5, h6 {
font-family: Arial, sans-serif; }
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: Arial, sans-serif; }
However, with the introduction of :is() and :where() we might not want to strictly keep this rule:
:where(h1, h2, h3) {
font-weight: 400; }
Having said that, sometimes you just need some common sense:
:where(
::-webkit-calendar-picker-indicator,
::-webkit-clear-button,
::-webkit-inner-spin-button,
::-webkit-outer-spin-button) {
color: hotpink; }
One property per line of code.
.modal {
position: absolute;
top: 10px; right: 10px; bottom: 10px; left: 10px; }
.modal {
bottom: 10px;
left: 10px;
position: absolute;
right: 10px;
top: 10px; }
Closing curly brace on the same line as the last property
The closing curly brace should be on the same line as the last property preceded by a space. This is an unusual one, but after years of writing CSS I saw some code done this way and immediately recognised that it was clearer - better - than my own code. I've done it that way ever since.
body {
color: dimgrey;
font-family: "Palatino Linotype", serif;
}
code {
font-family: "Courier New", monospace;
}
h1 {
font-size: 2.3em;
font-weight: 400;
}
summary {
cursor: pointer;
}
@media (prefers-reduced-motion) {
:root {
--transition: 0;
}
}
body {
color: dimgrey;
font-family: "Palatino Linotype", serif; }
code {
font-family: "Courier New", monospace; }
h1 {
font-size: 2.3em;
font-weight: 400; }
summary {
cursor: pointer; }
@media (prefers-reduced-motion) {
:root {
--transition: 0; }
}
Prefer long-hand properties.
This makes it easier (especially for inexperienced developers) to recognise what is overriding what and keep your specificity as low as possible.
.note {
background: white; /* background is short-hand for
background-image,
background-position-x,
background-position-y,
background-size,
background-repeat-x,
background-repeat-y,
background-attachment,
background-origin,
background-clip and
background-color! */
border: 1px solid; /* This sets border-color to initial, not to mention border-image. */ }
.note.error {
background: #f001;
border: 1px solid red; }
.note {
background-color: white;
/* Leave border-color as default */
border-style: solid;
border-width: 1px; }
.error {
/* Could add !important because this is a utility class */
background-color: #f001;
border-color: red; }
No CSS reset
For the record, I'm against using a CSS reset. CSS isn't broken, stop trying to fix it! In fact, it seems a little arrogant to think that you or I are the one to fix it if it were broken, though I suppose it's really just a misunderstanding. Learn to work with CSS instead of against it. The CSS Reset Contradiciton expresses it better than I can and is a good place to start if you're interested in reading more on this topic.
Miscellaneous rules
- Use hyphen-case, also known as kebab-case.
- Use lowercase. Careful, element selectors are not case-sensitive; class and id names are.
- Indent properties with one tab.
- Indent block comments with two tabs. This will make it easier to scan for comments.
- Put in the final, optional semicolon.
- No trailing white-space.
- CSS custom properties should be used sparingly. Using the rule 'Duplicate selectors, not properties' they will hardly be needed anyway.
Further suggestions
- Kevin Powell recommends writing a table of contents so you can more easily navigate your file using search and find. CSS files can become very long so this is a good idea.
Further reading
If you find this topic interesting, you might like my No-CSS page.