1198Days

1198 days since this post was last revised. Specific details are likely out of date.

I’m in the midst of fully documenting my preferred approach to writing enduring style sheets. When complete, all the documentation will live at: http://ecss.io (nothing there yet!)

Until then, here’s one section I’ve been working on that is concerned with how to deal with state.

Dealing with state

The majority of web applications need to deal with state. Until now, when I have attempted to organise and rationalise how to deal with state in style sheets, I’ve probably not being doing the best job I could.

First let’s just crystallise what I mean by ‘state’. Consider some typical ‘state’ examples:

  • A user clicks a button
  • A value in the interface is updated
  • An area of an interface is disabled
  • A widget in the interface is busy
  • An entered value exceeds allowable values
  • A section of the application starts containing live data

All these eventualities require state changes to be communicated in the DOM, so that any styles changes necessary can be applied in the front-end of the application too.

The web application itself, rarely actually requires any changes to the DOM to keep track of state. Client-side JavaScript applications for example, usually have internal means of dealing with state and tracking it. Therefore, until now, making changes to the DOM has been purely to affect aesthetic change via CSS (styling purposes).

How ECSS used to handle state change

Historically, ECSS, used a ‘tense’ micro-namespaced class in addition to any existing classes on the node to communicate this state. For example:

Incorrect code. Illustration only:

  • .is-Suspended
  • .is-Live
  • .is-Selected
  • .is-Busy

A node using these classes in the DOM might look like this:

<button class="co-Button is-Selected">Old Skool Button</button>

Switching to WAI-ARIA

However, if this information has to go in the DOM purely for styling hooks, it may as well lift a little more weight while its there.

These same styling hooks can actually be placed in the DOM as WAI-ARIA states. The States and Properties section of WAI-ARIA describes the W3C’s standardised manner in which to communicate states and properties to assistive technology within an application. In the opening section of the abstract description for WAI-ARIA contains this:

These semantics are designed to allow an author to properly convey user interface behaviors and structural information to assistive technologies in document-level markup

While the specification is aimed at helping communicate state and properties to users with disability (via assistive technology) it serves the need of a web application project architecture beautifully. Adopting this approach results in what is (cringingly) referred to as a ‘Win Win’; situation. We get to improve the accessibility of our web application, while also gaining a clearly defined, well considered lexicon for communicating the states we need in our application logic. Here’s the prior example re-written with aria to communicate state:

<button class="co-Button" aria-selected="true">Old Skool Button</button>

Class handles the aesthetics of the button. The aria-* attribute communicates the state (if any) of that node or its descendants.

In JavaScript application land, the only change needed is shifting from classList amendments for state changes to attribute amendments. For example, to set our button attribute:

button.setAttribute("aria-selected", "true");

ARIA attributes as CSS selectors

In our preferred CSS syntax, writing that change within a single set of braces would look like this:

.co-Button {
    background-color: $color-button-passive;
    &[aria-selected="true"] {
        background-color: $color-button-selected;
    }
}   

We use the ampersand (&) as a parent selector (as per Sass language conventions but preferably via PostCSS) and the attribute selector to leverage the enhanced specificity having the aria attribute on the node provides. Attribute selectors are nice low specificity (like classes) so there is no adverse effect on specificity. Then we can just style the changes as needed.

As a related note, the CSS Selectors Level 4 specification makes provision for case insensitivity by using a `i` flag before the closing square bracket. For example:

.co-Button {
    background-color: $color-button-passive;
    &[aria-selected="true" i] {
        background-color: $color-button-selected;
    }
}   

This allows any case value variant of the attribute to pass (by default it is case sensitive)

Nested syntax note

As documented elsewhere, the ability to nest state changes within a rule provides increased developer ergonomics. The intention is that a rule is only defined at root level once throughout the entire application’s styles. This provides a single source of truth to define all possible eventualities pertaining to that class.

States and properties, redone with ARIA

Section 6.5.1. of the WAI-ARIA specification describes ‘Widget Attributes’, these contain many of the common states needed when working with a web application and rapidly changing data.

Here are the examples given at the beginning of this document re-written using ARIA:

  • aria-disabled="true" (used instead of is-Suspended)
  • aria-live="polite" (used instead of .is-Live, the polite value is one of three possible values to describe how updates should be communicated)
  • aria-pressed="true" (used instead of is-Selected. Would indicate a button (or similar) has been pressed, would toggle to aria-pressed="false" when pressed again)
  • aria-busy="true" (used instead of is-Busy, to indicate the element and it’s subtree (if any) are busy

There are plenty more and the specification is (by W3C specification standards) easy to understand.

Summary

Using WAI-ARIA states to communicate changes in the DOM provides styling hooks that are as useful and easy to use as HTML classes. They also present no additional code in a JavaScript application to switch and toggle the values. While preference, I’m also a fan of the fact that an entirely different selector is used to communicate state in the style sheets. It is simpler to spot within a rule.

None of those prior factors really buy you anything new. What using WAI-ARIA states will do, virtually for free, is start to provide a better means of communicating your web applications state to users of assistive technology. If money talks, consider also that by using WAI-ARIA you are widening your product up to a greater number of users.

As such, using WAI-ARIA states and properties, is the recommended means of communicating state in projects adopting a ECSS methodology.

Ben Frain Developer, Author: 'Enduring CSS', 'Responsive Web Design with HTML5 & CSS3'.