Use the :lang pseudo-class over the lang attribute selector for language-specific styles

The content of HTML documents can be in many different languages. To specify the primary language of a document, we use the lang attribute on the root element.

<html lang="en">

We can also use the lang attribute within the page to demarcate specific elements or sections that are in a different language to the document’s primary language.

<html lang="en">
<head></head>
<body>
<section lang="fr">
<p>Comment dites-vous "Bonjour" en Espanol?</p>
</section>
</body>
</html>

If we wanted to style these sections of the page differently, we could use the [lang] attribute selector to select all elements, or children of elements, with the specific language attribute.

[lang="fr"] p {
background-color: #002295;
color: #fff;
}

The [lang] attribute selector doesn’t know the element’s language #

The problem with having language-specific styles based on the [lang] attribute selector is that the selector isn’t actually aware of the language of the element. It’s just like any other “dumb” attribute selector.

This can become a problem if we have a document with multiple, nested elements of different languages. Let’s take this section below. The section has a French lang attribute but, within the section, we have a quote in Spanish.

<section lang="fr">
<p>Comment dites-vous "Bonjour" en Espanol?</p>
<blockquote lang="es">
<p>Hola!</p>
</blockquote>
</section>

In our CSS, we may have simply styled all elements with a particular lang attribute and its descendants.

[lang="es"] p {
background-color: yellow;
color: #000;
}

[lang="fr"] p {
background-color: blue;
color: #fff;
}

Both paragraphs result in blue background-color

CSS has no concept of prioritising closer parents, so it doesn’t matter that the Spanish lang attribute is closer to the block quote paragraph element than the French one. Both of these styles are equally applicable. Because the style of the French language happened to be declared later in the CSS file, it prevails, even though, looking at the markup, we would have wanted the Spanish style to be used.

The :lang pseudo-class #

The :lang pseudo-class provides a solution to the limitations of styling the lang attribute in two ways:

  1. It uses the actual language of the element selected
  2. It can be applied to any element and is not directly based on the lang attribute

:lang and the "content language" #

The :lang pseudo-class is used to select an element based on its content language. The content language of an element is determined by a combination of three things:

  • Any lang attributes
  • Meta tags, e.g. <meta http-equiv="content-language" content="en">
  • HTTP headers, e.g. Content-language: en

This means that the :lang pseudo-class can be used even in cases where no lang attribute is specified.

:lang and nesting #

Being a pseudo-class, :lang is best used on specific elements rather than on children.

Using the same example as above, we can switch to using the :lang() attribute to select the paragraph elements. But instead of selecting the child paragraph elements of the specified languages, we can select the paragraph elements that are themselves of the specified language.

p:lang(es) {
background-color: yellow;
color: #000;
}

p:lang(fr) {
background-color: blue;
color: #fff;
}

Even though there is no lang attribute on the paragraph elements themselves, we are still able to use the pseudo-class because the content language of the paragraph is inherited from its parent.

The paragraph in Spanish is yellow

As we can see, the correct colours are applied to each paragraph.

Keep in touch KeepinTouch

Subscribe to my Newsletter 📥

Receive quality articles and other exclusive content from myself. You’ll never receive any spam and can always unsubscribe easily.

Elsewhere 🌐