Status: ED Work Status: Exploring Shortname: css-content Level: 3 Group: csswg TR: https://www.w3.org/TR/css3-content/ ED: https://drafts.csswg.org/css-content/ Previous Version: https://www.w3.org/TR/2016/WD-css-content-3-20160602/ Editor: Elika J. Etemad / fantasai, W3C Invited Expert, http://fantasai.inkedblade.net/contact Editor: Dave Cramer, Hachette Livre, dauwhe@gmail.com Former Editor: Håkon Wium Lie, Opera Software, howcome@opera.com Former Editor: Ian Hickson, Google, ian@hixie.ch Ignored Terms:, leader(), string(), target-counter(), target-counters(), target-text() Abstract: This CSS3 Module describes how to insert content in a document. Link Defaults: css21 (type) , css-display-3 (value) inline Status Text: This is a very rough draft, and is not ready for implementation.
h1::before { content: counter(section) ": "; }
chapter { counter-increment: chapter; }
chapter > title::before { content: "Chapter " counter(chapter) "\A"; }
/* Replace <logo> elements with the site's logo, using a format
* supported by the UA */
logo { content: url(logo.mov), url(logo.mng), url(logo.png), none; }
/* Replace <figure> elements with the referenced document, or,
* failing that, with either the contents of the alt attribute or the
* contents of the element itself if there is no alt attribute */
figure[alt] { content: attr(href, url), attr(alt); }
figure:not([alt]) { content: attr(href, url), contents; }
Name: content
Value: [ [ <> | <> ] ',' ]* [ normal | none | <> ] [/ <> ]?
Initial: normal
Applies To: ''::before'', ''::after'', ''::marker'', and page margin boxes. Image and url values can apply to all elements.
Inherited: no
Percentages: n/a
Computed Value: As specified below.
Media: all
The 'content' property dictates what is rendered inside the element or pseudo-element. It takes a comma separated list of URIs, followed by a space separated list of tokens, followed by an optional slash and string indicating alternative text. If there are multiple URIs provided, then each is tried in turn until a value which is both available and supported is found. The last value is used as a fallback if the others fail.
> | ''document-url'' | <> | ''leader()'' ]+ See sections below for details on each of these.
If the computed value of the part of the 'content' property that ends up being used is a single URI, then the element or pseudo-element is a replaced element. The box model defines different rules for the layout of replaced elements than normal elements. Replaced elements do not have '::before' and '::after' pseudo-elements; the 'content' property in the case of replaced content replaces the entire contents of the element's box.
.new::before {
content: url(./img/star.png) / "New!";
/* or a localized attribute from the DOM: attr("data-alt") */
}
.expandable::before {
content: "\25BA" / "";
/* a.k.a. ► */
/* aria-expanded="false" already in DOM,
so this pseudo-element is decorative */
}
h1 { content: url(header/mng), url(header/png), none; }
header/mng wasn't in a supported format, then header/png would have been used instead. In the example above, if header/png wasn't available either, then the <h1> element would be empty, as the last alternative is ''content/none''.
To make an element fallback on its contents, you have to explicitly give ''content/contents'' as a fallback:
content: url(1), url(2), url(3), contents;
What happens when no formats are supported, and the author does not explicitly indicate a fallback? Why doesn't an element fallback to ''content/contents'' unless an author explicitly says so? If the URI is part of the last comma separated value in the list, as the second URI in the following example:
h1 { content: url(welcome), "Welcome to: " url(logo); }
There appears to be some change from [[CSS21]] which says, "If the user agent cannot display the resource it must either leave it out as if it were not specified or display some indication that the resource cannot be displayed." Are we now saying that a user agent cannot display a missing image graphic in this situation? When a URI is used as replaced content, it affects the generation of ''::before'' and ''::after'' pseudo-elements.
foo { content: normal; } /* this is the initial value */
foo::after { content: contents; }
...the element's 'content' property would compute to ''content/contents'' and the after pseudo element would have no contents (equivalent to ''content/none'') and thus would not appear.
foo { content: none; }
foo::after { content: contents; }
But in this example, the ::after pseudo-element will contain the contents of the foo element.
Use cases for suppressing the content on the element and using it in a pseudo-element would be welcome. Note that while it is useless to include ''content/contents'' twice in a single 'content' property, that is not a parse error. The second occurrence simply has no effect, as it has already been used. It is also not a parse error to use it on a marker pseudo-element, it is only during the rendering stage that it gets treated like ''content/none''.
Do we need the statement about marker pseudo-elements here? Or is this legacy from the old version of the spec?
q element, used to delimit quotations. The ''quotes'' property, in conjunction with the various *-quote values of the 'content' property, can be used to properly style such quotations.
Name: quotes
Value: [ <> <> ]+ | none
Initial: depends on user agent
Applies To: all elements
Inherited: yes
Percentages: n/a
Computed Value: specified value
Media: all
The previous ED had an initial value of ''text'', which was an error. [[CSS21]] has initial value of "depends on user agent". Do we use auto for things like this, or is it just a UA stylesheet issue?
This property specifies quotation marks for any number of embedded quotations. Values have the following meanings:
<>= [open-quote | close-quote | no-open-quote | no-close-quote]
blockquote, and inserts a single closing quote at the end:
blockquote p:before { content: open-quote }
blockquote p:after { content: no-close-quote }
blockquote p:last-child::after { content: close-quote }
The device of the order of the garter is “Honi soit qui mal y pense.”English inside French:
Il disait: « Il faut mettre l’action en ‹ fast forward ›. »A style sheet like the following will set the 'quotes' property so that ''open-quote'' and ''close-quote'' will work correctly on all elements. These rules are for documents that contain only English, French, or both. One rule is needed for every additional language. Note the use of the child combinator (">") to set quotes on elements based on the language of the surrounding text:
:lang(fr) > * { quotes: "\00AB\2005" "\2005\00BB" "\2039\2005" "\2005\203A" }
:lang(en) > * { quotes: "\201C" "\201D" "\2018" "\2019" }
The quotation marks are shown here in a form that most people will be able to type. If you can type them directly, they will look like this:
:lang(fr) > * { quotes: "« " " »" "‹ " " ›" }
:lang(en) > * { quotes: "“" "”" "‘" "’" }
/* Specify pairs of quotes for two levels in two languages */
:lang(en) > q { quotes: '"' '"' "'" "'" }
:lang(no) > q { quotes: "«" "»" "’" "’" }
/* Insert quotes before and after Q element content */
q::before { content: open-quote }
q::after { content: close-quote }
to the following HTML fragment:
<html lang="en">
<head>
<title>Quotes</title>
</head>
<body>
<p><q>Quote me!</q></p>
</body>
</html>
would allow a user agent to produce:
"Quote me!"while this HTML fragment:
<html lang="no">
<head>
<title>Quotes</title>
</head>
<body>
<p><q>Trøndere gråter når <q>Vinsjan på kaia</q> blir deklamert.</q></p>
</body>
</html>
would produce:
«Trøndere gråter når ’Vinsjan på kaia’ blir deklamert.»
leader() = leader( dotted | solid | space | <Three keywords are shorthand values for common strings:>);
ol.toc a::after {
content: leader('.') target-counter(attr(href), page);
}
<h1>Table of Contents</h1>
<ol class="toc">
<li><a href="#chapter1">Loomings</a></li>
<li><a href="#chapter2">The Carpet-Bag</a></li>
<li><a href="#chapter3">The Spouter-Inn</a></li>
</ol>
This might result in:
Table of Contents 1. Loomings.....................1 2. The Carpet-Bag...............9 3. The Spouter-Inn.............13
Do leaders depend on the assumption that the content after the leader is right-aligned (end-aligned)?
BBBBBBBBBB BBB
BBBBBBBBBB ..........
BBBBBBBBBB BBB....AAA
BBBBBBB BBBBBBAInsert a line break after the before content, draw the leader on the next line, and draw the end content on top, and hide any leader strings that are not fully displayed.
BBBBBBB BBBBBB ......A
<See sections below for details on each of these.> = [ ''target-counter()'' | ''target-counters()'' | ''target-text()'' ]
target-counter() = target-counter( [ <The ''target-counter()'' function retrieves the value of the innermost counter with a given name. The required arguments are the url of the target and the name of the counter. An optional counter-style argument can be used to format the result. These functions only take a fragment URL which points to a location in the current document. If there’s no fragment, if the ID referenced isn't there, or if the URL points to an outside document, the user agent must treat that as an error. Issue: what should error handling be? Issue: restrict syntactically to local references for now.> | < > ] , < > [ , < > ]? )
…which will be discussed on page <a href="#chapter4_sec2"></a>.CSS:
a::after { content: target-counter(attr(href url), page) }
Result:
…which will be discussed on page 137.
<nav>
<ol>
<li class="frontmatter"><a href="#pref_01">Preface</a></li>
<li class="frontmatter"><a href="#intr_01">Introduction</a></li>
<li class="bodymatter"><a href="#chap_01">Chapter One</a></li>
</ol>
</nav>
CSS:
.frontmatter a::after { content: leader('.') target-counter(attr(href url), page, lower-roman) }
.bodymatter a::after { content: leader('.') target-counter(attr(href url), page, decimal) }
Result:
Preface.............vii Introduction.........xi Chapter One...........1
target-counters() = target-counter( [ <> | < > ] , < > , < > [ , < > ]? )
I have not found a compelling example for target-counters() yet.Issue: found a compelling example, in CSS specs. Do something.
target-text() = target-text( [ <> | < > ] [ , [ content | before | after | first-letter] ]? )
A simpler syntax has been proposed by fantasai: http://lists.w3.org/Archives/Public/www-style/2012Feb/0745.html
…which will be discussed <a href="#chapter_h1_1">later</a>.
a::after { content: ", in the chapter entitled " target-text(attr(href url)) }
Result: …which will be discussed later, in the chapter entitled Loomings.
meta[author] { string-set: author attr(author); }
head > title { string-set: title contents; }
@page:left {
@top {
text-align: left;
vertical-align: middle;
content: string(title);
}
}
@page:right {
@top {
text-align: right;
vertical-align: middle;
content: string(author);
}
}
Name: string-set Value: [ <The 'string-set' property copies the text content of an element into a ''named string'', which functions as a variable. The text content of this named string can be retrieved using the ''string()'' function. Since these variables may change on a given page, an optional second value for the ''string()'' function allows authors to choose which value on a page is used.> < >+ ]# | none Initial: none Applies to: all elements, but not pseudo-elements Inherited: no Percentages: N/A Media: all Computed value: specified value
[ <> <>+ ]#
H1 { string-set: chapter contents; }
When an H1 element is encountered, the ''chapter'' string is set to the element's textual contents, and the previous value of ''chapter'', if any, is overwritten.
string() = string( <The ''string()'' function is used to copy the value of a named string to the document, via the 'content' property. This function requires one argument, the name of the named string. Since the value of a named string may change several times on a page (as multiple elements defining the string can appear) an optional second argument indicates which value of the named string should be used. The second argument of the ''string()'' function is one of the following keywords:> , [ first | start | last | first-except ]? )
@page {
size: 15cm 10cm;
margin: 1.5cm;
@top-left {
content: "first: " string(heading, first);
}
@top-center {
content: "start: " string(heading, start);
}
@top-right {
content: "last: " string(heading, last);
}
}
h2 { string-set: heading content() }
The following figures show the first, start, and last assignments of the “heading” string on various pages.
content() = content( [text | before | after | first-letter | marker ]? )
<h1>Loomings</h1>CSS:
h1::before { content: 'Chapter ' counter(chapter); }
h1 { string-set: header content(before) ':' content(text); }
h1::after { content: '.'; }
The value of the named string “header” will be “Chapter 1: Loomings”.
<section title="Loomings">CSS:
section { string-set: header attr(title) }
The value of the “header” string will be “Loomings”.
Now described in [[CSS3LIST]]
Should this move back to CSS Content?
Name: bookmark-level Value: none | <integer> Initial: none Applies to: all elements Inherited: no Percentages: N/A Media: visual Computed value: specified value
section h1 { bookmark-level: 1; }
section section h1 { bookmark-level: 2; }
section section section h1 { bookmark-level: 3; }
Name: bookmark-label Value: <content-list> Initial: content(text) Applies to: all elements Inherited: no Percentages: N/A Media: visual Computed value: specified value
<h1>Loomings</h1>CSS:
h1 {
bookmark-label: content(text);
bookmark-level: 1;
}
The bookmark label will be “Loomings”.
Name: bookmark-state Value: open | closed Initial: open Applies to: block-level elements Inherited: no Percentages: N/A Media: visual Computed value: specified value
::alternate pseudo-element and the pending value of the 'content' property.
* Examples of Norwegian and French quotation marks no longer use plus signs and semicolons as delimiters.
* Dave Cramer added as co-editor. Ian Hickson and Håkon Wium Lie are now former editors.