By Harry Roberts
Harry Roberts is an independent consultant web performance engineer. He helps companies of all shapes and sizes find and fix site speed issues.
Written by Harry Roberts on CSS Wizardry.
N.B. All code can now be licensed under the permissive MIT license. Read more about licensing CSS Wizardry code samples…
My friend Tom recently gave an excellent talk titled Writing Readable Code. It’s only 15 minutes long, and is packed full of great little tips and pearls of wisdom. I’d highly recommend watching it.
After viewing Tom’s talk (three times now) I decided to jot down some of my own thoughts about what I find not necessarily readable code, but neat and tidy code.
I spend a lot of time reading other peoples’ code, and honestly, most of us could do better. Something I urge everyone to bear in mind is that pride in your work is something that transcends all skills levels.
One thing that the best developer in the world and the newest developer in the world both have in common is that either can be just as neat and tidy as the other: tidiness is divorced from skill or quality, and that’s some good news.
Pride in your work speaks for a lot, and leaving clean and tidy code behind you, among other things:
It seems like a very superficial thing to worry about, but to my mind, tidy code signals something more important: I would assume that a tidy developer has better attention to detail, is more likely to follow process, and is more likely to spot mistakes. Rightly or wrongly, I see it as a litmus test for more general approaches and attitudes.
Naturally this is very subjective, but to my mind tidy code is code that—separately to its function—is well documented, formatted, and presented. It’s more about cosmetics than it is about quality. So I guess herein lies a warning: bad code can still look tidy!
This means that one could conceivably write code littered with IDs and ridden
with !important
s and it could still look pleasing. The alternative title for
this article is Making Bad Code Look Good. You have been warned.
I cannot stress this enough: whitespace is free—use as much as you like!
Nothing feels more untidy, cramped, and claustrophobic than opening a file with a complete lack of whitespace:
.c-btn {
display: inline-block;
vertical-align: middle;
text-decoration: none;
text-align: center;
background-color: #C0FFEE;
padding: 0.5em 1em;
&:hover,
&:focus {
background-color: #BADA55;
}
}
.c-btn--secondary {
background-color: #BADA55;
&:hover,
&:focus {
background-color: #C0FFEE;
}
}
.c-btn--tertiary {
background-color: #DE1E7E;
&:hover,
&:focus {
background-color: #C0DEC5;
}
}
.c-btn--small {
padding: 0.25em 0.5em;
}
.c-btn--large {
padding: 1em 2em;
}
I mean, that just looks plain wrong, no?
When we scan text, we do so in saccades, which are rapid movements of the eye between fixation points. Whitespace creates these fixations points which help to guide the reader thematically: blank space between lines tells me that two or more blocks are separate; lack of blank spaces tells me that all code in a block is related. This helps people to focus on the smallest or most concentrated area at a time, allowing them to ignore anything that might not be immediately relevant.
.c-btn {
display: inline-block;
vertical-align: middle;
text-decoration: none;
text-align: center;
background-color: #C0FFEE;
padding: 0.5em 1em;
&:hover,
&:focus {
background-color: #BADA55;
}
}
.c-btn--secondary {
background-color: #BADA55;
&:hover,
&:focus {
background-color: #C0FFEE;
}
}
.c-btn--tertiary {
background-color: #DE1E7E;
&:hover,
&:focus {
background-color: #C0DEC5;
}
}
.c-btn--small {
padding: 0.25em 0.5em;
}
.c-btn--large {
padding: 1em 2em;
}
Immediately—even without syntax highlighting—that is instantly more readable, more parsable. At a glance I get a rough idea of the chunking of the code; I know that some pieces are closely related, and others less related, to the rest. The size of the gaps in the code are proprtional to the relation.
Let your code breathe.
As well as being useful for glancing at files, whitespace can also provide actual meaning. When I talk about semantic whitespace, I’m not necessarily talking about whitespace sensitive languages (like Sass or Python or Haskell), but about manipulation within a text editor or regular expression.
In my text editor, Vim, whitespace is actually meaningful—I can use empty lines
to navigate, delete, move, or otherwise manipulate code. In Vim, hitting {
will jump my cursor to the previous empty line, and }
will jump me to the
next. This means that I can jump around blocks of code just by using these keys.
But it gets better: I can combine the brace keys with other useful options and begin to manipulate code by the block:
d{}}}p
: Delete the block of code above my cursor, jump three blocks down the
file, paste the block back in.>}
: Indent the block below my cursor by one level.gU{
: Convert the block above the cursor to uppercase.For anyone whose editors have similar capabilities, whitespace isn’t just useful for scanning documents, but fundamental to the way we manipulate and edit them. A lack of whitespace is crippling, really giving productivity a huge knock.
To my mind, comments provide two key functions:
/* ==========================================================================
#BUTTONS
========================================================================== */
/**
* Buttons can be applied to any HTML element that is used to trigger a user
* action (e.g. following a call to action link, submitting a form).
*
* 1. Line differently sized buttons up a little nicer.
*/
.c-btn {
display: inline-block;
vertical-align: middle; /* [1] */
text-decoration: none;
text-align: center;
background-color: #C0FFEE;
padding: 0.5em 1em;
&:hover,
&:focus {
background-color: #BADA55;
}
}
/* Style variants
========================================================================== */
.c-btn--secondary {
background-color: #BADA55;
&:hover,
&:focus {
background-color: #C0FFEE;
}
}
.c-btn--tertiary {
background-color: #DE1E7E;
&:hover,
&:focus {
background-color: #C0DEC5;
}
}
/* Size variants
========================================================================== */
.c-btn--small {
padding: 0.25em 0.5em;
}
.c-btn--large {
padding: 1em 2em;
}
The main comment at the top acts as a title, and is prefixed with a hash (#
)
so that I can very easily grep for specific pieces of code (useful when looking
through compiled stylesheets). It grounds the file and introduces its intent.
Subsequent comments guide me around the sub-components of the file, or provide more granular details about the code itself.
Write more comments.
Tabs vs. spaces: it doesn’t matter which you use (as long as it’s spaces…) but what does matter is that you’re consistent. If you don’t have invisibles turned on in your editor then stop reading this post right now and go and enable them. If you’re not sure how to enable them, click this link. If you use Vim:
" Show invisibles
set list
set listchars=tab:»-,trail:·,eol:¬
Once you’ve turned invisibles on, your text might go from looking like this:
.c-banner {
display: block;
padding: 1em;
margin-bottom: 1em;
background-color: hotpink;
}
…to looking something like this:
.c-banner {¬
display: block;¬
»-padding:»-»-»- 1em;¬
»-margin-bottom: 1em;···¬
background-color: hotpink;¬
}·¬
Ewww! What’s all that? Was that there the whole time?
Yes, it was.
By turning on invisibles, we’ve immediately seen what a hidden mess our code was—mixtures of tabs and spaces, and a bunch of trailing spaces.
So many times I have opened a file that superficially seems tidy only to find that it’s a real mess of poor and inconsistent formatting. Turn on invisibles and ensure that you’re not leaving a total mess in your wake.
One thing that I really believe is that we should make it easy for people to follow our rules: I want them to have as few barriers as possible preventing them from doing the right thing.
Everyone has their own preferences, but a project should have its own consistent code style, and that may well differ from yours. This kinda sucks, but it’s just one of those things.
However, it does leave us with a bit of a dilemma:
So it’s quite likely that people are not going to adapt to a different but consistent coding style very readily. We need to automate it.
EditorConfig is a project designed to help…
…developers define and maintain consistent coding styles between different editors and IDEs.
It takes the form of a small dotfile, .editorconfig
, that lives in the root of
your project and defines simple rules for specific and/or all types of text file
you might edit. Two spaces by default, but four for Python? Easy. Delete all
trailing whitespace, except in Markdown where it’s meaningful? Done.
# editorconfig.org
root = true
[*]
charset = utf-8
indent_size = 2
indent_style = space
trim_trailing_whitespace = true
[*.js]
indent_size = 4
[*.py]
indent_size = 4
[*.{md,markdown}]
trim_trailing_whitespace = false
The beauty of this is that you don’t have to manually or consciously change your own coding style; you just carry on as you ever would and everything is taken care of for you.
Your editor probably supports EditorConfig, so you should definitely check it
out. Then define your
team’s style (best of luck) and check your agreed .editorconfig
into your
project.
Git has a bunch of whitespace related settings that will mark errors with mixed
tabs and spaces in diff
s. Take a read of the docs:
$ git --help config
…and then once in your pager, search for core.whitespace
by first hitting /
(forward slash) to enter search mode, and then typing:
core\.whitespace
Taking a look through those settings, you’ll likely be able to enforce some rules specific to your project, for example:
$ git config core.whitespace tab-in-indent
…will mark lines starting with tabs as being errors.
Read more in the documentation.
Something I’ve implemented with a few clients now is the idea of a template which they use to pre-populate all new files with. The template can contain exactly as much or as little as you like, and should be used to get developers started with a file containing the correct formatting and layout for them to build upon.
I set up a template file for inuitcss’ maintainers to use so that they could very easily follow the code style we laid out. That template file looks like this:
/* ==========================================================================
#TITLE
========================================================================== */
/**
* Long-form comment.
*
* This spans multiple lines and is also constrained to no longer than 80
* characters in width.
*
* 1. Provide line-comments like this.
*/
.X-class {
color: red; /* [1] */
}
/* Sub-title
========================================================================== */
Right out of the box we get:
=== */
lines)If we want to do things relatively long-hand, developers can simply duplicate
this file and rename it on the filesystem, but that feels a little cumbersome…
Because this file lives in its own GitHub
repository, it is accessible at an HTTP
endpoint. This means it’s curl
able: from right there on the CLI, a developer
can run the following
command:
$ curl -L git.io/inuitcssnew -o _layer.file.scss
…which will create a brand new, on-spec inuitcss file called _layer.file.scss
on their machine.
N.B. I’m using GitHub’s own URL shortener to have a nice short URL as opposed to something more verbose.
If we don’t want to save the file to disk immediately, or we’d rather just get to work right away, we can pipe the curl output straight into our text editor:
$ curl -L git.io/inuitcssnew | vim -
N.B. Passing the -
flag to Vim opens it with the contents of STDIN.
Or—another bonus for the Vim users—we can open a totally blank file that does not yet exist:
$ vim _components.buttons.scss
…and then use the read
command to read the contents or a local template file
into the current, empty buffer:
:read ../path/to/_template.scss
You can see a GIF of that in action.
As superficial at it may seem, writing neat and tidy code can be a very valuable exercise, and I don’t think I can overstate this enough: no matter your experience or skill level, you can all write neat and tidy code.
N.B. All code can now be licensed under the permissive MIT license. Read more about licensing CSS Wizardry code samples…
Harry Roberts is an independent consultant web performance engineer. He helps companies of all shapes and sizes find and fix site speed issues.
Hi there, I’m Harry Roberts. I am an award-winning Consultant Web Performance Engineer, designer, developer, writer, and speaker from the UK. I write, Tweet, speak, and share code about measuring and improving site-speed. You should hire me.
You can now find me on Mastodon.
I help teams achieve class-leading web performance, providing consultancy, guidance, and hands-on expertise.
I specialise in tackling complex, large-scale projects where speed, scalability, and reliability are critical to success.