Some of the most powerful CSS2 and CSS3 selectors defined in the specs are avoided by web developers because they’re not supported by commonly used web browsers. Sometimes in order to work around these shortfalls solutions with large overhead such as javascript libraries are used or code becomes littered with many specialized classes and sites become difficult to maintain.
Over time I’ve developed the habit of using specifically named class attributes to represent exactly where a pseudo-class would have applied. To aid in clarity and maintenance these classes are named with the same text as the name of the pseudo-class being represented:
- :first-child becomes .first-child
- :last-child becomes .last-child
- :first-of-type becomes .first-of-type
- :nth-child(odd) becomes .nth-child-odd
- :only-child becomes .only-child
- :empty becomes .empty
And so on.
Your Typical List of Links
Some of these classes I use on every site I build. First-child [or last-child] are particularly handy when dealing with horizontal lists or menus where you want different delimiters or padding around the items on the edges vs the items in the middle of the list. A simple example would be to use vertical borders to separate the items. If you put a left border on all of the items you need to find some way to not have a border on the left most item. In a perfect world the HTML and css would looks something like this:
ul li { float:left; padding: 0 1em; border-left: 1px solid black; }
ul li:first-child { border-left: none; }
<ul>
<li><a href="index.html">Home</a></li>
<li><a href="page2.html">Page 2</a></li>
<li><a href="page3.html">Page 3</a></li>
</ul>
Leaving no extra classes in the HTML at all. However, if your project must support browsers that fail rendering the above styles you’d update the HTML and CSS with the following simple additions:
ul li { float:left; padding: 0 1em; border-left: 1px solid black; }
ul li:first-child,
ul li.first-child { border-left: none; }
<ul>
<li class="first-child"><a href="index.html">Home</a></li>
<li><a href="page2.html">Page 2</a></li>
<li><a href="page3.html">Page 3</a></li>
</ul>
Remember, the class you’re adding should always represent exactly how the real pseudo-element behaves and thus the placement of the first-child class is important. For example you would not want to write the following HTML:
<ul>
<li><a class="first-child" href="index.html">Home</a></li>
<li><a href="page2.html">Page 2</a></li>
<li><a href="page3.html">Page 3</a></li>
</ul>
Even if you could style this example and the previous example to appear alike the danger is in the details. If in a later site revision you replaced the class selectors with the real pseudo-class selectors you’d wind up with totally different styling — in fact the pseudo-class version would apply to all the anchors in the list because they’re all first-children of their respective parent list item.
Legibility and Maintenance
Tossing classes into the HTML to have more ‘hooks’ to style with is nothing special. The key to these pseudo pseudo-classes working is the use of established names and established behaviors. Any developer can look at an element with class="first-child"
and know exactly what it represents. Usage of words like “first” or “linkA” or “item1” might be used in the same ways, but they might not evoke the exact same meaning. Perhaps the “link1” is the first link, but it may not be the parent elements first child. Or perhaps one project will use an “even” class on alternating list items, where another might call them “off” or “alternate”.
So there’s power in the distinction between “linkA” and “first-class” and there’s time saved by setting coding standards up front.
What about Pseudo-Elements?
CSS3 pseudo-elements are a bit trickier to duplicate by using using class attributes alone. But the principle of standardizing on the use of class names that are similar to the items they’re replacing. If I wanted to stylize the first letter of a paragraph in some special means I’d use a css selector such as p span.first-letter {}
and the necessary HTML to match instead of picking some other class name out of thin air.
Remember, the goal of pseudo pseudos is that there is a predefined behavior that you wish you could leverage, and you’re just looking for a way to duplicate that behavior in older browsers with the minimal amount of overhead and maximal amount of clarity and simplicity.
Comments Temporarily(?) Removed