Daily Tips & Tricks for Web Enthusiasts

HTML & CSS

Watch Out for Trailing Commas in CSS

When writing code there are a lot of situations where you need to provide a comma-separated list of things. Here’s how you create an array in JavaScript, for example:

var array = [foo, bar, baz];

This array contains foo, bar, and baz.

Some people, for clarity or just preference, will write that same code across several lines, like this:

var array = [
    foo,
    bar,
    baz
];

In JavaScript, the order of the items in an array matters. If you wanted to move baz up to the second position in the array you couldn’t just move that line up, because the commas wouldn’t be in the right places anymore.

In order to avoid this comma problem, and make it both easier and less error-prone to move things around, many people add a trailing comma to the last item, even though there’s nothing that comes after it, like this:

var array = [
    foo,
    bar,
    baz,
];

That makes it easy to move the items in the array around just by moving lines up and down. This is a common practice in many programming languages, and many people have developed a habit of placing a trailing comma after the last item in a comma-separated list like this.

Now, in CSS, you’ll also run into comma-separated lists of things. One of the most common things you’ll see is a list of selectors separated with commas, like this:

h1, h2, h3 {
    color: blue;
}

If you’ve picked up the habit of adding a trailing comma after the last item from another programming language you might be tempted to write something like the following (or you might see this in some CSS someone else wrote):

h1,
h2,
h3,
{
    color: blue;
}

Unfortunately, this CSS won’t work. Adding a comma after the last selector in CSS is not allowed, so adding the comma after the h3 selector will invalidate this selector list.

Furthermore, one of the interesting things about CSS is that any invalid selector in a list of selectors invalidates all of them. Thus, the comma placed after the h3 selector above will prevent the entire ruleset from working, so color: blue; won’t be applied to anything.

So, if you have some CSS that’s not working and you can’t figure out why, make sure you don’t have a trailing comma after the last selector!

Smart Line Height

The line-height property has some unexpected inheritance behavior when used with a length or percentage. Take this CSS, for example:

div.example {
    font-size: 20px;
    line-height: 1.5em;
}

div.example h2 {
    font-size: 40px;
}

With this CSS you might expect the line height of h2 elements inside div.example elements to be 60px, but that’s not the case. No, with this CSS, everything inside div.example elements will get the same 30px of line height regardless of their own font size, including those h2 elements.

Why is this? When you provide a length or percentage value for the line-height property the line-height calculation is made at that point, and that calculated value is used going forward. The em unit specifies a length, so we get the 30px of line height calculated immediately and used everywhere.

The good news is that there’s an easy way around this problem: Never provide a length or percentage value when using line-height. Instead use a number with no unit, like this:

div.example {
    font-size: 20px;
    line-height: 1.5;
}

div.example h2 {
    font-size: 40px;
}

Now the line height will be calculated by multiplying the font size of whichever element the line height is being applied to. This results in 30px of line height inside div.example elements by default, and 60px of line height on the h2 elements inside them, just as expected.

Set a Character Set

It’s important to define a character set for your HTML pages. The character set tells the web browser how the characters (letters, numbers, punctuation, etc.) are encoded, and doing so is a bigger deal than you might think.

The most common character set issue is special characters (including emoji) and other content not showing up properly. That’s annoying, but it gets worse. An incorrect or missing character set can actually be a significant security issue that opens the door to cross-site scripting attacks.

The good news is that defining a character set is easy. You just need to add a single <meta> element with a charset attribute as the first thing in your page’s <head>, like this:

<meta charset="UTF-8">

There are a few things you need to pay attention to when setting your character set:

  • The UTF-8 character set is highly recommended for pretty much all use cases these days.
  • Make sure the character set you define in your <meta> element matches the character encoding of the actual source files you’re using. You can usually select the character encoding in the preferences of your text editor, or when saving your files.
  • Make sure your character set <meta> element is the first thing in your <head>, as some web browsers will only look at the first 1024 bytes of a file before choosing a character encoding for the entire page.
  • Note that if the web server serving your page sets a Content-Type header, the character set defined in that header will override your <meta> element (but that doesn’t mean you shouldn’t set one in your HTML anyway).

Easy Layout Debugging with Outlines

When I’m working on a layout problem one of my favorite tricks to figure out what’s going on is applying outline: solid red 1px to the elements I’m working with. This works much better than borders because outlines do not affect layout, so my debugging outlines won’t get in my way or cause further problems.

This trick can easily be expanded for more complex debugging sessions too, just use different styles and colors on different elements. Here are some of my favorites:

.troublesomeElement {
    outline: solid red 1px;
}

.whatIsHappening {
    outline: dashed blue 1px;
}

.seriouslyWTF {
    outline: dotted orange 1px;
}

You can also combine this trick with some fancy selectors to make sure you remember to do certain things, like fill in blank links:

a[href=''] {
    outline: solid red 1px;
}

Intuitive Box Sizing

CSS is great, but it has some unusual quirks. One of its most annoying oddities has to do with how the width and height of elements are calculated. Take this CSS, for example:

div.example {
    width: 100px;
    height: 100px;
    padding: 10px;
    border: solid 2px;
}

You might expect the div.example element to be 100 pixels wide and 100 pixels high, as those are the values specified for the width and height properties, but you would be wrong. The CSS above will actually result in a div.example that has a width and height of 124 pixels.

Where did the number 124 come from? By default in CSS and element’s dimension are calculated using something called the content box model. That means the area where the content goes, in the middle of an element, are what the width and height properties apply to. So, in this case, our context box is made to be 100 pixels square. Then the padding and border are added on top of that. This results in a width of 124 pixels: 100 pixels of content width, 10 pixels of padding on either side, and 2 pixels of border on either side. 100 + 10 + 10 + 2 + 2 = 124. The height is calculated the same way.

Quirky, isn’t it? That’s not how most people think about this kind of thing. When you write something like width: 100px you expect the thing to be 100 pixels wide, right?

Well, I’ve got good news! You can specify a different box sizing model in CSS that actually does what you would expect. All you need to do is set the box-sizing property to border-box, like this:

div.example {
    box-sizing: border-box;
    width: 100px;
    height: 100px;
    padding: 10px;
    border: solid 2px;
}

Now, instead of the width and height properties applying to the content box in the middle of the element, they instead apply to the outermost border box surrounding the outer edge of the element. This results in a 100 pixel square box, which is much more intuitive.

I don’t know about you, but I vastly prefer the border-box model, which is why I almost always start every new project with the following CSS at the top of the stylesheet, which applies border-box sizing to all elements so I don’t have to think about it again:

* {
    box-sizing: border-box;
}