Declaring character encodings in CSS

Intended audience: CSS coders, Web project managers, and anyone who wants to know how to declare the character encoding of a CSS file.

Updated

Question

How do I declare the character encoding of a CSS style sheet?

If you have any non-ASCII text in your CSS file, for example non-ASCII characters in font names, in values of the content property, in selectors, etc., you need to be sure that the CSS parser knows how to transform the bytes into characters correctly, so that it understands your CSS code. This article describes how to do this.

Answer

You should always use UTF-8 as the character encoding of your style sheets and your HTML pages, and declare that encoding in your HTML. If you do that, there is no need to declare the encoding of your style sheet.

Other approaches are only needed if your style sheet contains non-ASCII characters and, for some reason, you can't rely on the encoding of the HTML and the associated style sheet to be the same. In this case you should use @charset or HTTP headers to declare the encoding. (If your HTML and CSS files use the same encoding, the latest versions of major browsers will apply the encoding of the HTML file to the CSS stylesheet.)

Details

Using @charset

As mentioned above, you should only use this when the style sheet and the calling HTML file are in different encodings.

It is important to understand that, although the @charset declaration looks like a CSS at-rule, it is not parsed as such for detection of the character encoding. Only an exact byte sequence, beginning with the very first byte in the style sheet, will be effective. Variations, even those that would be valid for a normal at-rule with the same syntax, are silently ignored.

To set the character encoding inside the style sheet, use the following sequence of bytes, apart from the charset-name, at the very start of the file, one byte per character.

@charset "charset-name";

The charset-name is case-insensitive, but should always be utf-8 for new style sheets. If you really cannot use UTF-8 for your style sheet, see Working with non-UTF-8 encodings, below.

Only one @charset byte sequence may appear in an external style sheet and it must appear at the very start of the document. It must not be preceded by any characters, not even comments.

Note! It is not enough to simply put @charset "utf-8"; at the top of the style sheet – you need to also save your style sheet in the UTF-8 character encoding. (See Using an encoding with your content.)

Important: Since the HTTP header has a higher precedence than the in-document @charset declaration, you should always take into account whether the character encoding is already declared in the HTTP header. If it is, @charset must be set to declare the same encoding, and will only have an effect when the style sheet is read in a context where there are no HTTP headers (eg. from a local drive).

The techniques index provides a set of links to help you detect whether a declaration is being sent in the HTTP header.

What about the byte-order mark?

The CSS3 Syntax specification says that if you have a UTF-8 byte-order mark at the start of your file, this should cause the browser to read the style sheet as UTF-8, regardless of any other declaration. Unfortunately, at the time of writing this is not supported interoperably – Internet Explorer 10 and 11 still give higher precedence to the HTTP header and @charset declarations.

So for the time being you should rely on the @charset or HTTP header declarations instead. The former has the additional advantage that it helps people looking at the source code to ascertain what is the encoding of the style sheet. The byte-order mark is invisible.

Read more about the byte-order mark.

Using HTTP

The server may already send a default character encoding declaration in the HTTP Content-Type header when your browser retrieves a style sheet, or it may not. This line in the HTTP response would indicate that the file is encoded in UTF-8.

Content-Type: text/css; charset=UTF-8

It could be that the server is serving a style sheet with an encoding declaration that you don't want, due to server-wide defaults or specific settings, or serving without an encoding declaration when you want one. You can change the situation either for the server as a whole, or for a specific file or set of files, by changing the server settings (globally or locally) or by using code in scripts such as PHP.

The declaration in the HTTP header will always override the in-document declaration, if there is a conflict, except for those browsers where the byte-order mark overrides it.

However, we recommend that if you need to use an HTTP declaration to set the correct encoding, you also include an @charset declaration inside the style sheet. This will ensure that the encoding is still known if the style sheet is used locally or moved, eg. for testing or editing.

Additional information

Most people will not need to know the information in this section. It is provided for the sake of completeness.

Working with non-UTF-8 encodings

This section is only to be read if you really cannot save your style sheet as UTF-8.

Until recently the IANA registry was the place to find names for encodings. The IANA registry commonly includes multiple names for the same encoding. In this case you should use the name designated as 'preferred'.

The new Encoding specification now provides a list that has been tested against actual browser implementations. You can find the list in the table in the section called Encodings. It is best to use the names in the left column of that table.

Note, however, that the presence of a name in either of these sources doesn't necessarily mean that it is OK to use that encoding. Several of the encodings are problematic. If you really can't use UTF-8, you should carefully consider the advice in the article Choosing & applying a character encoding.

The HTML 4.01 specification describes a charset attribute that can be added to the link element to indicate the encoding of the document you are linking to. However, the use of this attribute on a link element is currently obsoleted by the HTML5 specification, so you shouldn't use it.

Further reading