Lecture 23: Pseudo-Elements, Generated Content, and Additional Pseudo-Classes
Overview:
- :first-letter and :first-line Pseudo-Elements
- :before and :after Pseudo-Elements for Generated Content
- ::selection Pseudo-Element
- :root Pseudo-Element
- :first-child and :last-child Pseudo-Classes
- :not and :empty Pseudo-Classes
- :lang Pseudo-Class
- :target Pseudo-Class
- :only-child Pseudo-Class
- Combining Dynamic Pseudo-Classes
:first-letter and :first-line Pseudo-Elements
- These pseudo-elements are used to modify selectors. In general, pseudo-elements make it easier to access specific parts of a document that would otherwise require additional coding to isolate.
- Specificity for pseudo-elements is a bit confusing, because the CSS 2.1 specification states in one place that these should be ignored when determining specificity and elsewhere it states that the specificity is equal to that of an element (1). This is what leads to inconsistent browser implementations/behavior.
- :first-letter styles the first letter in that selector's content.
- :first-line styles the first line of content in that selector; layout and browser width will determine where that first line ends.
- Both come from the print world (think of books that have special typography for the first letter in a chapter, etc.)
- These can only be applied to block-level elements (or elements displayed as block, inline-block, table-caption or table-cell).
- If you see these specified as ::first-letter and ::first-line (with two colons rather than one colon) that is a change in CSS3. CSS1 originally defined them with one colon. Mac IE 5.x does not support the double-colon syntax. However, modern browsers support both versions.
- Windows IE 5.5 & 6 have a variety of bugs in their pseudo-element implementation. Some are syntax-related, such as needing a space between the end of the selector and the { that begins the declaration block. Another syntax issue arises if you have a number of selectors separated by commas; you must put a space after the pseudo-element and before the comma (such as
div:first-line , p {}). IE 7 fixed the first issue (related to space before the declaration block) and continues to have the second issue.
| Pseudo-Element | Usage and Effect | Properties Accepted | Supported By |
|---|---|---|---|
| :first-letter | Styles the first letter in the indicated selector. | background-related properties | border-related properties | color | clear (covered in INP 170: Web Coding II) | float (covered in INP 170: Web Coding II) | font-related properties | line-height | margin properties | padding properties | text-decoration | text-transform | vertical-align (if not floated) | Windows IE 5.01 and earlier browsers lack support (for the most part); Windows IE 5.5 and later browsers have support. Mac IE 5.x is supportive. |
| :first-line | Styles the first line of content in the indicated selector. | background-related properties | color | clear (covered in INP 170: Web Coding II) | font-related properties | letter-spacing | line-height | text-decoration | text-transform | vertical-align word-spacing | Windows IE 5.01 and earlier browsers lack support (for the most part); Windows IE 5.5 and later browsers have support. Mac IE 5.x is supportive. |
Sample code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Embedded CSS: First-Letter and First-Line</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"><!--
body, h1, h2 {font: 12px verdana,geneva,lucida,arial,sans-serif;}
h1 {font-size: 18px;}
h2 {font-size: 14px;}
h1:first-letter {font-size: 24px;}
.color:first-letter {color: white; background: #000; font-size: 18px;}
p:first-line {font-style: italic;}
p:first-letter {font-weight: bold;}
--></style>
</head>
<body>
<h1>Sample Level 1 heading with :first-letter styling on the
element</h1>
<p>A sample paragraph with enough content that it should eventually
wrap to two lines when the window is sized appropriately. A sample
paragraph with enough content that it should eventually wrap to two
lines when the window is sized appropriately.</p>
<h2 class="color">Sample Level 2 heading, using a class and
:first-letter</h2>
<p>Another example of a paragraph that will use the first-line styling.
Additional text in order to force wrapping. Additional text in order to
force wrapping. Additional text in order to force wrapping. Additional text
in order to force wrapping.</p>
</body>
</html>
:before and :after Pseudo-Elements for Generated Content
- Among the more controversial aspects of CSS2 is the content property, which must be used in conjunction with the :before and/or :after pseudo-elements.
- These allow content to be generated when the page loads and inserted into the document structure, which is moving CSS from being completely about presentation into a new area that is traditionally occupied by JavaScript (the behavior layer).
- Generated content is supported in Gecko-based browsers, Safari, and Opera. There is no support in Internet Explorer.
| Pseudo-Element or Property | Usage and Effect | Properties / Values Accepted | Supported By |
|---|---|---|---|
| :after | Inserts the indicated content after the selector's content. | CSS properties, most importantly the 'content' property | Gecko-based browsers, Safari, and Opera.
Internet Explorer lacks support. |
| :before | Inserts the indicated content before the selector's content. | CSS properties, most importantly the 'content' property | Gecko-based browsers, Safari, and Opera.
Internet Explorer lacks support. |
| content | Specifies content to insert either :before or :after | Text string surrounded by quotes | images brought in via url() | attribute values via attr() | keyword defined elements (used with the quotes property and accepts values of 'open-quote', 'close-quote', 'no-open-quote', and 'no-close-quote') | counters | Gecko-based browsers, Safari, and Opera.
Internet Explorer lacks support. Mozilla does not support counters. |
Sample code using images:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Embedded CSS: Generated Content 1</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"><!--
body {font: 12px verdana,geneva,lucida,arial,sans-serif;}
p:before {content: url(content-arrow.gif);}
--></style>
</head>
<body>
<p>The first paragraph.</p>
<p>The second paragraph.</p>
<p>The third paragraph.</p>
</body>
</html>
Sample code using text string output and counters:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Embedded CSS: Generated Content 2</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"><!--
body, h1 {font: 12px verdana,geneva,lucida,arial,sans-serif;}
/* need to put the counter-increment in the tag, not the :before
for it to work in Firefox; by default it increments by 1
so it is not essential to specify that */
h1 {font-size: 16px; counter-increment: paper 1;}
h1:before {content: counter(paper) ". ";}
.paper:after {
font-style: oblique;
content: " Copyright: Web Design Associates.";
}
--></style>
</head>
<body>
<h1>White Paper Title</h1>
<div class="paper">A description of the white paper.</div>
<h1>White Paper Title</h1>
<div class="paper">A description of the white paper.</div>
<h1>White Paper Title</h1>
<div class="paper">A description of the white paper.</div>
</body>
</html>
Sample code using attribute output:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Embedded CSS: Generated Content 3</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"><!--
body, h1 {font: 12px verdana,geneva,lucida,arial,sans-serif;}
h1 {font-size: 16px;}
ul {margin-bottom: 50px;}
#version1 a:after {content: " - " attr(href);}
#version1 li:after {content: " (" attr(title) ")";}
#version2 a:after {
content: " (" attr(href) " - " attr(title) ")";
}
--></style>
</head>
<body>
<h1>Links of Interest, Version 1:</h1>
<ul id="version1">
<li title="Web Search Engine">
<a href="http://www.google.com">Google</a>
</li>
<li title="Job Listings">
<a href="http://www.monster.com">Monster</a>
</li>
<li title="Technology News">
<a href="http://www.news.com">CNET</a>
</li>
</ul>
<h1>Links of Interest, Version 2:</h1>
<ul id="version2">
<li><a href="http://www.google.com"
title="Web Search Engine">Google</a>
</li>
<li><a href="http://www.monster.com"
title="Job Listings">Monster</a>
</li>
<li>
<a href="http://www.news.com"
title="Technology News">CNET</a>
</li>
</ul>
</body>
</html>
Sample code using quotes:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Embedded CSS: Generated Content 4</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"><!--
body {font: 12px verdana,geneva,lucida,arial,sans-serif;}
/* with quotes the first set of values are outer open/closed, then
the next set are the nested open/closed quotations to use */
q:lang(en) {quotes: '"' '"' "'" "'";}
q:lang(fr) {quotes: "<<" ">>" "<" ">";}
q:before {content: open-quote;}
q:after {content: close-quote;}
--></style>
</head>
<body>
<p><em>English version of quotes:</em><br />
<q>A quotation <q>and a nested quotation</q> to show the quotes
property.</q></p>
<p><em>French version of quotes (not a perfect match):</em><br />
<q lang="fr">A quotation <q lang="fr">and a nested quotation</q> to show
the quotes property.</q></p>
</body>
</html>
::selection Pseudo-Element
- This pseudo-element allows you to control background colors and text colors for text that a user highlights by clicking and dragging across it. The specification also indicates that cursor and outline should be supported, but test to ensure this is happening.
- Only Safari and Konqueror support ::selection (which is not surprising since they share essentially the same code base)
- Gecko-based browsers have the non-standard ::-moz-selection, because it is part of CSS3 and not finalized.
- No other browsers are supportive.
Sample code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Embedded CSS: Selection</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"><!--
body {font: 12px verdana,geneva,lucida,arial,sans-serif;}
::selection {background: green; color: #fff;}
::-moz-selection {background: green; color: #fff;}
div::selection {background: yellow; color: #000;}
div::-moz-selection {background: yellow; color: #000;}
--></style>
</head>
<body>
<p>This text should be white text on a green background when it is
selected</p>
<div>This text, however, should be black text on a yellow background
because the div selections are styled differently.</div>
</body>
</html>
:root Pseudo-Element
- The :root pseudo-element refers to the root element in the page.
- In an (X)HTML document this would be <html>
- In an XML document, in which you have defined all of your own data tags, the root element would be something else entirely. This would allow you to select that root element for styling without having to know the tag name.
- At this point Mac IE 5.x, Gecko-based browsers, Safari, and Konqueror support :root
Sample code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Embedded CSS: Root</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"><!--
:root {background: green; padding: 35px;}
body {background: #fff; color: #000;}
--></style>
</head>
<body>
<p>In supportive browsers, the rest of the page should be green and
there should be noticeable padding on all sides.</p>
</body>
</html>
:first-child and :last-child Pseudo-Classes
- One way of viewing a web page is as a series of parent/child/descendant relationships for elements, with elements sharing the same parent being siblings.
- How tags are nested sets up these relationships.
- The :first-child pseudo-class styles the indicated selector if it is the first child within its parent.
- The :last-child pseudo-class styles the indicated selector if it is the last child within its parent.
- If the indicated selector is the only child in its parent, both :first-child and :last-child would apply to it.
- Windows IE 5.x & 6 lack support. IE 7, Opera, and Mac IE 5.x support only :first-child. The Gecko-based browsers, Safari, and Konqueror support both.
- Note that the same IE 7 comment bug impacting direct adjacent selectors also impacts the :first-child pseudo-class. If there is an (X)HTML comment between your target element and its parent, it will not be the first child (the comment will be).
Sample code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Embedded CSS: First-Child and Last-Child</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"><!--
body {font: 12px verdana,geneva,lucida,arial,sans-serif;}
strong:first-child {font-style: italic;}
span:last-child {font-variant: small-caps;}
.example:first-child {font-weight: bold;}
.example:last-child {color: red; background: #fff;}
--></style>
</head>
<body>
<p>In this paragraph the first child is <strong>strong text that will
also italicize</strong>, while the next <strong>strong text will not be
italicized</strong> and then the final <span>tagged content will be in
small-caps text</span>.</p>
<p>We have <span class="example">some bold text</span>, other text
<span class="example">with no styling</span>, and then some <span
class="example">red text that is small-caps</span>.</p>
<p>And then a paragraph with <span class="example">one child</span>.</p>
</body>
</html>
:not and :empty Pseudo-Classes
- Typically we are using a selector in order to isolate what needs to be styled. With :not, however, we are indicating what elements are explicitly not styled.
- It can be tricky to get :not working properly, so test carefully.
- The :empty pseudo-class targets elements with no content (for current Firefox versions and Mozilla 1.8 the definition of "content" includes spaces and line feeds).
- This includes elements that have content added to them via JavaScript when the page loads, so those areas of the page can be specially styled via :empty
- Gecko-based browsers, Safari, and Konqueror support these pseudo-classes.
Sample code for the :not pseudo-class:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Embedded CSS: The :Not Pseudo-Class</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"><!--
body :not(.normal) {font-style: oblique;}
--></style>
</head>
<body>
<p class="normal">Text inside an element with class="normal".</p>
<p>All content not inside an element with class="normal" will render
as oblique text.</p>
</body>
</html>
Sample code for the :empty pseudo-class:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Embedded CSS: The Empty Pseudo-Class</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"><!--
body {font: 12px verdana,geneva,lucida,arial,sans-serif;}
p:empty {border: 6px double #000;}
--></style>
</head>
<body>
<p></p>
<p>This paragraph is not empty.</p>
<p></p>
</body>
</html>
:lang Pseudo-Class
- This pseudo-class is used to style content based on the language specified for that element.
- Gecko-based browsers, Opera, Mac IE 5.x, and the latest versions of Safari and Konqueror should be supportive.
Sample code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Embedded CSS: Lang</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"><!--
body {font: 12px verdana,geneva,lucida,arial,sans-serif;}
:lang(de) {background: #000; color: #fff; font-weight: bold;}
--></style>
</head>
<body>
<p>A German greeting: <span lang="de">Guten Tag!</span></p>
</body>
</html>
:target Pseudo-Class
- The :target pseudo-class allows you to style the element that is the targeted area of the page.
- The styles are only applied when that anchored area has been triggered, which then draws attention to that area.
- This is supported in Gecko-based browsers, Safari, and Konqueror, although in my testing the Gecko-based browsers were performing better than Safari.
Sample code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Embedded CSS: Target</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"><!--
body, h1 {font: 12px verdana,geneva,lucida,arial,sans-serif;}
h1 {font-size: 20px;}
a:target {color: #fff; background: #000; font-style: oblique;
padding: 5px;}
.height200 {height: 200px;}
--></style>
</head>
<body>
<p>
On This Page:<br />
<a href="#section1">Section 1</a><br />
<a href="#section2">Section 2</a><br />
<a href="#section3">Section 3</a>
</p>
<div class="height200"></div>
<h1><a name="section1">Section 1</a></h1>
<div class="height200"></div>
<h1><a name="section2">Section 2</a></h1>
<div class="height200"></div>
<h1><a name="section3">Section 3</a></h1>
</body>
</html>
:only-child Pseudo-Class
- The :only-child pseudo-class applies to elements that have a parent but no siblings.
- This is supported in Gecko-based browsers (as of Mozilla 1.8, which includes current Firefox versions) and the latest versions of Safari and Konqueror.
Sample code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Embedded CSS: Only-Child</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"><!--
body {font: 12px verdana,geneva,lucida,arial,sans-serif;}
em:only-child {font-weight: bold;}
--></style>
</head>
<body>
<p>This <em>emphasized text</em> has its default appearance as well as a
bold font-weight, because it is the only child of its parent.</p>
<p>This <em>emphasized text</em> only shows its default appearance and
does not pick up the bold font-weight because there is also some
<span>spanned content</span> that has the same parent.</p>
</body>
</html>
Combining Dynamic Pseudo-Classes
- The dynamic pseudo-classes (:hover, :active, :focus) can be combined together to represent situations where both are true (for example, when an element has focus and is also hovered over).
- The syntax for this joins together the two pseudo-classes into a sequence with no spaces between them (e.g., :hover:focus). Windows IE only will interpret the first dynamic pseudo-class and will ignore the second, so specify :hover first (there is no support for :focus in Windows IE 5.x - 7).
- Browsers have their own default :focus setting for links (usually a dotted box around the linked text), although Opera goes further in its default styling.
- This is also the same syntax used when the selector is two classes that must be specified togther (e.g., .class1.class2). When you actually call the class in your (X)HTML you do not need to match the exact sequencing given in your CSS.
Sample code for multiple dynamic pseudo-classes (tabindex was added so that Opera would tab to the link):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Embedded CSS: Multiple Dynamic Pseudo-Classes</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"><!--
body {font: 12px verdana,geneva,lucida,arial,sans-serif;}
a:hover {text-decoration: none;}
a:focus {border: 2px solid #000;}
a:hover:focus {background: #000; color: #fff;}
--></style>
</head>
<body>
<p>A <a href="http://www.google.com" tabindex="1">link to Google</a>.</p>
</body>
</html>
Sample code for multiple classes:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Embedded CSS: Multiple Classes</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"><!--
body {font: 12px verdana,geneva,lucida,arial,sans-serif;}
.ctr {text-align: center;}
.padding20 {padding: 20px;}
.ctr.padding20 {background: #000; color: #fff;}
--></style>
</head>
<body>
<p class="ctr padding20">Centered white text on a black background.</p>
<p class="ctr">Text that is just centered.</p>
<p class="padding20 ctr">Centered white text on a black background.</p>
</body>
</html>