Learning to Love the Boring Bits of CSS

Learning to Love the Boring Bits of CSS

The future of CSS gives us much to be excited about: On the one hand, there’s a whole range of new methods that are going to revolutionize the way we lay out pages on the web; on the other, there’s a new set of graphical effects that will allow on-the-fly filters and shaders. People love this stuff. Magazines and blogs are full of articles about them.

Article Continues Below

But if these tools are the show ponies of CSS, then I think it’s time we gave some love to the carthorses: the nuts-and-bolts components of the language, like selectors, units, and functions. I often call these the boring bits, although I say that only with great affection—an affection I think you should share.

To see why, let’s take a quick walk through some of the best of the new boring bits in CSS—the bits being worked on in half-lit laboratories away from the brilliance of the shiny new things in the shop windows. Some of these boring bits have been around for a while but deserve more recognition, while others are just starting to appear in browsers. But they’ll all be revolutionary to the way we work—albeit in humble, unassuming ways.

Relative size units#section1

It’s likely that, as the smart and forward-thinking developer you are, you’ve worked with relative sizing—that is, em units or percentages—so you’ll know this problem: having to use a calculator to work out sizes because of inheritance. For example, it’s pretty common nowadays to set a base font size for your document and then use relative sizing to set your fonts across the rest of the page. In CSS, that probably looks something like this:

html { font-size: 10px; }
p { font-size: 1.4em; }

This is fine, and not a problem at all, until you have a child element you want to set at a different font size. For example, in markup like this:

The cat sat on the <span>mat</span>.

If you want that span to be at a smaller font size, say 1.2em, what do you have to do? Get your calculator out and work out 1.2 divided by 1.4, resulting in this:

p span { font-size: 0.85714em; }

And the problem’s not limited to using em either. If you’re building a fluid site using percentages, you’ll know that the percentage is relative to its container; so if you have an element that you want to be 40 percent of its parent, the length of which is 75 percent, then the width of the element must be set to 53.33333 percent.

Not ideal.

Root-relative lengths#section2

To combat this font-sizing problem, we now have access to the rem (root em) unit. This is still a relative unit, but it’s always relative to a fixed base value, which is the font size of the root element of the document (in HTML, that’s always the html element). Presuming the same root font size of 10px that we used in the preceding example, the CSS rules required for the case at hand are:

p { font-size: 1.4rem; }
p span { font-size: 1.2rem; }

Now both rules are relative to the root font size, which is much more elegant and easy to work with, especially if you have a simple base like 10px or 12px. It’s sort of like going back to using px values again, only scalable.

This is one of the better-supported features in this article; it’s in all modern browsers including IE9, and only absent in Opera Mobile.

Viewport-relative lengths#section3

If you think the rem unit is cool (I do), you’ll be delighted to know there’s also a new set of length units to combat the percentages problem. These work in a similar way to rem, except that they’re relative not to a user-defined value on the document root, but to the dimensions of the device viewport itself.

The two main units are vh and vw, which are relative to the height and width (respectively) of the viewport. Each takes a number as a value, and that number is equal to the same percentage of the specified length. As I still remember the lessons of screenwriting school, let me show that rather than trying to tell it:

div { height: 50vh; }

In this example, the height of the div would be exactly half of the height of the viewport; 1vh = 1 percent of the viewport height, so it stands to reason that 50vh = 50 percent of the viewport height.

As the viewport size changes, so does the value of the unit—but the advantage of this over percentages is that you don’t have to worry about containing elements: an item with a value of 10vw will always be that wide regardless of the width of its parent.

There’s also a vmin unit, which is equal to the smallest of either vh or vw, and it was recently announced that a corresponding vmax unit would be added to the spec (although it hasn’t been at the time of writing).

As of right now these are in IE9+, Chrome, and Safari 6.

Calculated values#section4

When you’re working fluidly and/or responsively, you’ll doubtless come across the problem of mixing units—wanting to have a grid that’s sized in percentages but with fixed margins. For example:

div {
  margin: 0 20px;
  width: 33%; 
}

If your layout only uses padding and border, then you can use box-sizing to help you get around that, but it won’t help you with margins. A better, more flexible approach is to use the calc() value function, which lets you perform mathematical operations with different units, such as:

div {
  margin: 0 20px;
  width: calc(33% - 40px);
}

You’re not limited to using it only on width; you can use it anywhere length values are permitted—and if you want to go really deep down the rabbit hole, you can also use calc() inside calc().

IE9+ has this unprefixed (!), Firefox has it with the -moz- prefix (which should be unprefixed in release 16 or 17), and Chrome and Safari have implemented it with the -webkit- prefix. It doesn’t seem to be in mobile WebKit yet, however.

Load a subset of characters#section5

Snappy performance has always been important, but the broad range of mobile devices on the market now—each bringing great variability and uncertainty in connection speed—makes it perhaps even more so. One way to speed up page loading is to keep external file sizes down, which makes a new property for @font-face that aids in doing just that a very welcome addition.

The property in question is unicode-range, and it takes as a value a range of unicode character references. When pulling in external assets, only those specified characters are loaded from the font file, instead of the complete set. This code demonstrates how to load only three characters from the file foo.ttf:

@font-face {
  font-family: foo;
  src: url('foo.ttf');
  unicode-range: U+31-33;
}

This is especially useful if you’re using font icons and only want to show a subset on a given page. In one test I ran, using unicode-range shaved an average 0.85 seconds from the loading time of a font file, which is not insubstantial. Of course, your own mileage may vary.

This property is currently implemented in IE9+ and WebKit browsers like Chrome and Safari.

New pseudo-classes#section6

Units and values are all well and good, but it’s selectors and pseudo-classes that I get particularly excited about. Coming up with a clever selector pattern, even though it’s hidden away where only a hardy few may ever see it, makes me feel like a craftsman. To paraphrase Steve Jobs’ father: you should make the back of the fence look as good as the front even if no one else knows you’ve done it—because you’ll know.

When I first used :nth-of-type() it was a revelation, like I had kicked down the doors of perception. OK, I’m exaggerating a little. But there are a couple of new CSS pseudo-classes that are really worth getting enthused about.

The negation pseudo-class#section7

You probably won’t realize quite how useful the :not() pseudo-class is until you try it. The argument provided to :not() is a simple selector—no compounds. When a list of subjects is being made by a selector that includes :not(), any elements matching the argument will be excluded from that list. I know, that sounds complicated to me, too. But it’s actually quite simple.

Imagine this: you have an item list and you want to apply a rule to all its odd-numbered items, but never the last one in the list. At the moment you’d have to do something like this:

li { color: #00F; }
li:nth-child(odd) { color: #F00; }
li:last-child { color: #00F; } 

With the negation pseudo-class you can exclude the last item from the rule using :last-child as the argument, thus reducing the number of rules by one and making the code a little easier to manage:

li { color: #00F; }
li:nth-child(odd):not(:last-child) { color: #F00; }

It’s nothing groundbreaking, and as I’ve shown already you can work without it—but it’s quite useful. I had the opportunity to use it on a project built with embedded WebKit, and it proved its worth consistently. It’s honestly one of my favorite pseudo-classes.

That’s right, I have favorite pseudo-classes.

This is the most widely implemented of all the features in this article; it’s in IE9+ and all modern browsers, unprefixed. And if you’re familiar with jQuery, you may already be used to using this—it’s been in there since version 1.0, along with the similar not() method.

The matches-any pseudo-class#section8

The :matches() pseudo-class accepts as an argument a simple selector, a compound selector, a comma separated list, or any combination of those items. Great! But what does it do?

It’s most useful for cutting the cruft of multiple selectors. As a use case, imagine you have a bunch of p elements in different containers but you only want to select a few of them; perhaps the style rule you write would look something like this:

.home header p,
.home footer p,
.home aside p {
  color: #F00;
}

With :matches(), you can shorten that considerably by finding the commonalities in the selectors; in our example here all have .home at the start and end in p, so we can use :matches() to aggregate all of the elements in between those. Confusing? Here’s what it looks like:

.home :matches(header,footer,aside) p { color: #F00; }

This is actually part of CSS4 (CSS Selectors Level 4, to be precise), and in the same spec it mentions that you’ll also be able to use the same syntax—comma-separated compound selectors—in future versions of :not(). Exciting!

Today, :matches() is in Chrome and Safari with the -webkit- prefix, and in Firefox under its old name, :any(), with the -moz- prefix.

Do you love the carthorse yet?#section9

The best thing about all the new features in this article is that they solve real-world problems, from the small but annoying repetition of selectors to the new and ongoing challenges of building high-performance responsive sites. In fact, I can imagine using every single one of these features on a regular basis.

New features like filters may have higher visibility, but you’re far more likely to find the ones presented here useful on every one of your builds.

Each of them will make your professional life a little easier while expanding the possibility space of what you can achieve—and there’s nothing boring about that.

About the Author

Peter Gasston

Peter Gasston is a developer, writer, public speaker, and author of The Book of CSS3 (No Starch). He lives in London, England, and is currently working on his second book.

15 Reader Comments

  1. I’d be interested to know if there is a performance difference between using:

    li { color: #00F; }
    li:nth-child(odd) { color: #F00; }
    li:last-child { color: #00F; }

    vs using

    li { color: #00F; }
    li:nth-child(odd):not(:last-child) { color: #F00; }

  2. I’ve found that when doing responsive design, rem is easier to work with than px or %. That seems to be where it really shows it’s usefulness.

  3. @robweir and @jblatch1 The advantage over px is that it’s a relative unit; you can change the value at any time and all of your length values which use rem will scale automatically. For example:

    html { font-size: 12px; }
    h1 { font-size: 2rem; } <- 24px h2 { font-size: 1.5rem; } <- 18px p { font-size: 1rem; } <- 12px html { font-size: 14px; } h1 { font-size: 2rem; } <- 28px h2 { font-size: 1.5rem; } <- 21px p { font-size: 1rem; } <- 14px The advantage over em is that it's always relative to a fixed size, so you don't get the 0.546728em problem.

  4. I love A List Apart because I can find folks like you who love CSS (as I do), and I can learn from their big, selector filled brains. Fun article. Thanks!

  5. Great article!

    “Can’t use it on a daily basis blabla”.
    That doesn’t count. It’s very important to have this new stuff and it’s important to have it now. People like Glow (first comment) won’t be satisfied until we have daily browser updates bringing the hot new features automatically to everyone in the world, which won’t be a good thing, I guess.

  6. I hadn’t ever heard of the root relative unit until now.

    I could see myself setting font-size to 1px on the html element, (overwriting it in body to a more sane base) and then using rem as a pixel replacement everywhere. for instance, instead of the 10px base as seen in the article and using 1.2rem for 12px, I would set 1px base and use 12rem for a 12px match.

    Are there pitfalls that I’m not thinking of off-hand?

  7. Yep, it simplifies the math a lot and in my opinion. The reason why EMs are not very popular is because having to work with multiple digits decimals is a pain in the neck. REM is exactly what EMs should have been in the first place.

  8. I was got excited when I came to read Viewport-relative lengths and calculated values. Unfortunately, Browser compatibility was the issue that I can use them in my projects. Anyways, It was good to read such useful informative article.

  9. Thanks – very interesting. After years, I finally redesigned our web sites with CSS basically by playing around and looking up specific answers until things worked. Recently I updated a few pages with a new feature by sticking in a *gasp* one-column one-row table because I didn’t want to start all over with CSS, which I haven’t used in months.
    This inspires me to look into it again – and the descendents thing offers some great possibilities I hadn’t been aware of as swell.

  10. I think this is the part of the HTML story where these features and functions start to divide those who are HTML savvy into the amateurs and professionals.
    All very interesting stuff.

  11. Fortunately we have used CSS, and all we have to do is open our CSS file which stores the layout of the site, and change the number relating to the position of the image. That will change his position throughout the whole site. http://www.ahmedabadwebs.com

  12. I have habbit to use px values, it’s only matter of habit to change on rem value, but it’s good possibility to have these choice. Thing that i like most about CSS3 is that you can make “dynamic” effects almost like in Adobe Flash.

  13. Really a great post. All that looks really promising but as another user said, what about older versions of IE?
    I also think that pseudoclasses should be used only if you really need to because, when you have to modify/optimize some code made by others, it is always a pain to find appropriate selectors and so on.

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

Nothing Fails Like Success

Our own @zeldman paints the complicated catch-22 that our free, democratized web has with our money-making capitalist roots. As creators, how do we untangle this web? #LetsFixThis