Pseudo class selectors are CSS selectors with a colon preceding them. You are probably very familiar with a few of them. Like hover:
a:hover {
/* Yep, hover is a pseudo class */
}
They are immensely useful in a variety of situations. Some of them are CSS3, some CSS2… it depends on each particular one. Outside of IE, they have great browser support. In IE land, even IE8, support is pretty barren. However, the IE9 preview has full support for them. The link-related ones work but not much else. Let’s take a brief look at each one of them. Don’t worry, there aren’t that many.
Link-related pseudo class selectors
:link
– Perhaps the most confusion-causing link-related pseudo-selector. Aren’t all <a>
links? Well not if they don’t have an href attribute. This selects only those that do, thus is essentially the same as a[href]
. This selector will become a lot more useful should any-element linking become reality.
:visited
– Selects links that have already been visited by the current browser.
:hover
– When the mouse cursor rolls over a link, that link is in its hover state and this will select it.
:active
– Selects the link while it is being activated (being clicked on or otherwise activated). For example, for the “pressed” state of a button-style link or to make all links feel more button-like.
There is a fun technique to remember all the link pseudo-class selectors. Look at the first letter of each: LVHA … LOVE HATE.
Input & link related pseudo class selectors
:focus
– Defining hover styles for links is great, but it doesn’t help out those who used keyboard navigation to get to the link. :focus will select links that are the current focus of the keyboard. This is not limited to links, but can be used (and really should be used) on inputs and textareas as well. Some would tell you to define a :focus style for anything that has a :hover style.
:target
– The target pseudo class is used in conjunction with IDs, and match when the hash tag in the current URL matches that ID. So if you are at URL www.yoursite.com/#home then the selector #home:target will match. That can be extremely powerful. For example, you can create a tabbed area where the tabs link to hash tags and then the panels “activate” by matching :target
selectors and (for example) using z-index to move to the top.
:enabled
– Selects inputs that are in the default state of enabled and ready to be used.
:disabled
– Selects inputs that have the disabled attribute. A lot of browsers will make the input a faded out gray, you can control that with this selector.
:checked
– Selects checkboxes that are, wait for it, checked.
:indeterminate
– Selects radio buttons that are in the purgatory state of neither chosen or unchosen (like when a page loads with radio button choices but no default is set).
:required
– Selects inputs with the required
attribute.:optional
– Selects inputs that do not have the required
attribute.
:read-only
/ :read-write
– Selects elements based on a combination of readonly
and disabled
attriutes.
Position/Number-based pseudo class selectors
:root
– Selects the element that is at the root of the document. Almost certainly will select the element, unless you are specifically working in some weird environment that somehow also allows CSS. Perhaps XML.
:first-child
– Selects the first element within a parent.
:last-child
– Selects the last element within a parent.
:nth-child()
– Selects elements based on a simple provided algebraic expression (e.g. “2n” or “4n-1”). Has the ability to do things like select even/odd elements, “every third”, “the first five”, and things like that. Covered in more detail here with a tester tool.
:nth-of-type()
– Works like :nth-child, but used in places where the elements at the same level are of different types. Like if inside a div you had a number of paragraphs and a number of images. You wanted to select all the odd images. :nth-child won’t work there, you’d use div img:nth-of-type(odd)
. Particularly useful when working with definition lists and their alternating <dt>
and <dd>
elements.
:first-of-type
– Selects the first element of this type within any parent. So if you have two divs, each had within it a paragraph, image, paragraph, image. Then div img:first-of-type would select the first image inside the first div and the first image inside the second div.
:last-of-type
– Same as above, only would select the last image inside the first div and the last image inside the second div.
:nth-last-of-type()
– Works like :nth-of-type, but it counts up from the bottom instead of the top.
:nth-last-child()
– Works like :nth-child, but it counts up from the bottom instead of the top.
:only-of-type
– Selects only if the element is the only one of its kind within the current parent.
Relational pseudo class selectors
:not()
– Removes elements from an existing matched set that match the selector inside the parameter of :not(). So for example, all divs except those with a class of “music” = div:not(.music). The spec says that :not selectors cannot be nested, but they can be chained. Some browsers (Firefox) also support comma-separated selectors as the selector parameter, although chaining them would be a far safter bet. Also useful in conjunction with attribute selectors, e.g. input:not([disabled]).
:empty
– Selects elements which contain no text and no child elements. Like:
Text-related pseudo class selectors / elements
::first-letter
– Selects the first letter of the text in the element. Typical use: drop caps.
::first-line
– Selects the first line of text in the element. Typical use: setting the first sentence in small caps as a typographical eye-catcher/lead-in.
:lang
– This pseudo selector is in the CSS3 spec but is only implemented in IE 8+. Will match anything that either has or is a descendant of an element with a matching lang attribute. For example, :lang(fr)
will match any paragraph, even without a lang attribute, if the parent body had lang="fr"
as an attribute.
Quick note
You can chain pseudo selectors just like you can chain class and ID selectors. This is particularly useful here while we are looking at :first-letter
and :first-line
. You probably wouldn’t want to drop cap every single paragraph on the page, but just the first one, so, p:first-child:first-letter { }
Content-related pseudo “elements”
::before
– Is able to add content before a certain element. For example, adding an opening quote before a blockquote or perhaps an preceding image to set apart a particular paragraph.
::after
– Is able to add content after a certain element. For example, a closing quote to a blockquote. Also used commonly for the clearfix, where an empty space is added after the element which clears the float without any need for extra HTML markup.
Pseudo Elements vs Pseudo Classes
The above two selectors are appropriately called pseudo “elements” (not selectors) because they don’t select any “real” element that exists on the page. This goes for these two, as well as the previous sections ::first-letter
and ::first-line
. Make sense? Like the first letter that ::first-letter
selects isn’t an element all to itself, it’s just a part of an existing element, hence, pseudo element.
Selector Style | Name | Does | Specificity |
---|---|---|---|
:: | pseudo element | selects/creates some actual content | 0 0 0 1 |
: | pseudo class | selects elements in certain conditions | 0 0 1 0 |
Tag Qualification
These selectors can be tag-qualified, meaning they will only apply if both the element (tag) and selector match. For instance:
p:first-child {
color: red;
}
That will only match if the first child of another element is a <p>
. If it’s not, it won’t match.
Deprecated
:contains()
– As far as I know, this is gone. The current CSS3 spec has removed it. I don’t know the story, let me know if you do. At a glance, it looks ridiculously useful (being able to select objects based on the textual content they contain). It may be because of problems, or having content in selectors being undesirable. My preference would be to have it select by elements rather than text, like p:contains(img)
, but alas, no such luck.
Update: There is a :has()
selector now!
::selection
– Allows the changing of style of selected text. It was drafted for CSS Selectors Level 3 but removed before it reached the Recommendation status. Despite this, it’s implemented in some browsers, which will probably retain experimental support for it. For Firefox, you can use ::-moz-selection. More information here.
Update: ::selection
is totally standard now, go ahead and use it!
jQuery Usage
jQuery can use all of these in its selectors, which is awesome. Even awesomer, jQuery has additional pseudo class selectors available.
:first
– Matches the first instance of the already matched set. This is different than :nth-child(1) which will only select if the selector matches and it’s the first child. With :first, the selector matches, then it takes the first one it finds regardless of child position.
:eq()
– jQuery doesn’t support It does now. This selects the Xth element from the already-matched set. It’s also zero-indexed (0 is the first element) unlike :nth-of-type
as a part of it’s selector engine, but this is very similar.:nth-child
in which the first element is 1.
:contains('text')
– This is removed from CSS, but it works in jQuery.
:lt()
– The same as :nth-child(-n+X), as in it selects the “first X elements”
:gt()
– The same as :nth-child(n+X), as in it selects everything except the “first (X-1) elements”
:even
– The same as :nth-child(even)
or :nth-child(2n)
:odd
– The same as :nth-child(odd)
or :nth-child(2n+1)
:has()
– Tests if the element has a descendant of a certain selector before matching, like :has("div.intro")
.
There are actually a whole bunch more, and all of them are clever and useful (or at least an improvement on readability) See the selector documentation for more.
jQuery can’t really help you with pseudo elements like ::before
and ::after
, but you can access their values in some browsers. E.g if a div had some ::before
generated content, you could get the value like:
var div = document.querySelector("div");
var content = window
.getComputedStyle(div, '::before')
.getPropertyValue('content');
Specificity
Class selectors and pseudo class selectors have the same specificity weight. Pseudo elements have the specificity of an element selector.
li {} /* specificity = 0,0,0,1 */
li:first-child {} /* specificity = 0,0,1,1 */
li:first-line {} /* specificity = 0,0,0,2 */
li.red {} /* specificity = 0,0,1,1 */
Typically they are used in conjunction or listed afterwards in CSS anyway, so hopefully it won’t cause too many problems…
ul li.friend { margin: 0 0 5px 0; }
ul li:last-child { margin: 0; }
In that case the zeroing out of the margin would work (assuming it matched the same element), but only because the zeroing out is listed second (they have the same specificity). So… watch for that.
Fascinating roundup – very useful, both as a reminder of things forgotten and as a source of new learning.
I bet I’ll be using :target in the near future…
Thanks Chris for summing this up. Great job, as usual :-)
Nice summary, thank you =)!
I too haven’t used :target until now. Will have to try that in future. Very useful post, thanks.
Thanks! Did you made a test for browser support? A table that helps deceiding when I can use the selectors would be really appreciated :-)
i was looking for smth like this for a lot of time now. Thanks
I didn’t actually realise there was this many of them!
The link based selectors are standard, I would imagine everyone know what each of them does and use them on a regular basis.
I have never really found myself needing to use a lot of them, but now I look at it and understand what they do, I might have to start using a couple… Especially :focus, :enabled & :disabled. Really would be good for adding that little extra to my contact forms.
The text related ones are quite a cool as well, is :first-letter supported across all the browsers?
Thanks for supplying all of these, just got to try and remember what they all do.
Very interesting summary. Not being a CSS whiz I love these insights into what can be done.
very nice! The parent/child selectors are going to make some thorny javascript go byebye.
Nice summary indeed!
There are a lot of them pseudo-classes I didn’t know of yet.
Thanx again.
In reply to my first comment: http://www.quirksmode.org/css/contents.html
Some pseudo-love!
another very useful article, really appreciate the work you put in, thx chris
Very useful! keep it up Chris!
Hey,
thank you for sharing such a nice summary.
Maybe you should mention the difference between pseudo-classes and pseudo-elements and the use of double or single colons (::)
Cheers,
dave
Nice, Chris! I wasn’t aware of the :not and :empty psuedo classes. Too bad both of these are available in IE. DAMN IE!
Great Post. I don’t tend to use :nth-last-child(N) and :nth-last-of-type(N) too often but may have to end up starting to use it more
Nice round-up!
Is the compatibility list for the browsers’ versions as simple as “it works in everything but IE version < 9"? I got a lot of clients trailing "browser-version-wise"… sadly.
Oh, you got a little typo here :
"You can chain pseduo selectors just like you can…”
Great stuff. Pseudo classes are great…the only issue is browser compatibility. Thx for the list though!
“Also used commonly for the clearfix, where an empty space is …”
The clearfix HACK is not a good thing. CSS needs an official, documented way of clearing floats.
Sure the clearfix HACK will be with us for the next 10 years minimum but that doesn’t mean we should just ignore this problem and not address is with a proper css attribute.
I like the ideas you’ve been posting around about a value for the overflow property for clearing floats.
But, to be clear, the clearfix isn’t a hack. It’s perfectly valid CSS. It’s getting it to work in IE 6/7 that uses hacks.
Ok, you’re right. But it just doesn’t “feel” right to have to define all that stuff to get a simple, highly desirable behavior.
Would you do an article on the reasoning behind why parent containers collapse when their children are floated. I can’t think of any scenario with any layout I’ve ever built where I _wanted_ a container to collapse. I think I prefer IE’s old behavior of always wrapping around floats. It’s just what makes the most sense 99.99999% of the time (in my layouts)
That’s a great idea. It’s weird… but there IS a reason it works that way. And actually, if it worked the other way, I think we would be complaining MORE.
I disagree but I’d have to see the scenarios where you think it would be more of a problem.
If you have a lot of images on a page with lots of text and each image tag was with a paragraph tag and for some reason all paragraphs were set to clearfix then it would not look great if a lot of the images were taller than their pagraphs.
But most of the time in my work when I use an image tag it’s in its own p/div/figure with a 1 sentence description. So, if that figure is floated it can run along side multiple paragraph blocks if needed.
It has nothing to do with whether or not you “want” a container to collapse. The reason that the container collapses is because when you add “float” to an element, it is then removed from the document flow. To quote SitePoint’s CSS reference on clearing floats: “A floated box is taken out of the flow, so it doesn’t affect the block-level boxes around it.” (which is the standard behavior and is required in order to make floats work properly.)
Right. Floats are like absolute positioning’s half cousin. They’re removed from the document flow… sort of.
The “highly desirable behavior” of floats is that they don’t affect block elements (that aren’t floated), but inline elements (like text) flow around them.
That’s why adding “float: left;” to an image in a paragraph just works as you expect: the image goes to the left, the paragraph doesn’t move, and the text flows around the image. Perfect.
However, that makes them finicky monsters for complex layouts. They’re probably the worst way to make complicated layouts … except for every other way.
@Lee: yeah, if an image is floated left in a paragraph and the image is longer than the paragraph, you want the next paras to flow round the image too. I think that’s what float was designed for – it’s just a shame we have to use it for everything else when avoiding tables.
The official way is display: table and display: table-cell etc. But guess who does not support that thus making it useless in real life. Hint: It’s the same browser that also only supports a few of this pseudo-selectors.
You forgot a:focus, which is what I usually use instead of a:active for tabbing support (highlight the current tabbed link).
Very nice round-up.
Too bad :contains that takes a selector (like Jquery’s :has() method) is probably not going to happen. I think every developer on earth would love it just to be able to do a:contains(img)
Some nitpicks:
For :first-child, I would state it this way: “Selects the element only if it is the first child of its parent.” Similar for :last-child. I interpret your current description (“Selects the first element of its type within a parent”) as closer in meaning to :first-of-type.
:before and :after are technically pseudo-ELEMENTS, not pseudo-classes. The difference, as you note, is that (a) you
canmust add content (many browsers won’t display them if there’s no added content), and they can accept more types of styles (such as clear:both;, which is why its used for the clearfix method).When are we going to get parent selectors? So, for example, if we want to set a property for the parent a tag wrapped around an img tag… which is almost always a bit of a pain. My latest solution is to just give linked images a class .imglink that overrides my other link styles so I don’t get a weird background or other odd behavior, but it would be so much simpler to set a css rule for img:parent a (or however the syntax would work – a:parent img?) Have you heard anything about this in CSS3? (or do we already have something like this that I’ve missed?)
I should say I give the parent “a” tag the imglink class… <a class=”imglink”><img…
I’ve asked the same question elsewhere. I once got a reply from someone claiming to be familiar with the code in both webkit and firefox and they said that 2 issues preventing it from happening were speed and the order in which the browser applies the css.
I honestly can’t believe the speed excuse. Pretty much every javascript library allows you to find an element and then climb the dom tree to its parent and ancestors. If jquery & prototype can do it, why can’t the browser do it even faster?
jQuery and friends only do their DOM traversals when you specifically ask them to, but the browser has to recalculate which CSS rules match on every dynamic page update and some user interactions as well. Imagine if you had
div:ancestor(a:hover) { font-weight: bold }
the browser would have to walk the DOM all the way to the root every time the user moved the mouse in or out of an A tag, and then potentially reflow a huge area of the document!
Good article. I haven’t found too many sites that explain the pseudo-class selectors that well. w3schools does not even cover more than the absolute basic ones. To be persnickety, though, you do also cover some pseudo-element selectors, which do not share the same name as pseudo-class. :)
Nevertheless, this article has been bookmarked!
For anyone who likes to explore the power CSS offers, this is another good article: http://www.smashingmagazine.com/2009/08/17/taming-advanced-css-selectors/
Excellent article Chris.
And it is all works in IE6 / IE7 ? (IE8?)
Awesome Post! I never knew about all the other pseudo selectors. Specially the one which enables us to select the last and the first element of an unordered list! It saves time and space to create extra classes for them (as and when required).
As always, very nice and easy explaining. I’ll redirect “n00bs” to both w3schools and css-tricks ;-)
I quote from the html specs:
At all times, exactly one of the radio buttons in a set is checked. If none of the elements of a set of radio buttons specifies `CHECKED’, then the user agent must check the first radio button of the set initially.
So how would that justify adding an indeterminate pseudo class in css?
Also, p:empty{display:none;} which seemed like an easy fix to where users could remove data that would otherwise be displayed in a p element, did its work too good. In some weird cases it also set display:none to p elements that were absolutely not empty.
So if you’re wondering why something is gone, skip this and just fix it server side ;-)
:root didn’t seem to work too well either in my html5 page(luckily it didn’t matter, I just wanted to test it)
I’d love to see a test case of :empty disappearing an element that isn’t empty, that’d be a good thing to get documented.
That’s interesting about the specs and the “exactly one” business. Wondering which doctype… got a link?
Where it tells about the exactly one:
http://www.w3.org/TR/html401/interact/forms.html#h-17.2.1
Since I’m more interested in html5 as “partner” of css3 I then checked the differences document. But I could not find any difference between html4 and 5 on radio buttons.
http://dev.w3.org/html5/html4-differences/
It could be I’m missing some specs, I can’t say I’ve read every document w3 ever created.
On the other subject;
It’s been a while since I found the bug. I just recreated it by adding p:empty{display:hidden;} on top of my stylesheet.
It seems that at the time I did not test any other browsers, if I did I would have known what I know now: It only affects webkit.
Screenshot of how it should be:
http://geuze.name/other/how_it_should_be.png
Then Safari
http://geuze.name/other/bug_safari:empty.png
Then Chrome(5)
http://geuze.name/other/bug_chrome:empty.png
The bug disappears as soon as you hover the element(s)(which makes it still annoying to see)
Maybe the used stylesheet is not the best there is(fairly certain of it) but I see no reason for it to fail on this other than it being a (rare) bug in webkit.
I mean’t p:empty{display:none;}
I just came back from celebrating St Patricks day ;)
Yep, meaning not one major browser is fully HTML4 compliant. The HTML5 specification has recognised this: http://dev.w3.org/html5/spec/forms.html#radio-button-group (the big green text, in case you miss it)
It’s poor UI in my opinion. The most popular option should be checked. If choosing nothing is valid, then a radio group isn’t a good fit because the user cannot easily revert the group to its indeterminate state.
Nice! Papa CSS sure does have a lot of “children.”
Hi,
Someone knows the real difference between pseudo-classes and pseudo-element ?
Both are very different but I still can’t differentiate them.
And I read over some website that there are pseudo-selector, pseudo-classes selector and pseudo-element selector. I’m so mixed !
The only pseudo-element I use are a:link, a:visited, a:hover. And I though they were call pseudo-classes !
Can someone can make it clear to me please ?
Thanks !
Very nice article Chris!
I like the clearfix method and will probably implement it from now on. Thanks!
Love these posts that shed some light on underused and relatively unknown code. It’s like finding a door with a dust covered handle…
Just hope there’s a floor on the other side ;)
:contains() is most likely going to return as :matches() or :any() although it most likely won’t make it into CSS3, most likely CSS4 or as a UA extension.
You can see the current discussion going on in the www-style mailing list archives.
Using nth-child a lot lately. Didnt think of using :first-letter and :last-letter to create a stylized quote or blockquote. Really wish CSS3 offered a “current” pseudo class for elements like links in navigations :-)
thank you,i’m a junior for css,usful for me
am i right??
through the study,i think i can do as say!
Great round up Chris, some stuff i didn’t know, so this will be very handy.
Nice round-up.
Cris, as expected – Wonderful plus infornative article.
I will certainly add p:first-child:first-letter {font-size:16px } to see if it has any positive effect on my readers at my blog.
– Aery
p:first-child:first-letter
This is not working in none Brwoser (FF, Safari, IE, …). What did i wrong?
Whats works is p:first-letter, but thats not what i want.
Chris this is a great explanation!
It would be great if there was some sort of chart with these… and maybe even which browser support each? Anyone know if one exists? Even if it’s not as thorough as your article above?
It is always so interesting and much appreciated what knowledge this site offers! But honestly, as long IE does not play well it can’t be used in the next, what, 10 years?
The necessary fallbacks for the mention browser make the use of all those great css handlings almost unnecessary.
:target would actually be extremely useful and save on page load times. You would then only need to code a JavaScript fix for IE, while other browsers would only need to load CSS. Also being able to check for a hash is pretty cool, without the need of PHP or JS.
Thanks for the article.
Hey Chris, great article. I forget to apply :focus on my forms all the time, just one of those things I need to get in the habit of!
Small typo, after the Quick Note header:
“You can chain pseduo….” should be
“You can chain pseudo….”
Another fantastic article. Making a note of a few of them now so I remember to include them in my next project. Thanks Chris.
What do you recommend to use if you want to add the attribute of a self-closing element to the page? (This makes more sense in XML.) I can use :before or :after but there is nothing to be before or after. Hope you understand what I mean.
Chris, awesome write up man! Can’t wait to go through it in detail!
SitePoint CSS Reference (http://reference.sitepoint.com/css/specificity) says about calculating specificity:
…
Count the class selectors (for example, .test), attribute selectors (for example, [type=”submit”]), and pseudo-classes (for example, :hover).
…
To calculate c, count the number of other attributes and pseudo-classes in the selector.
So I think the specificity of a pseudo class selector is NOT less than a regular class selector
what is the truth?
I think SitePoint is incorrect. I just did a test (current Firefox and Safari) and a real class selector (.test) beat out a pseudo selector (:nth-child) in a specificity battle every time. I even tested switching document order in case they were exactly the same.
i feel upset about this, so i tested too (FF3.6.2 and Chrome4.0.280)
please check this:
http://teamtom.net/homokozo/pseudo-class-spec-test/pseudo-class-specificity-test-1a.html
every second element colored green by :nth-child plus the first list element colored blue by a class
and then this:
http://teamtom.net/homokozo/pseudo-class-spec-test/pseudo-class-specificity-test-1b.html
the first element became green too, because i changed the order of the definitions
this proves me that the li:nth-child(2n-1) and li.first are the same specificity, and the last wins
what do you think?
You’re right, my test was flawed. In fixing up my own test, I found that the second selector, even when a psuedo selector, beat out the real class selector, proving they are of the same value.
I updated the article to be more correct. I also wish I could remember where I saw that chart originally because someone has it wrong.
QUESTION?
div id=asidegroup holding left and right asides can be set to opacity 0.2, then opacity 1.0 on hover… hover one and both pop into view. Here we style a physical div container for two objects in one physical location, and it works great!
Now, say we want all Chickadee snaps scattered across a page to flutter and chirp when we hover any chickadee… how do we do that? Now, take it further, please. Say we want all girl Chickadee snaps to flutter and chirp when one girl is hovered, and ditto the boys when a boy is hovered naturally… Here we want to isolate certain page objects in one style group containing physically isolated likely class-associated objects (but it could be a named group of ID’s as well). How do we do that?
I saw something like this on a Cornell Ornithology page, also on a Yellowstone Volcano page, but those were Mars Lander script. We want to explore style grouping using HTML5 and CSS3.
Chris, what you and TeamTom approach is at the programmatic scale a mix of very divergent word processor entities. For example, where :active traps yellow then :focus’ yellow here, then background sticks as a reminder of last accessed link until page surface is clicked – Internet Explorer. Whereas Chrome is unable to retain active focus instructions between literal instances, since it dives on primary, raw link-related focus implementation. Anyway, just as active imprints focus, setting active apart in the top reliability seat (top of this page, lol), well focus though less intrusive also consistently imprints the programmatic interface with the same reliability as, say, hover. I notice you have removed my older post here (guess it was not perfectly understood by all and sundry), where we challenged Nth of n using focus as a “delimiter”. In many ways focus is more reliable than hover, though its public profile is crudely scatted on by the likes of Google, rushing to implement as little as possible as quickly as possible. Let’s not pull the wool over our eyes, what? I mean, public interface we share here is a very small segment of what is Internet, each interface providing a unique set of programmatic interpolations. Where interface commanders (nor commandos) set the score, :focus would also be seated top-of-page. Is this too heady (or particular)?
You have an error in the description of last-child.
You said “…of its type…” but it should be “if the last element happens to be of that type” or so.
and that’s the definition for nth-last-of-type, not last-child… and great, somebody catched it 4 years ago ¬¬ and already commented it above.