CSS Reference Pseudo-class


The content property is used with the ::before and ::after pseudo-elements to generate content that is to be inserted into an element in the page.

The value of the content property is the content inserted into that element via the pseudo-elements.

The content inserted using the content property can be string(s) of text, glyphs, images, counters (for styling lists), or quotes. Combining multiple values into one is also possible. See the list of values below and the examples for details.

Note that the content property must be included in the set of rules for the ::before and ::after pseudo-elements, otherwise they won’t be generated and inserted. You have to always include content. In many cases, it is left empty if you don’t want to add any content and just want to use the pseudo-element for cosmetic use cases. You can read more about different use cases and examples for ::before and ::after in their respective entries.

Trivia & Notes


Content inserted into a page using pseudo-elements is not inserted into the DOM—it is only visually displayed. Hence, screen readers won’t be able to access and read the content generated using pseudo-elements. So, it is recommended that you don’t use pseudo-elements to insert vital content into a page (such as footer notes that are relevant to the article, for example).

Pseudo-elements are mostly used to insert and style cosmetic content, and should not be relied on to insert content that is relevant to the meaning and completeness of the content on the page.

Also, since the content inserted using pseudo-elements is not inserted into the DOM, this means that you cannot attach any event handlers to it using JavaScript.

Official Syntax

  • Syntax:

    content: normal | none | [ <string> | <uri> | <counter> | attr(<identifier>) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit 
  • Initial: normal
  • Applies To: ::before and ::after pseudo-elements
  • Animatable: no


No content is inserted. The pseudo-element is not generated.
Computes to none for the ::before and ::after pseudo-elements.
A string of text. The string of text is wrapped in quotation marks. See the <string> data type entry for a list of possible values.

Example: The following add a “New!” note after elements (such as items in a list of products) that have the class new.

.new::after {
    content: "New!";
    color: green;

You may also include newlines in the generated content by writing the “\A” escape sequence in one of the strings after the content property. This inserted line break is still subject to the white-space property.

The URI is specified using the url() function. It points to an external resource such as an image. If the resource or image can’t be displayed, the browser must either leave it out as if it were not specified or display some indication that the resource cannot be displayed.

For example, the following adds an icon to buttons with a class signup in a page.

button.signup::before {
    content: url(path/to/signup.png);

A CSS Counter. Counters may be specified with two different functions: counter() or counters().
See the CSS Counters entry for examples and more information.


li {
    content: counter(my-counter-name);

Counters are a fairly long topic and are outside the scope of this entry. For more information, please refer to the the CSS Counters entry.

open-quote | close-quote
These values are replaced by the appropriate string from the quotes property. Example:

q, blockquote {
  quotes: "“" "”" "‘" "’";
q:before, blockquote:before {
    content: open-quote;
q:after, blockquote:after {
    content: close-quote;

For a detailed explanation and more examples refer to the quotes property entry.

no-open-quote | no-close-quote
Stops the quotes from displaying, but continues to increment (decrement) the level of nesting for quotes. See quotes.
This function (abbreviation for ‘attribute’) returns as a string the value of attribute X of an element. If the element does not have an attribute X, an empty string is returned.

For example, links <a> have an href attribute which determines the location to which the link points. Using the content property with the attr() function you can retrieve the value of the URL in the href attribute, which is pretty powerful. This can be used in print style sheets to print the URL to which a link points, right after the content of that link (using the ::after pseudo-element). For example:

@media print {
    a[href]::after {
        content: attr(href);

The above rule selects all links that have an href attribute (using the attribute selector), retrieves the value of the href attribute using the attr() function, and then uses that value as the content of the ::after pseudo-element, which will be inserted into the links after the link’s content.

The attr() function can retrieve the value of any attribute of an element, including custom HTML5 data-* attributes. For example:

<li data-label="todo">Buy Milk</li>
li::before {
    content: attr(data-label);
    color: grey;

In CSS3, the attr() expression gets a new syntax. The new syntax is not stable, not supported in any browser yet, and there are no examples of use cases anywhere. The specification also says that the new syntax is at risk and may be dropped during the Candidate Recommendation stage. If the new syntax is not dropped, this entry will be updated with the new values. The syntax looks like the following:

attr( <attr-name> <type-or-unit>? [ , <attr-fallback> ]? )

where <attr-name> is the attribute name, <type-or-unit> is an optional argument which tells the user agent how to interpret the attribute value, and defines a type for the attr() expression. If omitted, ‘string’ is implied. The <attr-fallback> argument represents a fallback value, which is used if the named attribute is missing, or its value cannot be parsed into the given type or is invalid/out-of-range for the property. If it’s absent, the default value for the given <type-or-unit< (from the list below) is implied.

The type or unit argument can be one of the following: ‘string’, ‘color’, ‘url’, ‘integer’, ‘number’, ‘length’, ‘angle’, ‘time’, or ‘frequency’.

As mentioned above, this entry will be updated with an elaborated description and examples if the new expression syntax is not dropped in the future.


It is possible to combine different content values in the content property. The values are then concatenated into one. For example, the following will retrieve the value of the custom data attribute from the example above, and add a colon after it:

li::before {
    content: attr(data-label) ":";
    color: grey;

The following example improves the above example where the href value of a link is retrieved and printed in print style sheets. Printing the URl right after the link content without some visual separators may confuse the reader, so wrapping the URL value in parenthesis is useful and preferred. This can be done by combining the attr() function with two strings of text for the two parenthesis like so:

@media print {
    a[href]::after {
        content: " (" attr(href) ")";

The display property specifies whether the content inserted is displayed as inline-level or block-level. ::before and ::after are displayed inline by default.

Separation of Concerns—Content and Design

In addition to the accessibility issue, some people may argue that adding content via CSS is against the concept of separation of concerns—design and content should be separated to help maintain code better. This may be true in most cases, but it still allows for modular style sheets. For example, the above example where the generated content is used to style links on print style sheets is very useful and can be used in any website by just pasting the snippet into the style sheet.

Other examples such as inserting an “external link” icon to all links in a web page that refer to external pages are also veru useful and modular, and maintaining these styles and content is fairly easy, so the concept of adding content via CSS may be frowned upon by some purists, but it is still useful, and it is up to CSS authors and developers to decide what kind of content to add without affecting the maintainability of their code.

Live Demo

The following live demo shows different content added using the content property in combination with the ::before and ::after pseudo-elements.

View this demo on the Codrops Playground

You can see these demos and more in the ::before and ::after entries.

Browser Support

The content property is supported in all major browsers: Chrome, Firefox, Safari, Opera, Internet Explorer, and on Android and iOS.

Written by

Last updated February 3, 2015 at 12:33 pm by Mary Lou

Do you have a suggestion, question or want to contribute? Submit an issue.