How Our CSS Framework Helps Enforce Accessibility


Screenshot of two visually identical 'Buy it Now' buttons

Spot the difference….You can’t! To a sighted user it appears we have two identical button elements.

A user interface control not only needs to look like a certain control, it must be described as that control too. Take for example a button, one of the simplest of controls. There are many ways you can create something that looks like a button, but unless you use the actual button tag (or button role – more on roles later), it will not be described as a button.

Why does it need to be described as a button? Users of AT (assistive technology), such as a screen reader, may not be able to see what the control looks like visually; therefore it is the job of the screen reader to describe it aurally. A screen reader, such as VoiceOver for Mac OSX and iOS, can do this job only if we, the developers, ensure the correct semantics are present in our HTML code.


In the table below, compare and contrast the accessibility tree attributes for each element  (hint: click each image to view at full size). VoiceOver uses the accessibility tree to convey to the user what it knows about the web page. You will see that for the fake button, there is nothing in the tree to identify the span element as a button. Quite simply, VoiceOver does not know this element is intended to be a button.

Now spot the difference: this is how VoiceOver sees these two elements
‘REAL’ button ‘FAKE’ button
HTML <button class="btn">Buy it Now</button> <span class="btn">Buy it Now</span>
ACCESSIBILITY TREE ATTRIBUTES Annotated accessibility tree of real button Annotated accessibility tree of fake button
VOICEOVER “Buy it now, Button.”

“To click this button press CTRL-OPTION-SPACE.”

“Buy it now.”

Accessibility tree screenshots taken from Mac OSX Accessibility Inspector

What’s also interesting is that if you look at the ‘Actions’ section of the tree, the real button has an ‘accessibilityPerformPress’ action, while the fake button does not. Armed with this information, VoiceOver can also describe how to interact with the element (e.g., press CTRL-OPTION-SPACE). No such information will be communicated for the fake button.

We can safely say that this fake button is not accessible, because the AT doesn’t know what it is or how to interact with it. It appears our fake button is accessible only to people who can see the screen and use a mouse. Oh dear – this fake button has excluded a large number of our users from being able to buy items!

Swiss cheese

You might be wondering, “Who on earth would use a span or div tag for a button?”

You might now also be thinking, “What on earth does Swiss cheese have to do with any of this?”

In the Swiss cheese model of accident causation, risk of a threat becoming a reality is mitigated by differing layers and types of defenses that are “layered” behind each other. For example, we might use code linting, code reviews, accessibility checkers, and manual testing to help ensure that this button is properly described. We liken these separate layers to multiple slices of Swiss cheese, stacked side by side – hence the name.

Illustration of swiss cheese model

Is there anything cheese can’t do? Although many layers of defense lie between hazards and accidents, there are flaws in each layer that, if aligned, can allow the accident to occur.

What if we could also write our CSS framework in a way that acts as another layer in our line of defense? Read on to find out how!

Enforcing roles

Continuing on from our previous ‘fake button’ example, let’s suppose the developer had created the following rules to make the span element appear visually like a button:

.btn {
  background-color: #0654ba;
  border-radius: 0.25em;
  color: white;
  padding: 0.25em 1em;

Screenshot of fake 'Buy it Now' button

The dreaded fake button (although you still can’t tell, just by looking at it)

What we have here is the proverbial cart before the horse. The developer has styled the element before describing its purpose. One way in which we can create the necessary description (the horse) is to require a role attribute. We’ll go into more detail on the role attribute later, but here’s the interesting bit – we can leverage attribute selectors and re-write our CSS like so:

[role=button].btn {
  background-color: #0654ba;
  border-radius: 0.25em;
  color: white;
  padding: 0.25em 1em;

Screenshot of unstyled 'Buy it Now' span element

Under the skin: our attribute selector has now exposed the fake button for the fraud that it is!

Our selector now ensures that a button will visually appear like a button only if it has first been described as a button. You can almost think of this as TDD (test-driven development). If the HTML does not pass our ‘test’, the visual style will not be applied.

Implicit roles

It’s important to know that nearly all elements have a default implicit role, and these default roles do not need to be specified in the HTML – to do so would be redundant. No prizes for guessing what the default role of a button element is. Yes, it’s button!

You might think that it was easy enough for us to convert a span into an accessible button using the button role, but in actual fact our work would not be finished there. Adding a role does not add behavior. A fully accessible button must be keyboard focusable and it must be invokable with SPACE and ENTER keys too. A button element gives this behavior for free; a span element – even with a role of button – does not, and we must implement its behavior by hand.

So please, and I really can’t emphasize this strongly enough, do everybody a favor and always use an actual button element for buttons.

The only real reason you might have for using the button role is when progressively enhancing a link into a button using JavaScript; for example, to make the link open an overlay instead of a new page – which is exactly what we do on eBay. As with spans and divs, allowing anchor tags for buttons does re-open the door to misuse and abuse (think ‘faux’ buttons); and though it is possible to enforce the correct usage with clever use of attribute selectors, it’s a little more convoluted and therefore beyond the scope of this post.

Again, we can enforce this markup requirement by rewriting our CSS selector like so:

button.btn {
  background-color: #0654ba;
  border-radius: 0.25em;
  color: white;
  padding: 0.25em 1em;

Screenshot of our final 'Buy it Now' button

Horse, cart, & driver: the element now has the appearance, description, and interaction of a button

Finally, no more span and div tags for buttons. Our CSS framework simply does not allow it.

Enforcing states

So far we’ve looked at a simple example of how CSS selectors can force developers to put the proper semantics in place – whether implicitly or explicitly. But what about state? If an element has state (a checked checkbox for example), it is not sufficient to describe only what the element is; we must also describe what state it is in.

Developers often fall into exactly the same trap as before: they convey the state visually but not aurally.

In the following code example, the developer has used a modifier class of btn--disabled in order to alter the opacity and background-color of the button:

button.btn--disabled {
  background-color: #999;
  opacity: 0.5;

Screenshot of a button that appears visually disabled

Our ‘ghosted out’ button appears visually disabled

Modifier class is a BEM (Block, Element, Modifier) concept. Throughout this article we will be using a variation of BEM in order to structure and distinguish our class names.

You might be thinking that this isn’t really disabled. If so, you are quite right. This button will not be described as disabled and it will not behave as disabled.

Again, you might be thinking, “Who actually does this kind of stuff?”, but fear not, our CSS selectors can again protect us from this manner of profanity:

button[disabled] {
  background-color: #999;
  opacity: 0.5;

As you can see, the previous modifier class will no longer cut the mustard. It is removed from the selector entirely and the HTML disabled property takes its place. Only when this property is applied in the markup will the button be well and truly disabled for all users.

Comparing accessibility trees we see that the button with class name is still described as ‘Enabled’
Disabled property Disabled class
Annotated accessibility tree of button with disabled property Annotated accessibility tree of button with disabled classname

So far, none of this is particularly earth-shattering, I’m sure you agree, but it sets the stage nicely for moving onto more complex controls and widgets, where we must start delving deeper into the world of WAI-ARIA (commonly referred to as just ARIA for short).


HTML gives us only a limited set of controls such as buttons, links, and the various form value inputs. What about menus, tabs, carousels, overlays, etc. – how do we describe those? Yes, you guessed it – ARIA comes to our rescue.

ARIA gives us many more roles beyond a simple button, and these roles, in conjunction with a multitude of states and properties, open up a whole new set of desktop-like user interface controls and widgets for us to play with. Just make sure you read the instructions before diving in. You do read the instructions don’t you?

Look out for more controls in HTML5, such as menu and dialog. In fact, you might be interested to know that both the menu and dialog tags started out life as ARIA roles before they were introduced as bona fide HTML elements. Don’t get too excited, though – neither have cross browser support at the time of this writing.

In the next section we will look at an example of such a widget and demonstrate how we can use ARIA to influence the way we write CSS selectors in order to enforce accessible markup.


A tabs widget allows the layered stacking of two or more content panels, whereby only one panel of content can be visible at any time. A list of clickable tabs allows the user to swap out the visible panel. This all happens on the client, without a full page reload (i.e., the client is stateful). By decluttering the user interface in this way we can say that a tabs widget follows the principle of progressive disclosure.

Screenshot of eBay's tabbed interface for sign-in or register

Using tabs, the user can switch between “Sign In” or “Register” without a full page reload.

It is critical that our interface is not only visually identifiable as a tabs control (I’ve seen designs that struggle even to meet this criterion!), but also aurally. Without any tab-related HTML tags, how do we achieve this?

Faux tabs

A seasoned developer might set out initially to create the tabs as a list of clickable page anchors for the tabs, with a group of divs acting as anchor targets for the tab panels:

<div class="tabs">
    <li class="tabs__tab tabs__tab--selected">
      <a href="#sign-in">Sign in</a>
    <li class="tabs__tab">
      <a href="#register">Register</a>
    <div class="tabs__panel tabs__panel--active" id="sign-in">
      <!-- Sign in Content -->
    <div class="tabs__panel" id="register">
      <!-- Register Content -->

This is a perfectly reasonable approach to begin with. Page anchors are often well suited as the starting point for tabs, because in the case of JavaScript being unavailable they ensure at least some basic functionality when clicked (i.e., the browser will scroll to the content of the relevant panel). However, when JavaScript does become available, care must be taken to prevent the default link behavior so as to not interfere with tab semantics and behavior. Let me be very clear about this: links are not the same as tabs!

This technique of making core content and functionality available pre-CSS and pre-JavaScript is called progressive enhancement. Progressive enhancement is the safest and surest way to guard against the unknown (e.g., script timeout, script failure, scripting disabled) and to ensure your core experience remains backwards and forwards compatible in all HTML-capable browsers.

We will assume that all layout-related styling is in place for the links (i.e., they are neatly spaced out horizontally), and that by default the visible state of all panels is hidden, with only the ‘active’ panel displayed. Let’s then suppose our developer chooses to visually convey the selected ‘tab’ state using only an underline (a veritable tour de force of minimalism, I know):

.tabs__tab {
  text-decoration: none;
.tabs__tab--selected {
  text-decoration: underline;
.tabs__panel {
  display: none;
.tabs__panel--active {
  display: block;

It would now take only a small amount of JavaScript for our developer to turn this into a “functioning” tabs widget by preventing the default link action (i.e., prevent it navigating to the URL fragment) and toggling the ‘selected’ and ‘active’ modifier classes accordingly; and indeed our developer might be tempted to stop there.

But although this control looks like a tabs widget, it will currently be described only as a list of links (scroll down to see the accessibility tree). No clues are given as to the dynamic, stateful nature of the widget. Screen reader users attempting to follow one of these links are going to be surprised when nothing happens after invoking the link, and equally surprised when no navigation occurs. They are left guessing as to what type of control they might be interacting with. Not a good experience.

Let’s fix it so that if developers try to use our amazingly awesome CSS to style their tabs like ours (go on, admit it, you want that underline too), the styles will appear only if they have the correct accessible markup in place.

Real tabs

To achieve the correct markup for tabs, just as with our simple button example, we can replace class names with ARIA roles and states.

Luckily, ARIA gives us a set of tab-related roles:

  • tablist
  • tab
  • tabpanel

We can also leverage the following global ARIA states:

  • aria-selected
  • aria-hidden
  • aria-controls
  • aria-labelledby

Whilst it would be entirely possible to continue on with our demonstration of progressive enhancement by applying the above roles and states to override our previous link-based markup, it does add some additional complexities which might distract us from the primary topic at hand. So, rather than getting bogged down in those details, let’s drop the progressive enhancement for now and pretend we live in a magical world where JavaScript is always on, is always available, and always works.

Actually, to be honest, it’s not just a JavaScript issue. Some people would argue that by using list-based markup, we also provide for a reasonable semantic fallback in the cases where the tab & tablist roles are not supported by the user’s browser & AT combo.

It will make most sense if we show you the new HTML first this time, rather than the CSS, and hopefully, without the cognitive clutter of the list and link tags, our end goal is now a little clearer. You will quickly see that the core DOM structure remains almost identical:

<div class="tabs">
  <div role="tablist">
    <div role="tab" aria-selected="true" tabindex="0">
      <span>Sign in</span>
    <div role="tab" aria-selected="false" tabindex="-1">
    <div role="tabpanel" id="sign-in" aria-hidden="false">
      <!-- Sign in Content -->
    <div role="tabpanel" id="register" aria-hidden="true">
      <!-- Register Content -->

With these new ARIA roles in place, our tabs will now actually be described as tabs by assistive technology. Likewise, when our JavaScript toggles the ARIA selected state, this state will also be conveyed to our users.

Note that AT actually requires two additional ARIA properties that are not present in our markup: aria-controls (on the tabs) and aria-labelledby (on the tabpanels). These ARIA properties are not typically used as styling hooks on tabs, so we will leave them out for the sake of code brevity; but be sure to include them when building your own tabs widget!

Okay, so we are nearing the end now, but first we must finish up our CSS. Our selectors must become a contract for the accessible HTML above. Where before we had classes for BEM blocks and elements, now we have ARIA roles. Where before we had classes for BEM modifiers, now we have ARIA states:

.tabs [role=tab][aria-selected=false][tabindex="-1"] {
  text-decoration: none;
.tabs [role=tab][aria-selected=true][tabindex="0"] {
  text-decoration: underline;
.tabs [role=tabpanel][aria-hidden=true] {
  display: none;
.tabs [role=tabpanel][aria-hidden=false] {
  display: block;

Personally, I’m a big fan of BEM, but it’s nice where possible like this to be able to replace it with something a little more real, if you know what I mean.

Finally, let us compare the accessibility tree of the first real tab with the first faux tab
Real tab Faux tab
Annotated accessibility tree of real tabs Annotated accessibility tree of faux tabs

One other rule we have enforced in our selectors is the tabindex attribute. Keyboard accessibility for tabs must be implemented in JavaScript using a roving tabindex technique; this is because the tabs in a tablist are selected using the arrow keys, not the tab key (the tab key is actually used to exit the list of tabs). While not strictly necessary to ensure the correct description is given, this selector helps ensure that the correct attribute values are in place for roving tabindex behavior. It’s up to you whether you want to go this far, into the realm of behavior-testing, in your own selectors.

Good behavior

We must always remember that correctly describing a UI control is only part of making it accessible. The user expectation is that it behaves like that control too. Therefore we must also ensure that the correct accessible behavior is in place.

For example, a button must always be ‘clickable’ with SPACE and ENTER keys. Sadly, this kind of behavior is often the first thing to go missing when developers try rolling their own buttons using span or div tags.

More complex controls such as tabs, menus, or autocomplete will typically require a more significant amount of JavaScript in order to make sure the control fully behaves according to its description.


We have seen that each layer of the web frontend has its own responsibilities in terms of creating accessible UI controls:

  • HTML provides the aural description and some built-in behavior
  • CSS provides the visual style and interaction clues
  • JS provides any missing behavior not provided by ARIA or HTML

HTML provides behavior, without the need for JavaScript, for built-in tags such as links, buttons, and form controls.

For the purpose of this blog post, our focus has been primarily HTML and CSS. HTML is fundamental in laying solid foundations for accessible UI controls and widgets, and we have shown how those foundations can be enforced by use of CSS attribute selectors.

So, the next time you find yourself creating a class name like ‘active’, ‘hidden’, ‘on’, or ‘off’ – stop and think instead how you might be able to leverage HTML properties or ARIA states in your selectors. Likewise, if you find yourself creating a class name like ‘btn’, ‘tab’, or ‘dialog’ – also stop and think about how you might be able to leverage an existing HTML tag or ARIA role.

Thank you for reading. I hope you enjoyed it. If you are interested in more accessibility-related articles in future, be sure to leave a comment below!

Finally, if you are interested in learning more about our CSS framework, watch this space for an upcoming announcement and further details. We are currently applying the finishing touches to the framework before releasing it as open source.

Appendix / bibliography

51 thoughts on “How Our CSS Framework Helps Enforce Accessibility

  1. Dan

    Great, great post. Super informative and a really preventative way of enforcing best practices at a central (styleguide) level. Thanks Ian!

  2. Ian McBurnie Post author

    Dan, thank you for your feedback and kind comments. Much appreciated!

  3. Daniel Eden

    This is really cool! Inspired us to work on some similar enforcement at Dropbox, but with a slightly different approach.

    Rather than not styling the element at all, we style the element as though the requirement for it to be a `button`, for example, were not present, but then we use the `:not` selector to add an egregious red outline to the element. On inspecting the element, the engineer will see a comment above the red outline declaration telling them to use a correct tag, role, etc.

    Here’s a PR adding this feature via an `assert-selector` mixin:

  4. Hakim

    Really helpful post, thanks Ian. It’s changed some Of my HTML markup way…


  5. Ian McBurnie Post author

    Thanks, Jonathan! I’m hoping 2016 will bring more articles like this.

    Daniel, tooling such as that is a great idea and will surely reduce the learning-curve for those developers who are left scratching their head when the styles are not applied. Thanks for sharing!

  6. Pingback: The Late Code: November 5, 2015 - Matt Sparks

  7. Alasdair Clark

    This is win-win for code maintenance too. By naming something what it actually is in the code, next time the developer comes to change it they can easily reason about it.

  8. Ian

    Nice to see this, maybe if we say it often enough developers will actually start doing this!

  9. David Gilbertson

    This is quite brilliant. We are currently 60% of our way through a project and accessibility has not been built in so far (I know, I know). I now plan to update our CSS to target the correct semantic elements and aria roles. This will hopefully break the page visually where it would have been broken for users relying on AT..

  10. Marcy Sutton

    This is awesome! I especially love how CSS can augment front-end test coverage. Thank you for writing!

  11. Di Wu

    Great post! Thanks!

    So does adoption of ARIA affect SEO or not? I think Google is serious about accessibility, so I guess by optimizing accessibility with ARIA could have positive impact on SEO. Does anyone have experimented with it?

  12. Neil Osman

    True joy, thanks!
    Made me think:
    A. Consider the option to select all none interactive elements with the proper ARIA role and attach each a key event function to handle the relevant keycode.
    B. Consider the option, in certain scenarios to run tests on pages with none native interactive elements that has a registered click event.

  13. Pingback: [Educator-Gold] [webdev] Web Design Update: November 12, 2015 | educatorgold

  14. Pingback: [Educator-Gold] [webdev] Web Design Update: November 12, 2015 | educatorgoldarchives

  15. Pingback: HTML5 Weekly No.214 | ENUE Blog

  16. Eric Wright

    Thank you for writing! I appreciate the plain language (and the technical chops!). I’ll be a regular reader of more accessibility content. Thanks, too, Daniel, for sharing the approach at Dropbox.

  17. Ian McBurnie Post author

    Thank you everyone for your kind comments, they certainly go a long way towards making writing a more rewarding experience, so I am very grateful.

    Also, after publishing, it came to my attention that Mr Heydon Pickering had touched upon the very same subject (using attribute selectors to test for bad HTML) as part of an article he wrote back in 2013, ‘Semantic CSS With Intelligent Selectors’. I highly encourage you to check that out too, in it’s entirety, if you haven’t done so already.

  18. Pingback: Proper Use of Buttons and Links | Web Axe

  19. Pingback: How Our CSS Framework Helps Enforce Accessibility | – route404 –

  20. Pingback: Дайджест интересных материалов из мира веб-разработки и IT за последнюю неделю №185 (8 — 15 ноября 2015) -

  21. Carl

    The amount of depth and explanation you have gone into is perfect and I can’t wait to start implementing these changes myself. As a big user of BEM and state-named classes such as .is-active it isn’t too much of a step to switch my code to using elements and HTML states.

    Accessibility is something that I’m always to improve on, and I think this will really be beneficial, especially for my team.

    Thanks for writing this article. I look forward to reading more in the near future 🙂

  22. Becka11y

    Too bad your blog doesn’t follow proper accessibility principles and include alt attributes on the images!

  23. Nap

    Great article! This was very helpful, I’m using div, span, a for a long time and this will definitely change my coding. I’m really thankful I bump into this.

    Thanks Ian

  24. Joanne

    I’d like to learn how you set up your CSS tests to detect non-semantic HTML.

    1. Ian McBurnie Post author

      Hi Joanne. We can guard against non-semantic html using a similar technique as described in the post, and it’s essentially what Heydon Pickering describes as using ‘intelligent selectors’.

      Supposing we have a simple ordered list component. A common mistake would be to create selectors like ‘.my-ordered-list’ and ‘.my-ordered-list__item’. These types of selectors open the door to non-semantic HTML (such as divs), because they do not specify an element selector. Better selectors would be ‘’ and ‘’ (or drop the BEM notation entirely and use a simpler ‘ > li’). Yes, this is a trivial example but the concepts can be applied anywhere.

      Here is Heydon’s article:

      I hope I understood your question correctly.

  25. Pingback: How Our CSS Framework Helps Enforce Accessibility | Tech +

  26. alexander farkas

    As I saw the title in my reader I expected a superficial article. Fortunately it is a very good one. So thanks for this.

    I would like to just criticize one point.

    You say:
    > We must always remember that correctly describing a UI control *is only part of making it accessible*. The user expectation is that it behaves like that control too. Therefore we must also ensure that the correct accessible behavior is in place.

    In my eyes the last part of your advice is so important, that it negates the first sentence. In reality describing UI components with ARIA without implementing the corresponding behavior, doesn’t improve a11y a little bit/partially. Often a11y is harmed by this approach.

    ARIA should follow the implemented behavior, not vice versa. Take your tabs example. Consider the developer has implemented just the normal (mouse) click behavior of a tab control and you ensure he changes the right attributes (aria-selected) and so on. But the JS developer has not implemented the keyboard behavior, roving tabindex and/or the focus management ( In this case the tab does not only look like a tab, it also describes itself as one, which means a screenreader user will try to control it via cursors and he/she will fail.

    If you would use the old school markup on the other hand (internal links) a screenreader user will know, that he can control it via a simple click (a click on a link is input independent ). From there it is much simpler to make this accessible by simply just moving the focus into the fake tabpanel.

    Of course the usability of a real tab control might be much better, but the risk, that you harm a11y with half baked ARIA implementation is much much higher.

    My main point is this: Implementing complex ARIA patterns without the right behavior is more harmful than doing something simple. (By simple I mean, most complex UI can be broken down to a button or mutiple buttons and little bit of focus management.)

    And complex ARIA should be only implemented if the developer is willing to test this in at least two screenreaders on two different OS.

    1. Ian McBurnie Post author

      Thank you, Alexander. I totally agree with your point. I tried my best to allude to the equal (or more so) importance of behaviour but didn’t want to stray too far off my main topic (using CSS attribute selectors to enforce accessible markup). It’s a tricky balance. I tried also, in the case of the ‘faux tabs’, to allude to the fact that complex widgets can be broken down to simpler rudiments – a list of page anchors in this case.

      The assumption I make in the article, and yes it’s a big one, is that developers will not leave an ARIA widget in a half-baked state. How they achieve this is beyond the scope of the article, I feel (maybe worthy of a follow up post?). As you correctly point out though, usually the best way is to build complex ARIA widgets in a progressively enhanced manner, built up from rudiments. So in many cases these ARIA attributes will actually be added on the client-side, not in the server-side markup.

      Thank you again for highlighting this point. I hope people reading the article will also read your valuable comment so that they fully understand the harmful consequences of having a description without the matching behaviour.

      Fully agree with your last point too. No developer should try and tackle complex ARIA widgets unless they have access to at least two screen readers on two different OS, and are willing to use them!

      1. alexander farkas

        > maybe worthy of a follow up post?

        Would love to read it. Nice work.

  27. Pingback: How Our CSS Framework Helps Enforce Accessibility | Dinesh Ram Kali.

  28. Pingback: How Our CSS Framework Helps Enforce Accessibility - Turnkey Shop

  29. Pingback: How Our CSS Framework Helps Enforce Accessibility

  30. Pingback: How Our CSS Framework Helps Enforce Accessibility - Daniele Milana

  31. Pingback: How Our CSS Framework Helps Enforce Accessibility | My Blog

  32. Pingback: 12-11-2015 - Links - Magnus Udbjørg

  33. Pingback: Revision 242: Nützliche Services und a11y im täglichen Job | Working Draft

  34. Pingback: My readings in 2015 week 47 | My path to become awesome dev

  35. Ivan Nikolić

    Great article! I’m always amazed when some developers try to reinvent the wheel with spans and divs functionality and the only reason for that is antiquated reason “you can’t style button element easily”. That might be the case 5 years ago, but right now it doesn’t really matter since browser CSS support is really good in terms o button styling.

    One thing from article that I don’t fully agree is on using classes for styling different states of element, especially ARIA states. HTML properties are all well and good, especially `disabled` which is descriptive enough and probably shouldn’t have it’s dedicated HTML class, but ARIA attributes can pretty easily get “ugly” so using some abstraction is always nice. For example, instead of referencing two ARIA attributes for tabpanel hidden state, you could just use one HTML class `is-hidden` on element with class `.tabpanel` whenever it’s `aria-hidden` attribute changes. It’s a win-win move—you get the accessibility gains, but also you get a nicer API for styling (and probably JS functionality, but that should be delegated to callbacks on actions).

    My 2 cents 🙂

    1. Ian McBurnie Post author

      Hi Ivan.

      I guess we’ll have to politely disagree on that point 🙂

      Personally I embrace the so-called ugliness of ARIA in my CSS (only when ARIA is a viable choice, of course), it means there is no ambiguity in the HTML (e.g. does ‘is-hidden’ on one widget mean the same as it does on another?), no maintenance of global classes, and that JavaScript only needs to maintain one state on the DOM element, rather than two.

      Of course do whatever works best for you and your team if you prefer abstractions/ergonomics in your CSS code!

      One thing I would say however is that some abstractions might actually be detrimental (and this point is up for debate too); yes using ARIA can get some CSS devs on the team out of their comfort zone to begin with because it might seem ugly or weird to them, but ultimately it causes them to sit up and learn about accessibility, something which ‘is-hidden’ never does because it’s an abstraction. Although I guess this all becomes a moot point as far as aria-hidden is concerned because we will soon (if not already) begin moving to the HTML5 hidden attribute.

      Anyway, I do appreciate your comments and thoughtful feedback and it’s nice to get a different point of view. Thanks again!

  36. Pingback: How Our CSS Framework Helps Enforce Accessibility | eBay Tech Blog | @tapps' bookmarks

  37. Pingback: Дайджест продуктового дизайна, ноябрь 2015 | Юрий Ветров об интерфейсах

  38. Pingback: Link Round Up #5 » Blog » Snow Tips

  39. Pingback: Do CSS Frameworks Offer Greater Accessibility?

  40. Gal Amherst

    You are so right! We still have a long way to go to break the technological wall. Fortunately the web accessibility world has made huge strides in improving our access.

    My sincere thanks to all those bettering our worlds accessible user experience!

Comments are closed.