CSS is one of the most powerful tools that is available to web designers (if not the most powerful). With it we can completely transform the look of a website in just a couple of minutes, and without even having to touch the markup. But despite the fact that we are all well aware of its usefulness, CSS selectors are still not used to their full potential and we sometimes have the tendency to litter our HTML with excessive and unnecessary classes and ids, divs and spans.
The best way to avoid these plagues spreading in your markup and keep it clean and semantic, is by using more complex CSS selectors, ones that can target specific elements without the need of a class or an id, and by doing that keep our code and our stylesheets flexible.
When we are writing our CSS we have to keep in mind that some selectors will rank higher than others in the cascade, the latest selector that we wrote will not always override the previous ones that we wrote for the same elements.
So how do you calculate the specificity of a particular selector? It’s fairly straightforward if you take into account that specificity will be represented as four numbers separated by commas, like: 1, 1, 1, 1 or 0, 2, 0, 1
Firebug lets you easily see which selector is being applied to an element.
Useful links:
There are 6 different types of attribute selectors:
This will match all the
Another useful usage of attribute selectors is to target different types of
This will target all the
Now let’s say you want to add a different icon next to each different type of file your website is linking to, so your website’s visitors know when they’ll get an image, a PDF file, a Word document, etc. This can be done by using an attribute selector:
In this example, we’ve used an attribute selector that will target all the links (
Notes on browser support
Apart from Internet Explorer 6, all major browsers support attribute selectors. This means that when you are using attribute selectors on your stylesheets, you should make sure that IE6 users will still be provided with a usable site. Take our third example: adding an icon to your links adds another level of usability to your site, but the site will still be usable if the links don’t show any icons.
For example, if you want to match all the
You can also use both child and descendant selectors combined. For example, if you want to target only the
Notes on browser support
Like the attribute selectors, the child selector is not supported by Internet Explorer 6. If the effect you are trying to achieve by using it is crucial for the website’s usability or overall aesthetics, you can consider using a class selector with it, or on a IE-only stylesheet, but that would detract from the purpose of using child selectors.
The adjacent sibling combinator can be very useful, for example, when dealing with text. Lets say you want to add a top margin to all the
You can be even more specific and say that you only want this rule applied if the elements are within a particular
Or you can add another level of complexity: say you want the first line of the paragraphs of every page to be in small caps.
Because you know that the first paragraph of every post immediately follows an
So if you need to target all the
Notes on browser support
Internet Explorer 6 doesn’t understand sibling combinators, but, as for the other cases, if your audience includes a small percentage of IE6 users, and if the website’s layout isn’t broken or severely affected by its lack of support, this is a much easier way of achieving lots of cool effects without the need of cluttering your HTML with useless classes and ids.
There are two types of dynamic pseudo-classes: link and user action ones. The link are
From all the CSS selectors mentioned in this post, these will probably be the ones that are most commonly used.
The
The
You can use more than one user action dynamic pseudo-class in your stylesheets, so you can have, for example, a different background color for an input field depending on whether the user’s cursor is only hovering over it or hovering over it while in focus:
Notes on browser support
The dynamic pseudo-classes are supported by all modern browsers, even IE6. But bear in mind that IE6 only allows the
Let’s take another example: you want all your
Notes on browser support
IE6 doesn’t support the
For example, lets say you want a specific link on your site to have a different background color, depending on that page’s language:
The selectors will match that particular link if the page’s language is either equal to “en” or “fr” or if it starts with “en” or “fr” and is immediately followed by an “-”.
Notes on browser support
Not surprisingly, the only version of Internet Explorer that supports this selector is 8. All other major browsers support the language pseudo-selector.
For example, lets imagine you have a long page with lots of text and
Notes on browser support
This time, Internet Explorer is really annoying and has no support at all for the
So you can say that any
You can also say that all checkboxes that are checked should have a left margin (to be easily seen within a long list of checkboxes):
Notes on browser support
All major browsers, except our usual suspect, Internet Explorer, support the UI element states pseudo-classes. If you consider that you are only adding an extra level of detail and improved usability to your visitors, this can still be an option.
You can target a single child, by defining its value as an integer:
This will turn the text on the third
You can target a parent’s children using expressions. For example, the following expression will match every third
In the previous case, the first yellow
In this case, the first yellow
The value of
Using one of the examples above:
Instead of matching the first four
You can also use the values “even” or “odd”, with the difference that in this case they will count the children starting from the last one:
This can be very useful if we want to target elements that may contain different elements within them. For example, let’s imagine we want to turn every second paragraph in a block of text blue, but we want to ignore other elements such as images or quotations:
You can use the same values as you would use for the
We can be even more clever, and combine more than one of these pseudo-classes together on a massive selector. Let’s say all images within a post
So in the first part of this selector, we are targeting every image starting from the second one. In the second part, we are targeting every image except for the last one. Because the selectors aren’t mutually exclusive, we can use them both on one selector thus excluding both the first and last element at once!
Let’s image you don’t want the last paragraph within your post
This selector will target the last paragraph that is a direct and the last child of an element with the class of “post”.
For example, you can target the first paragraph that is a direct child of a particular
With this selector you make sure that you are targeting only paragraphs that are direct children of the “post”
The
Let’s say you have several boxes (“news”) with paragraphs of text inside them. When you have more than one paragraph, you want the text to be smaller than when you have only one:
In the first selector, we are defining the overall size of the
How can this be useful? Image you have a sequence of posts, each one represented by a
It can be useful in a number of ways. For example, if you have multiple boxes in your “sidebar”
Beware that even if there is a single space in the “box”
Notes on browser support
Internet Explorer (up until version 8) has no support for structural pseudo-classes. Firefox, Safari and Opera support these pseudo-classes on their latest releases. This means that if what it’s being accomplished with these selectors is fundamental for the website’s usability and accessibility, or if the larger part of the website’s audience is using IE and you don’t want to deprive them of some design details, it’s be wise to keep using regular classes and simpler selectors to cater for those browsers. If not, you can just go crazy!
For example, this can be useful if you need to style all the
Another example: you want all the paragraphs within your post
Can you image the number of possibilities this selector brings with it, and the amount of useless selectors you could strip out off your CSS files were it widely supported?
Notes on browser support
Internet Explorer is our usual party pooper here: no support at all, not even on IE8. This probably means that this selector will still have to wait a while before some developers lose the fear of adding them to their stylesheets.
Pseudo-elements exist in CSS 2.1, but the CSS 3 specifications state that they should be used with the double colon “::”, to distinguish them from pseudo-classes. In CSS 2.1, they are used with only one colon, “:”. Browsers should be able accept both formats, except in the case of pseudo-elements that may be introduced only in CSS 3.
This is particularly useful to add subtle typographical details to your text blocks, like, for example, transforming the first line of an article into small caps:
If you’ve been paying attention, you’ll know that this means the paragraph that comes immediately after an
You could also refer to the first line of a particular
Or go one step farther and target specifically the first paragraph within a particular
Here, the “>” symbol indicates that you are targeting a direct child the post
Like the
Here is how you could use the
Bear in mind that if you use both
This element can sometimes produce unexpected results, if you’re not aware of the W3C specs: it’s actually the CSS selector with the longest spec! So it’s a good idea to read them carefully if you’re planning on using it (as it is for all the other selectors).
These elements will inherit many of the properties of the elements that they are being attached to.
Image you want to the words “Graphic number x:” before the descriptions of graphs and charts on your page. You could achieve this without having to write the words “Graphic number”, or the number itself yourself:
What just happened here?
First, we tell the HTML to create the “image” counter. We could have added this property to the body of the page, for example. Also, we can call this counter whatever name we want to, as long as we always reference it by the same name: try it for yourself!
Then we say that we want to add, before every paragraph with the class “description”, this piece of content: “Figure number ” — notice that only what we wrote between quotes will be created on the page, so we need to add the spaces as well!
After that, we have
The next property is there so that the counter knows that for each
It’s not as complicated as it looks, and it can be quite useful.
The
Fun fact: the
Notes on browser support
These pseudo-elements are supported by IE8 (not IE7 or 6), if the single colon format is used (for example,
If you’re a bit more adventurous, or if you’re not afraid of letting go of the past filled with useless and non-semantic classes and ids, why not sneak one or two of these powerful CSS selectors into your next project? We promise you’ll never look back.
The best way to avoid these plagues spreading in your markup and keep it clean and semantic, is by using more complex CSS selectors, ones that can target specific elements without the need of a class or an id, and by doing that keep our code and our stylesheets flexible.
CSS Specificity
Before delving into the realms of advanced CSS selectors, it’s important to understand how CSS specificity works, so that we know how to properly use our selectors and to avoid us spending hours debugging for a CSS issue that could be easily fixed if we had only payed attention to the specificity.When we are writing our CSS we have to keep in mind that some selectors will rank higher than others in the cascade, the latest selector that we wrote will not always override the previous ones that we wrote for the same elements.
So how do you calculate the specificity of a particular selector? It’s fairly straightforward if you take into account that specificity will be represented as four numbers separated by commas, like: 1, 1, 1, 1 or 0, 2, 0, 1
- The first digit (a) is always zero, unless there is a style attribute applied to that element within the markup itself
- The second digit (b) is the sum of the number of IDs in that selector
- The third digit (c) is the sum of other attribute selectors and pseudo-classes in that selector. Classes (
.example
) and attribute selectors (eg.li[id=red])
are included here. - The fourth digit (d) counts the elements (like
table
,p
,div
, etc.) and pseudo-elements (like:first-line
) - The universal selector (*) has a specificity of zero
- If two selectors have the same specificity, the one that comes last on the stylesheet will be applied
#sidebar h2
— 0, 1, 0, 1h2.title
— 0, 0, 1, 1h2 + p
— 0, 0, 0, 2#sidebar p:first-line
— 0, 1, 0, 2
#sidebar p#first { color: red; }
— 0, 2, 0, 1#sidebar p:first-line { color: blue; }
— 0, 1, 0, 2
Firebug lets you easily see which selector is being applied to an element.
Useful links:
- CSS Specificity: Things You Should Know
- Link Specificity¯MeyerWeb
- CSS: Specificity Wars
- Assigning property values, Cascading, and Inheritance—W3C
1. Attribute selectors
Attribute selectors let you target an element based on its attributes. You can specify the element’s attribute only, so all the elements that have that attribute — whatever the value — within the HTML will be targeted, or be more specific and target elements that have particular values on their attributes — and this is where attribute selectors show their power.There are 6 different types of attribute selectors:
[att=value]
The attribute has to have the exact value specified.[att~=value]
The attribute’s value needs to be a whitespace separated list of words (for example, class=”title featured home”), and one of the words is exactly the specified value.[att|=value]
The attribute’s value is exactly “value” or starts with the word “value” and is immediately followed by “-”, so it would be “value-”.[att^=value]
The attribute’s value starts with the specified value.[att$=value]
The attribute’s value ends with the specified value.[att*=value]
The attribute’s value contains the specified value.
div
whose class
attribute starts with “post-”:1 | div[class*= "post" ] { |
2 | background-color : #333 ; |
3 | } |
div
elements whose class attribute contains the words “posts”, in any position.Another useful usage of attribute selectors is to target different types of
input
elements. For example, if you want your text inputs to have a different width from the others, you can use a simple attribute selector:1 | input[type= "text" ] { |
2 | width : 200px ; |
3 | } |
input
elements whose type
attribute is exactly “text”.Now let’s say you want to add a different icon next to each different type of file your website is linking to, so your website’s visitors know when they’ll get an image, a PDF file, a Word document, etc. This can be done by using an attribute selector:
01 | a[href$= ".jpg" ] { |
02 | background : url (jpeg.gif) no-repeat left 50% ; |
03 | padding : 2px 0 2px 20px ; |
04 | } |
05 |
06 | a[href$= ".pdf" ] { |
07 | background : url (pdf.gif) no-repeat left 50% ; |
08 | padding : 2px 0 2px 20px ; |
09 | } |
10 |
11 | a[href$= ".doc" ] { |
12 | background : url (word.gif) no-repeat left 50% ; |
13 | padding : 2px 0 2px 20px ; |
14 | } |
a
) whose href
attribute ends ($
) with .jpg, .pdf or .doc.Notes on browser support
Apart from Internet Explorer 6, all major browsers support attribute selectors. This means that when you are using attribute selectors on your stylesheets, you should make sure that IE6 users will still be provided with a usable site. Take our third example: adding an icon to your links adds another level of usability to your site, but the site will still be usable if the links don’t show any icons.
2. Child selector
The child selector is represented by the sign “>”. It allows you to target elements that are direct children of a particular element.For example, if you want to match all the
h2
elements that are a direct child of your sidebar div
, but not the h2
elements that may be also within the div
, but that are grandchildren (or later descendants) of your element, you can use this selector:1 | div#sidebar > h 2 { |
2 | font-size : 20px ; |
3 | } |
blockquote
elements that are within divs that are direct grandchildren of the body
element (you may want to match blockquotes inside the main content div
, but not if they are outside it):1 | body > div > div blockquote { |
2 | margin-left : 30px ; |
3 | } |
Like the attribute selectors, the child selector is not supported by Internet Explorer 6. If the effect you are trying to achieve by using it is crucial for the website’s usability or overall aesthetics, you can consider using a class selector with it, or on a IE-only stylesheet, but that would detract from the purpose of using child selectors.
3. Sibling combinators
There are two types of sibling combinators: adjancent sibling combinators and general sibling combinators.Adjacent sibling combinator
This selector uses the plus sign, “+”, to combine two sequences of simple selectors. The elements in the selector have the same parent, and the second one must come immediately after the first.The adjacent sibling combinator can be very useful, for example, when dealing with text. Lets say you want to add a top margin to all the
h2
tags that follow a paragraph (you don’t need to add a top margin if the heading comes after an h1
tag or if it’s the first element on that page):1 | p + h 2 { |
2 | margin-top : 10px ; |
3 | } |
div
:1 | div.post p + h 2 { |
2 | margin-top : 10px ; |
3 | } |
1 | .post h 1 + p:first-line { |
2 | font-variant : small-caps ; |
3 | } |
h1
tag, you can refer to the h1
on your selector.General sibling combinator
The general sibling combinator works pretty much the same as the adjacent sibling combinator, but with the difference that the second selector doesn’t have to immediately follow the first one.So if you need to target all the
p
tags that are within a particular div
and that follow the h1
tag (you may want those p
tags to be larger than the ones that come before the title of your post), you can use this selector:1 | .post h 1 ~ p { |
2 | font-size : 13px ; |
3 | } |
Internet Explorer 6 doesn’t understand sibling combinators, but, as for the other cases, if your audience includes a small percentage of IE6 users, and if the website’s layout isn’t broken or severely affected by its lack of support, this is a much easier way of achieving lots of cool effects without the need of cluttering your HTML with useless classes and ids.
4. Pseudo-classes
Dynamic pseudo-classes
These are called dynamic pseudo-classes because they actually do not exist within the HTML: they are only present when the user is or has interacted with the website.There are two types of dynamic pseudo-classes: link and user action ones. The link are
:link
and :visited
, while the user action ones are :hover
, :active
and :focus
.From all the CSS selectors mentioned in this post, these will probably be the ones that are most commonly used.
The
:link
pseudo-class applies to links that haven’t been visited by the user, while the :visited
pseudo-class applies to links that have been visited, so they are mutually exclusive.The
:hover
pseudo-class applies when the user moves the cursor over the element, without having to activate or click on it. The :active
pseudo-class applies when the user actually clicks on the element. And finally the :focus
pseudo-class applies when that element is on focus — the most common application is on form elements.You can use more than one user action dynamic pseudo-class in your stylesheets, so you can have, for example, a different background color for an input field depending on whether the user’s cursor is only hovering over it or hovering over it while in focus:
1 | input:focus { |
2 | background : #D2D2D2 ; |
3 | border : 1px solid #5E5E5E ; |
4 | } |
5 |
6 | input:focus:hover { |
7 | background : #C7C7C7 ; |
8 | } |
The dynamic pseudo-classes are supported by all modern browsers, even IE6. But bear in mind that IE6 only allows the
:hover
pseudo-class to be applied to link elements (a
) and only IE8 accepts the :active
state on elements other than links.:first-child
The:first-child
pseudo-class allows you to target an element that is the first child of another element. For example, if you want to add a top margin to the first li
element of your unordered lists, you can have this:1 | ul > li:first-child { |
2 | margin-top : 10px ; |
3 | } |
h2
tags in your sidebar to have a top margin, to separate them from whatever comes before them, but the first one doesn’t need a margin. You can use the following code:1 | #sidebar > h 2 { |
2 | margin-top : 10px ; |
3 | } |
4 |
5 | #sidebar > h 2: first-child { |
6 | margin-top : 0 ; |
7 | } |
IE6 doesn’t support the
:first-child
pseudo-class. Depending on the design that the pseudo-class is being applied to, it may not be a major cause for concern. For example, if you are using the :first-child
selector to remove top or bottom margins from headings or paragraphs, your layout will probably not break in IE6, it will only look sightly different. But if you are using the :first-child
selector to remove left and right margins from, for example, a floated sequence of divs, that may cause more disruption to your designs.The language pseudo-class
The language pseudo-class,:lang()
, allows you to match an element based on its language.For example, lets say you want a specific link on your site to have a different background color, depending on that page’s language:
1 | :lang(en) > a#flag { |
2 | background-image : url (english.gif); |
3 | } |
4 |
5 | :lang(fr) > a#flag { |
6 | background-image : url (french.gif); |
7 | } |
Notes on browser support
Not surprisingly, the only version of Internet Explorer that supports this selector is 8. All other major browsers support the language pseudo-selector.
5. CSS 3 Pseudo-classes
:target
When you’re using links with fragment identifiers (for example,http://www.smashingmagazine.com/2009/08/02/bauhaus-ninety-years-of-inspiration/#comments
, where “#comments” is the fragment identifier), you can style the target by using the :target
pseudo-class.For example, lets imagine you have a long page with lots of text and
h2
headings, and there is an index of those headings at the top of the page. It will be much easier for the user if, when clicking on a particular link within the index, that heading would become highlighted in some way, when the page scrolls down. Easy:1 | h 2: target { |
2 | background : #F2EBD6 ; |
3 | } |
This time, Internet Explorer is really annoying and has no support at all for the
:target
pseudo-class. Another glitch is that Opera doesn’t support this selector when using the back and forward buttons. Other than that, it has support from the other major browsers.The UI element states pseudo-classes
Some HTML elements have an enable or disabled state (for example, input fields) and checked or unchecked states (radio buttons and checkboxes). These states can be targeted by the:enabled
, :disabled
or :checked
pseudo-classes, respectively.So you can say that any
input
that is disabled should have a light grey background and dotted border:1 | input:disabled { |
2 | border : 1px dotted #999 ; |
3 | background : #F2F2F2 ; |
4 | } |
1 | input[type=”checkbox”]:checked { |
2 | margin-left : 15px ; |
3 | } |
All major browsers, except our usual suspect, Internet Explorer, support the UI element states pseudo-classes. If you consider that you are only adding an extra level of detail and improved usability to your visitors, this can still be an option.
6. CSS 3 structural pseudo-classes
:nth-child
The:nth-child()
pseudo-class allows you to target one or more specific children of a parent element.You can target a single child, by defining its value as an integer:
1 | ul li:nth-child( 3 ) { |
2 | color : red ; |
3 | } |
li
item within the ul
element red. Bear in mind that if a different element is inside the ul
(not a li
), it will also be counted as its child.You can target a parent’s children using expressions. For example, the following expression will match every third
li
element starting from the fourth:1 | ul li:nth-child( 3 n+ 4 ) { |
2 | color : yellow; |
3 | } |
li
element will be the fourth. If you just want to start counting from the first li
element, you can use a simpler expression:1 | ul li:nth-child( 3 n) { |
2 | color : yellow; |
3 | } |
li
element will be the third, and every other third after it. Now imagine you want to target only the first four li
elements within the list:1 | ul li:nth-child(-n+ 4 ) { |
2 | color : green ; |
3 | } |
:nth-child
can also be defined as “even” or “odd”, which are the same as using “2n” (every second child) or “2n+1” (every second child starting from the first), respectively.:nth-last-child
The:nth-last-child
pseudo-class works basically as the :nth-child
pseudo-class, but it starts counting the elements from the last one.Using one of the examples above:
1 | ul li:nth-child(-n+ 4 ) { |
2 | color : green ; |
3 | } |
li
elements in the list, this selector will match the last four elements.You can also use the values “even” or “odd”, with the difference that in this case they will count the children starting from the last one:
1 | ul li:nth-last-child(odd) { |
2 | color : grey; |
3 | } |
:nth-of-type
The:nth-of-type
pseudo-class works just like the :nth-child
, with the difference that it only counts children that match the element in the selector.This can be very useful if we want to target elements that may contain different elements within them. For example, let’s imagine we want to turn every second paragraph in a block of text blue, but we want to ignore other elements such as images or quotations:
1 | p:nth-of-type(even) { |
2 | color : blue ; |
3 | } |
:nth-child
pseudo-class.:nth-last-of-type
You guessed it! The:nth-last-of-type
pseudo-class can be used exactly like the aforementioned :nth-last-child
, but this time, it will only target the elements that match our selector:1 | ul li:nth-last-of-type(-n+ 4 ) { |
2 | color : green ; |
3 | } |
div
to be floated left, except for the first and last one (let’s image these would full width, so they shouldn’t be floated):1 | .post img:nth-of-type(n+ 2 ):nth-last-of-type(n+ 2 ) { |
2 | float : left ; |
3 | } |
:last-child
The:last-child
pseudo-class works just as the :first-child
pseudo-class, but instead targets the last child of a parent element.Let’s image you don’t want the last paragraph within your post
div
to have a bottom margin:1 | .post > p:last-child { |
2 | margin-bottom : 0 ; |
3 | } |
:first-of-type and :last-of-type
The:first-of-type
pseudo-class is used to target an element that is the first of its type within its parent.For example, you can target the first paragraph that is a direct child of a particular
div
, and capitalize its first line:1 | .post > p:first-of-type:first-line { |
2 | font-variant : small-caps ; |
3 | } |
div
, and that are the first to match our p
element.The
:last-of-type
pseudo-class works exactly the same, but targets the last child of its type instead.:only-child
The:only-child
pseudo-class represents an element that is the only child of its parent.Let’s say you have several boxes (“news”) with paragraphs of text inside them. When you have more than one paragraph, you want the text to be smaller than when you have only one:
1 | div.news > p { |
2 | font-size : 1.2em ; |
3 | } |
4 |
5 | div.news > p:only-child { |
6 | font-size : 1.5em ; |
7 | } |
p
elements that are direct children of a “news” div
. On the second one, we are overriding the previous font-size by saying, if the p
element is the only child of the “news” div
, its font size should be bigger.:only-of-type
The:only-of-type
pseudo-class represents an element that is the only child of its parent with the same element.How can this be useful? Image you have a sequence of posts, each one represented by a
div
with the class of “post”. Some of them have more than one image, but others have only one image. You want the image within the later ones to be aligned to the center, while the images on posts with more than one image to be floated. That would be quite easy to accomplish with this selector:1 | .post > img { |
2 | float : left ; |
3 | } |
4 |
5 | .post > img:only-of-type { |
6 | float : none ; |
7 | margin : auto ; |
8 | } |
:empty
The:empty
pseudo-class represents an element that has no content within it.It can be useful in a number of ways. For example, if you have multiple boxes in your “sidebar”
div
, but don’t want the empty ones to appear on the page:1 | #sidebar .box:empty { |
2 | display : none ; |
3 | } |
div
, it will not be treated as empty by the CSS, and therefore will not match the selector.Notes on browser support
Internet Explorer (up until version 8) has no support for structural pseudo-classes. Firefox, Safari and Opera support these pseudo-classes on their latest releases. This means that if what it’s being accomplished with these selectors is fundamental for the website’s usability and accessibility, or if the larger part of the website’s audience is using IE and you don’t want to deprive them of some design details, it’s be wise to keep using regular classes and simpler selectors to cater for those browsers. If not, you can just go crazy!
7. The negation pseudo-class
The negation pseudo-class,:not()
, lets you target elements that do not match the selector that is represented by its argument.For example, this can be useful if you need to style all the
input
elements within a form, but you don’t want your input elements with the type submit to be styled — you want them to be styled in a different way —, to look more like buttons:1 | input:not([type= "submit" ]) { |
2 | width : 200px ; |
3 | padding : 3px ; |
4 | border : 1px solid #000000 ; |
5 | } |
div
to have a larger font-size, except for the one that indicates the time and date:1 | .post p:not(.date) { |
2 | font-size : 13px ; |
3 | } |
Notes on browser support
Internet Explorer is our usual party pooper here: no support at all, not even on IE8. This probably means that this selector will still have to wait a while before some developers lose the fear of adding them to their stylesheets.
8. Pseudo-elements
Pseudo-elements allow you to access elements that don’t actually exist in the HTML, like the first line of a text block or its first letter.Pseudo-elements exist in CSS 2.1, but the CSS 3 specifications state that they should be used with the double colon “::”, to distinguish them from pseudo-classes. In CSS 2.1, they are used with only one colon, “:”. Browsers should be able accept both formats, except in the case of pseudo-elements that may be introduced only in CSS 3.
::first-line
The::first-line
pseudo-element will match the first line of a block, inline-block, table-caption or table-cell level element.This is particularly useful to add subtle typographical details to your text blocks, like, for example, transforming the first line of an article into small caps:
1 | h 1 + p::first-line { |
2 | font-variant : small-caps ; |
3 | } |
h1
tag (“+”) should have its first line in small caps.You could also refer to the first line of a particular
div
, without having to refer to the actual paragraph tag:1 | div.post p::first-line { font-variant : small-caps ; } |
div
:1 | div.post > p:first-child::first-line { |
2 | font-variant : small-caps ; |
3 | } |
div
, so if the paragraph were to be inside a second div
, it wouldn’t match this selector.::first-letter
The::first-letter
pseudo-element will match the first letter of a block, unless it’s preceded by some other content, like an image, on the same line.Like the
::first-line
pseudo-element, ::first-letter
is commonly used to add typographical details to text elements, like drop caps or initials.Here is how you could use the
::first-letter
pseudo-element to create a drop cap:1 | p { |
2 | font-size : 12px ; |
3 | } |
4 |
5 | p::first-letter { |
6 | font-size : 24px ; |
7 | float : left ; |
8 | } |
::first-line
and ::first-letter
in the same element, the ::first-letter
properties will override the same properties inherited from ::first-line
.This element can sometimes produce unexpected results, if you’re not aware of the W3C specs: it’s actually the CSS selector with the longest spec! So it’s a good idea to read them carefully if you’re planning on using it (as it is for all the other selectors).
::before and ::after
The::before
and ::after
pseudo-elements are used to insert content before or after an element’s content, purely via CSS.These elements will inherit many of the properties of the elements that they are being attached to.
Image you want to the words “Graphic number x:” before the descriptions of graphs and charts on your page. You could achieve this without having to write the words “Graphic number”, or the number itself yourself:
1 | .post { |
2 | counter-reset : image; |
3 | } |
4 |
5 | p.description::before { |
6 | content : "Figure number " counter (image) ": " ; |
7 | counter-increment : image; |
8 | } |
First, we tell the HTML to create the “image” counter. We could have added this property to the body of the page, for example. Also, we can call this counter whatever name we want to, as long as we always reference it by the same name: try it for yourself!
Then we say that we want to add, before every paragraph with the class “description”, this piece of content: “Figure number ” — notice that only what we wrote between quotes will be created on the page, so we need to add the spaces as well!
After that, we have
counter(image)
: this will pick up the property we’ve already defined in the .post
selector. It will by default start with the number one (1).The next property is there so that the counter knows that for each
p.description
, it needs to increment the image counter by 1 (counter-increment: image
).It’s not as complicated as it looks, and it can be quite useful.
The
::before
and ::after
pseudo-elements are often only used with the content property, to add small sentences or typographical elements, but here it’s shown how we can use it in a more powerful way in conjunction with the counter-reset
and counter-increment
properties.Fun fact: the
::first-line
and ::first-letter
pseudo-elements will match the content added by the ::before
pseudo-element, if present.Notes on browser support
These pseudo-elements are supported by IE8 (not IE7 or 6), if the single colon format is used (for example,
:first-letter
, not ::first-letter
). All the other major browsers support these selectors.Conclusion
Enough with the boring talk, now it’s time for you to grab the information on this post and go try it for yourself: start by creating an experimental page and test all of these selectors, come back here when in doubt and make sure to always refer to the W3C specs, but don’t just sit there thinking that because these selectors aren’t yet widely supported you might as well ignore them.If you’re a bit more adventurous, or if you’re not afraid of letting go of the past filled with useless and non-semantic classes and ids, why not sneak one or two of these powerful CSS selectors into your next project? We promise you’ll never look back.
References
- CSS 2 Selectors — W3C
- CSS 3 Selectors Level 3 — W3C
- Comparison of layout engines (Cascading Style Sheets) — Wikipedia
- Generated content, automatic numbering, and lists — W3C
Further Resources
- Keeping Your Elements’ Kids in Line with Offspring — A List Apart
- Selectutorial – CSS selectors
- A Look at Some of the New Selectors Introduced in CSS3
- CSS 2.1 selectors, Part 1 and Part 2
- CSS 3 selectors explained
- CSS selectors and pseudo selectors browser compatibility
- 10 Useful CSS Properties Not Supported By Internet Explorer
- Styling a Poem with Advanced CSS Selectors
No comments:
Post a Comment