Pseudo-classes – The Basics

The following is adapted from HTML5 & CSS3 for the Real World, created by Alexis Goldstein, Louis Lazaris, and Estelle Weyl.


It’s likely that you’re already familiar with some of the user interaction pseudo-classes, namely :link, :visited, :hover, :active, and :focus.

Important: Key Points to Note

There are security issues the :visited pseudo-class can pose, so browsers do not support all CSS properties on visited links. Without these limitations, malicious sites could apply a style to a visited link, such as a unique background image for each visited link, to check whether popular sites or banks have been visited by the user. This allows the attacker to glimpse the user’s browsing history without their permission. As a result, modern browsers limit the styles that can be applied with :visited.

The spec explicitly condones these changes, saying: UAs [User Agents] may, therefore, treat all links as unvisited links, or implement other measures to preserve the user’s privacy while rendering visited and unvisited links differently.

For better accessibility, add :focus wherever you include :hover as not all visitors will use a mouse to navigate your site.

:hover can apply to any element on the page not just links and form controls.

:focus and :active are relevant to links, form controls, content editable elements, and any element with a tabindex attribute.

While it’s likely you’ve been using these basic pseudo-classes for some time, there are many others available. Several of these pseudo-classes have been in the specification for years, but weren’t supported (or commonly known) until browsers started supporting the new HTML5 form attributes that made them more relevant.

The following pseudo-classes match elements based on attributes, user interaction, and form control state:

A user interface element that’s enabled, which is basically any form control that supports the disabled attribute but doesn’t currently have it applied.

Conversely, a user interface element that is disabled: any form control that supports the disabled attribute and currently has it applied.

For radio buttons or checkboxes that are selected or ticked.

For form elements that are neither checked nor unchecked. For example, if you tick a check all checkbox to select a group of checkboxes, then deselect some but not all of the checkboxes in the group, the check all could be set to the indeterminate state (with JavaScript) to indicate that it’s neither checked nor unchecked.

This selector singles out the element that is the target of the currently active intrapage anchor. That sounds more complicated than it is: you already know that you can have links to anchors within a page by using the # character with the ID of the target. For example, you may have Skip to content link in your page that, when clicked, will jump to the element with an ID of content.

This changes the URL in the address bar to thispage.html#contentand the :target selector now matches the element in the document that has content as its ID. It’s as if you had included, temporarily, the selector #content. We say temporarily because as soon as the user clicks on a different anchor, :target will match the new target.

Applies to one or more UI elements that are the default among a set of similar elements. For example, the one radio button in a group of same-named radio buttons that was checked on page load will continue to match :default after another radio button in the same-named group is selected. Similarly, checkboxes that are selected on page load will continue to match :default after they are unchecked.

Applies to elements that are valid, based on the type, pattern, or other input attributes (as we discussed in Chapter 4).

Applies to empty required elements and elements failing to match the requirements defined by the type or pattern attributes.

Applies to elements with range limitations where the value is within those limitations. This applies, for example, to date/time, number, and range input types with min and max attributes. When the value is null, it is :in-range.

The opposite of :in-range: elements whose value is outside the limitations of their range. Missing values are not out of range, as they are empty.

Applies to form controls that have the :required attribute set.

Applies to all form controls that do not have the :required attribute.

Applies to elements whose contents are unable to be altered by the user. This is most elements other than those with the contenteditable attribute set and form fields.

Applies to elements whose contents are user-alterable, such as contenteditable components and writable input fields.

Browser support for these attributes is complete in browsers that support the attributes in their form controls; in other words, browsers that support required and pattern also support the associated :valid and :invalid pseudo-classes.

IE8 and earlier lack support for :checked, :enabled, :disabled, and :target. The good news is that IE9 does support these selectors, but not the user-interface selectors. IE10 and IE11 support :indeterminate, :required, and :optional, but not :default, :in-range, :out-of-range, :read-only, or :read-write.

While support is still lacking, JavaScript libraries such as Selectivizr can help in targeting these pseudo-classes in Internet Explorer.