Using White Space For Readability In HTML And CSS

About The Author

Louis is a front-end developer, writer, and author based in Toronto, Canada. He curates the newsletters Web Tools Weekly and VSCode.Email and blogs about … More about Louis ↬

Email Newsletter

Weekly tips on front-end & UX.
Trusted by 200,000+ folks.

In this article, Louis Lazaris will show us how to use white space in development code to ensure that our files are as readable and maintainable as possible. He will offer some advice on how to make our code as performance-friendly as possible. This means concatenating and minifying as many assets as possible, thus serving the smallest possible files and the least number of files.

Right up front, I’ll offer some simple advice: In production, your code should be as performance-friendly as possible. This means, Gzip’ing, concatenating and minifying as many assets as possible, thus serving the smallest possible files and the least number of files. I don’t think anyone would argue that these suggestions aren’t best practices (even if we don’t implement them in every project).

White Space Readability
Well-written, readable code doesn't create mind games and labyrinths when other developers read it. (Image: Toca Boca)

Now that we’ve got that out of the way, how can we use white space in development code to ensure that our files are as readable and maintainable as possible? Well, we could consider a number of options, starting with some basics.

Basic HTML Indentation

I think most if not all of us add basic indentation in our HTML:

<header>

   <hgroup>
      <h1>Section title</h1>
      <h2>Tagline</h2>
   </hgroup>

   <nav>
      <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/about/">About</a></li>
      <li><a href="/services/">Services</a></li>
      <li><a href="/contact/">Contact</a></li>
      </ul>
   </nav>

</header>

<div class="main">
   <p>Content goes here.</p>
</div>

The principle here is that whenever something is nested, you indent, so that it’s clear where everything is in the markup’s hierarchy. With simple HTML nesting, the content in the <head> section is often neglected, but keeping the nesting consistent here, too, is good practice.

For example, the following sample code is fairly readable, even with no nesting:

<!DOCTYPE html>
<html>
<head>
<title>Foo</title>
</head>
<body>
<!-- content… -->
</body>
</html>

However, with much more content in the <head> section, nesting could make it easier to scan the contents:

<!doctype html>
<html class="no-js" lang="en">
   <head>
      <meta charset="utf-8">
      <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
      <title>HTML5 Please - Use the new and shiny responsibly</title>
      <meta name="description" content="Look up HTML5, CSS3, etc features, know if they are ready for use, and if so find out how you should use them - with polyfills, fallbacks or as they are.">
      <meta content="width=device-width, initial-scale=1.0" name="viewport">

      <link rel="shortcut icon" href="favicon.ico" />
      <link rel="apple-touch-icon-precomposed" sizes="114x114" href="apple-touch-icon-114x114-precomposed.png">
      <link rel="apple-touch-icon-precomposed" sizes="72x72" href="apple-touch-icon-72x72-precomposed.png">
      <link rel="apple-touch-icon-precomposed" href="apple-touch-icon-precomposed.png">

      <link href="https://fonts.googleapis.com/css?family=Francois+One|Open+Sans:400italic,400,800" rel="stylesheet">
      <link href="css/style.css" rel="stylesheet">
      <script src="js/libs/modernizr-2.0.min.js"></script>
      <script>if (location.host == 'h5bp.github.com') location.href = '//html5please.us/'</script>

   </head>
   <body id="gfs">
      <!-- content… -->
   </body>
</html>

This last chunk of code is taken from the HTML5 Please website. As you can see, when the content in the <head> section starts to get larger, indenting makes things a bit easier to digest at a glance. Notice that the <head> and <body> elements are indented, because they are both immediate children of the <html> element.

Of course, some developers might have a slightly different method of indenting in certain areas, but the idea is basically the same; the intention is to make the code easier to read in a development environment.

Basic CSS Indentation

In addition to indenting HTML, many developers (me included) will do matching indentation in any corresponding CSS. The following code would match the HTML shown in the first example above:

header {
   color: blue;
}

   hgroup {
      color: green;
   }

      hgroup h1 {
         line-height: 1.5;
      }

      hgroup h2 {
         font-size: 15px;
      }

   nav {
      background: purple;
   }

      nav ul {
         float: left;
      }

         nav ul li {
            font-size: 20px;
         }

            nav ul li a, nav ul li a:visited {
               text-decoration: none;
            }

.main {
   border: solid 1px #ccc;
}

To some, this seems a bit obsessive. But I prefer it because it helps me to scan the CSS and find matching hierarchies without having to read each selector. Of course, this type of hierarchy in your CSS should be used sparingly if you’re implementing modular CSS principles that encourage class-based modules and limited use of the descendant selector (for example, ul li).

Certainly, some of the code above is kind of awful; I wouldn’t recommend tying your heading and list styles to a specific context like that. But for the purpose of understanding this concept of indenting CSS, look at it as a theoretical example.

The point is that you have the option to indent CSS to match the HTML’s structure, thus making it easier to scan and easier to make sense of relative to the markup.

Of course, as is the case with a few things mentioned in this post, some of this doesn’t apply when you’re using a CSS preprocessor. For example, the nested selectors option for Sass would make this last tip quite different in such an environment.

Readable CSS3

Let’s take our abuse of white space even further. Many new CSS3 features allow for either comma-separated or space-separated value sets. Two simple examples are multiple backgrounds and transforms. Let’s see how we can make these easier to read:

.example {
   background: url(images/example.png) center center no-repeat,
               url(images/example-2.png) top left repeat,
               url(images/example-3.png) top right no-repeat;
}

.example-2 {
   transform: scale(.8)
              skew(20deg, 30deg)
              translateZ(0);
}

Notice what we’ve done here? Instead of keeping the entire value on a single line (which can get lengthy in some cases — especially when gradients and vendor prefixes are involved), we’ve put each value set on a new line, aligned with the one above it.

Thus, each of the three backgrounds is on its own line, and each transform function is on its own line, left-aligned with the first of each example.

Generally, this might go against the idea of having a single property per line (assuming, of course, that you’re not doing single-line rule sets). But when compared to the alternative of potentially really long lines, this is a good option, and it makes these rule sets very easy to read.

Dealing With Vendor Prefixes

As mentioned, if you’re preprocessing your CSS or using -prefix-free, then this advice doesn’t apply. But you could manipulate white space to make your vendor prefixes easier to read at a glance:

.example {
   -webkit-transform: scale(.8);
      -moz-transform: scale(.8);
        -o-transform: scale(.8);
           transform: scale(.8);
}

Here we’ve lined up the colons so that the values align, making it easy to scan all values to ensure they’re the same. I can’t tell you how many times I’ve adjusted only the WebKit value in a rule set like this and forgotten to do the rest. Of course, this illustrates the importance of preprocessing, but if you’re not doing that yet, then this use of white space is a good option to consider.

Additionally, many text editors offer a feature called “block edit” or multiline editing. This is available in Sublime Text, Vim, Coda and probably most others. Using this feature is that much easier when the values you’re changing are aligned vertically.

Readable File References

The gist of this next suggestion comes from a tweet by Twitter Bootstrap cofounder Jacob Thornton. The idea here is that if a list of file references is contained in your document, you can make them easier to read by doing something like the following:


<link rel="apple-touch-icon-precomposed" sizes="144x144" href="assets/ico/apple-touch-icon-144-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="assets/ico/apple-touch-icon-114-precomposed.png">
  <link rel="apple-touch-icon-precomposed" sizes="72x72" href="assets/ico/apple-touch-icon-72-precomposed.png">
                <link rel="apple-touch-icon-precomposed" href="assets/ico/apple-touch-icon-57-precomposed.png">
                               <link rel="shortcut icon" href="assets/ico/favicon.png">

The example above is taken directly from Bootstrap. Here, all href attributes of the <link> elements are aligned. This makes it easier to refer to or adjust a <link> tag because the update will usually be to the value of the href attribute.

Of course, this somewhat violates the rules of indenting HTML. So, alternatively, you could opt for this:

<link rel="apple-touch-icon-precomposed" sizes="144x144" href="assets/ico/apple-touch-icon-144-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="assets/ico/apple-touch-icon-114-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="72x72"   href="assets/ico/apple-touch-icon-72-precomposed.png">
<link rel="apple-touch-icon-precomposed"                 href="assets/ico/apple-touch-icon-57-precomposed.png">
<link rel="shortcut icon"                                href="assets/ico/favicon.png">

This latter example seems cleaner and has the bonus of aligning the other attributes, although that’s not as necessary in my opinion.

But wait. What if you don’t care that the href attribute is listed last (which seems to be the custom and is unnecessary for validation)? Then you could do this instead:

<link href="assets/ico/apple-touch-icon-144-precomposed.png" rel="apple-touch-icon-precomposed" sizes="144x144">
<link href="assets/ico/apple-touch-icon-114-precomposed.png" rel="apple-touch-icon-precomposed" sizes="114x114">
<link href="assets/ico/apple-touch-icon-72-precomposed.png" rel="apple-touch-icon-precomposed" sizes="72x72">
<link href="assets/ico/apple-touch-icon-57-precomposed.png" rel="apple-touch-icon-precomposed">
<link href="assets/ico/favicon.png" rel="shortcut icon">

No white space tricks needed here, because the href attributes align just fine. But if you’re bothered by the lack of alignment of the other attributes, or if you just can’t stand the thought of the href attribute being listed first, then you’ll have to opt for one of the preceding solutions.

Readable Conditional Classes

The concept behind the alignment of attributes is nothing new. HTML5 Boilerplate has been doing this sort of thing for some time now with its IE conditional classes. Here’s what that chunk of code looks like in the latest version:

<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->

In this case, the class attribute on the opening <html> tag in each conditional (and, incidentally, the tag itself) is being aligned, because this is the part of the code that’s most relevant to readability and maintenance, and the part of the code that would suffer most in readability if this alignment were not present.

Readable Comma-Separated Selectors

Sticking with Boilerplate, let’s go back to CSS. Here’s something used in that project’s main style sheet:

html,
button,
input,
select,
textarea {
   color: #222;
}

Here, instead of keeping all of the comma-separated selectors on a single line — which would be more difficult to scan — each selector is put on a new line. This can be helpful when the selectors are somewhat lengthy, as in this next example, also taken from Boilerplate:

.visuallyhidden.focusable:active,
.visuallyhidden.focusable:focus {
   clip: auto;
   height: auto;
   margin: 0;
   overflow: visible;
   position: static;
   width: auto;
}

Similar to the idea behind aligning HTML attributes discussed above, this vertical alignment makes the code a breeze to scan through when compared to scanning a single seemingly never-ending line of comma-separated selectors.

Can Your Text Editor Help With Any Of This?

As a long-time developer who has grown accustomed to coding by hand, my knowledge of the features of different text editors is fairly limited.

Some text editors or IDEs might do some of this automatically. Also, plugin developers can use some of these patterns to create plugins or extensions that do this sort of thing automatically or at the click of a button.

If you have any suggestions of built-in tools or extensions to text editors that can assist with this, I’m sure Smashing Magazine’s readers would be glad to hear about them.

Conclusion

We’re all encouraged to do whatever we can to make code in a development environment as easy to read and maintain as possible. I hope these suggestions will improve your code in this way.

And knowing that this use of white space won’t bloat our files is comforting — after all, this is not for production code. So, do whatever you feel is necessary to make your HTML and CSS easier to deal with, and be sure to minify those assets when deploying to production.

Finally, if you have any suggestions on using white space in HTML or CSS, we’d be glad to hear them.

Further Reading

Smashing Editorial (al, mrn)