Understanding Pseudo-elements

In CSS, there are certain selectors you can use that act like you've injected new HTML into the page and have the flexibility to style those new imaginary elements. These are known as pseudo-elements.

CSS 2.1 has four of them:

  • :first-line allows you to style the first line of a block element
  • :first-letter allows you to style the first letter of a block element
  • :before allows you to inject and style content before an element, block or inline.
  • :after allows you to inject and style content after an element, block or inline.

Pseudo-elements can only be applied to the last "simple selector in a chain", as the recommendation says. A simple selector is either the univeral selector (*) or a type selector (I tend to call them element selectors) followed by attribute, ID or pseudo-class selectors.

p:first-line { /* this will work */ }
p:first-line span { /* this won't work */ }
p.intro:first-line { /* this will work */ }
p:first-line.intro { /* this won't work */ }
.intro:first-line { /* this will work */ }
#main:first-line { /* this will work */ }
body#about #content p.intro:first-line { /* this will work */ }

Because the pseudo-element is considered an element unto its own, the style can only be overridden by styling an elements that would be contained within the pseudo-element or by increasing the specificity on the selector. For example, look at the following HTML structure and its corresponding CSS:

<div id="main">
<p>Lorem ipsum ... </p>
</div>

#main p {color:#555;}
p:first-line {color:#000;}

The pseudo-element wins out and the first line is black and not gray. If you needed to override the style you'd have to increase the specifity. Like, if we wanted to override the style for an intro paragraph that was different from the rest of them.

p:first-child:first-line {font-size:2em}

This rule has an element selector and a pseudo-class selector (which counts towards the specificity rules just as a regular class selector) which has more specificity than just the element selector used before. I used the pseudo-class :first-child to reiterate something important: the pseudo-element must be last in the declaration.

Caveats

Internet Explorer only supports :first-line and :first-letter. The selectors :before and :after will not work — not even in version 7.

From JavaScript, there's no way that I've found to gain access to these additional elements that have been pseudo-injected into the page. In fact, detecting that these styles are even being applied appears to be impossible in anything but Firefox.

Published July 08, 2007
Categorized as HTML and CSS
Short URL: http://snook.ca/s/833

Conversation

17 Comments · RSS feed
Damien Buckley said on July 08, 2007

Thanks for this little snippet. With browser progression etc I'm using psuedo selectors more & more often though there is lttle in the way of explanations as to what will & wont work. Nicely done.

Ian said on July 08, 2007

Thanks for the read Jonathan :)

I'm curious however. Do you actually use pseudo elements? I personally don't for precisely the reason you mentioned in your Caveats. They don't work for the biggest browser market: IE.

The only reason I ask is; if you do use them, what sort of situations do you use them in? I for one can't see any advantage to them if I have to re-implement the functionality for IE. I may as well do it the same for all browsers.

Jonathan Snook said on July 08, 2007

@Ian: admittedly, I almost never use pseudo-elements. Some who are particular of their typography may play with the drop cap or first-line to lead into the content. You can do so somewhat consistently across browsers. Although, even then there are some further caveats that I haven't described. Like starting a sentence with quotes and using :first-letter. IE will only modify the quote mark whereas Firefox will include the quote mark with the first letter as the spec indicates you should.

I did use :after on a project to add textual decoration like » characters after links. For IE, I just used JavaScript to add them in manually. This meant only a fraction of the site's audience didn't get them but it wasn't a big deal if they didn't.

kimblim said on July 09, 2007

Thanx for that clarification Jonathan - I have also made a small example page with some of the pseudo selectors, which some of your readers might find useful: http://kimblim.dk/csstest/ - it has browser support and some very basic examples.

Harmen Janssen said on July 09, 2007

@Kimblim: That's a handy list you provided there :)
You might want to revise your example of :checked, though, 'cause Firefox does support it. (see: http://www.whatstyle.net/articles/18/pretty_form_controls_with_css)

Sorry to go off topic here, Jonathan. Thanks for an interesting article!

Matt Wilcox said on July 09, 2007

I thought that :hover and such were also pseudo classes - and the rule:

p:hover a { attribute : value; }

works fine in Gecko based browsers. Which makes perfect sense to me, it ought to work - but if I understand your explanation of the specification it should not work. Frankly I'm happy it does.

Matt Nish-Lapidus said on July 09, 2007

Have you heard about Dean Edwards' IE7 script? It's been around since 2004 and fixes exactly these problems. http://dean.edwards.name/IE7/

I still use it as part of my base scripts for most sites (those that I can reliably use JS on anyway) ... It's really amazing.

Matt Nish-Lapidus said on July 09, 2007

Also, as for what to use pseudo-classes for .. :first-child and :last-child are amazing for styling lists where you need different margins, styles, etc, for the beginning and end. no need for special classes in your markup any more.

also, :hover support in IE is fixed, which is amazing.

Jonathan Snook said on July 09, 2007

@Matt Wilcox: Yes, there are a number of pseudo-classes. What I'm talking about here is strictly pseudo-elements.

@Matt Nish-Lapidus: Yes, IE7Scripts can solve the before and after but can be a little heavy handed if you're just trying to fix something small. The :after fix I did for IE, for example, did use Dean's lovely library but it was causing loading issues. Instead, I was able to replicate what I needed in about 4 lines of code.

Maybe I'll go into more detail on pseudo-classes in my next post. :)

Peter Gasston said on July 09, 2007

In the CSS 3 Selectors module, pseudo-elements are distinguished from pseudo-classes by having a double-colon before them; ::before, ::first-letter, etc.

Chris said on July 09, 2007

This is a really slick trick. I will have to use it for a client design or one of my own soon! This lends way to making documents on the web flexible like a print document. Very slick.

Matt Wilcox said on July 09, 2007

My apologies, I had missed the distinction.

fathima said on July 09, 2007

Probably the only place I ever use pseudo-elements is when i use :after to clear floats, as was first (I think) demonstrated by Matt Brubeck. Adding height: 100% adjusts for IE incompatibilities, which is the only reason I've ever used this pseudo-element.

Now, with increasing browser progression, I look forward to breaking out the rest of the newfangled funkiness. And so Kimblim, I expect to make much use of your excellent list. :)

kimblim said on July 13, 2007

@harmen: Thanx for pointing that out. Apparently Firefox does support the :checked selector - it just doesn't support having a 1px red border on a checkbox ;) The page has now been updated..

Michael said on July 17, 2007

Jonathan,

I tried printing this out and it printed a blank page, the article but cut off the bottom, then a third blank page. Any thoughts?

mdawg

Jonathan Snook said on July 17, 2007

@Michael: I've just added a print stylesheet which should format things nicely for print. It removes everything but the article and the comments. Thanks.

Chris said on July 25, 2007

Some of these are quite slick and I am going to try a few with my latest client. I will let you know if they work out right. Thanks for the tip!

Sorry, comments are closed for this post. If you have any further questions or comments, feel free to send them to me directly.