I believe it’s value listening to something Sara Soueidan has to say. That’s very true if she’s talking at an occasion for the primary time in 4 years, which was the case when she took the stage at CSS Day 2024 in Amsterdam. What I take pleasure in most about Sara is how she not solely explains the why behind every thing she presents however affords it in a method that makes me go “a-ha!” as a substitute of “oh crap, I’m doing every thing mistaken.”
(Oh, and you must take her course on Sensible Accessibility.)
Sara’s presentation, “The Different ‘C’ in CSS”, was revealed on YouTube simply final week. It’s roughly 55 minutes of must-see factors on the assorted methods CSS can, and does, affect accessibility. I started watching the presentation casually however rapidly fired up a spot the place I may take thorough notes as soon as I discovered myself ooo-ing and ahhh-ing alongside.
So, these are the issues I took away from Sara’s presentation. Let me know in case you’ve additionally taken notes so we will evaluate! Right here we go, there’s so much to absorb.
Right here’s the video
Sure, CSS impacts accessibility
CSS modifications greater than the visible look of components, whether or not we prefer it or not. Greater than that, its results cascade all the way down to HTML and the accessibility tree (accTree). And once we’re speaking in regards to the accTree, we’re referring to an inventory of objects that describes and defines accessible details about components.
There are usually 4 predominant bits of information about an accTree object:
- Function: what sort of factor is that this? Most HTML components map to ARIA roles, however not all of them.
- Identify: identifies the factor within the person interface.
- Description: how will we additional describe the factor?
- State: what’s its present state? Announce it!
The browser supplies interactive options — like checking a checkbox that updates and exposes the factor’s data — so the person is aware of what occurs following an interplay.
Accessibility tree objects may comprise properties and relationships, equivalent to whether or not it’s a part of a bunch or labeled by one other factor.
Instance: Record semantics
CSS can have an effect on an object’s accessible function, identify, description, and even whether or not it’s uncovered within the accTree in any respect. As such, it could actually instantly affect the display screen reader announcement. We shared some time again how eradicating list-style
impacts checklist semantics, significantly within the case of Safari, and Sara explains its nuances.
/* Removes checklist function semantics in Safari */
/* Want so as to add aria-role=checklist */
ul {
list-style: none;
}
/* Doesn't take away function semantics in Safari */
nav ul {
list-style: none:
}
/* Eliminated until particularly re-added within the markup */
ul:the place([role="list"]) {
list-style: none;
}
/* Preserves checklist semantics */
ul {
list-style: "";
}
show: contents
CSS can fully take away the presence of a component from the accessibility tree. I took a screenshot from considered one of Sara’s slides but it surely’s simply so darn useful that I figured placing the information in a desk can be extra helpful:
Uncovered to a11y APIs? | Keyboard accessible? | Visually accessible (rendered)? | Kids uncovered to a11y APIs? | |
---|---|---|---|---|
show: none |
❌ | ❌ | ❌ | ❌ |
visibility: hidden |
❌ | ❌ | ❌ | ❌ |
opactity: 0 and filter: opacity(0) |
✅ | ✅ | ❌ | ✅ |
clip-path: inset(100%) |
✅ | ✅ | ❌ | ✅ |
place(off-canvas) |
✅ | ✅ | ❌ | ✅ |
.visually-hidden |
✅ | ✅ | ❌ | ✅ |
show: contents |
✅ | ✅ | ❌ | ✅ |
The show: contents
technique does greater than it’s purported to. In brief, we all know that show
controls the kind of field a component generates. A worth of none
, for instance, generates no field.
The contents
worth is form of like none
in that not field is generated. The distinction is that it has no affect on the factor’s youngsters. In different phrases, declaring contents
doesn’t take away the factor or its little one components from the accTree. Greater than that, there’s a present bug report saying that declaring contents
in Firefox breaks the anchoring impact of an ID attribute connected to a component.
Eric Bailey says that utilizing show: contents
is taken into account dangerous. If utilizing it, the advice is to set it on a generic <div>
as a substitute of a semantically significant factor. If we had been to apply it to a significant interactive factor, it will be faraway from the accTree, and its youngsters can be bumped as much as the following degree within the DOM.
Visually hiding stuff
Many, many people use some form of .visibility-hidden
class as a utility for hiding components whereas permitting screenreaders to choose them up and announce the contents. TPGi has an amazing breakdown of the method.
.visually-hidden:not(:focus):not(:lively) {
width: 1px;
top: 1px;
overflow: hidden;
clip: rect(0 0 0 0); /* for IE solely */
clip-path: inset(50%);
place: absolute;
white-space: nowrap;
}
That is tremendous near what I personally use in my work, however the two :not()
statements had been new to me and threw me for a loop. What they do is ensure that the selector solely applies when the factor is neither centered nor activated.
It’s simple to slap this class on issues we need to cover and name it a day. However we’ve got to watch out and use it deliberately when the state of affairs permits for us to cover however nonetheless announce a component. For instance, we’d not need to use this on interactive components as a result of these ought to be displayed always. In case you’re interacting with one thing, we’ve got to have the ability to see it. However for generic textual content stuff, all good. Skip to content material hyperlinks, too.
There’s an exception! We might want an animated checkbox and have to cover the native management’s look
in order that it stays hidden, despite the fact that CSS is styling it in a method that it’s seen. We nonetheless must account for the shape management’s totally different states and the way it’s introduced to assistive tech. For instance, if we cover the native checkbox for a customized one by positioning it method off the display screen, the assistive tech won’t announce it on focus or activation. Higher to completely place the checkbox over the customized one to get the interactive accessibility advantages.
Backside line: Ask your self whether or not an interactive factor will grow to be seen when it receives focus when deciding whether or not or to not use a .visually-hidden
utility.
CSS and accessible names
The browser follows a selected course of when it determines a component’s accessible identify (accName):
- First, it checks for
aria-labelledby
. If current, and if the ID within the attribute is a legitimate reference to a component on the web page, it makes use of the reference’s factor’s computed textual content because the factor’s accessible identify. - In any other case, it checks for
aria-label
. - In any other case, until the factor is marked with
function="presentation"
orfunction="none"
(i.e., the factor doesn’t settle for an accName anymore), the browser checks if the factor can get its personal identify, which may occur in a number of methods, together with:- from an HTML elemnenty, equivalent to
alt
ortitle
(which is greatest on an<iframe>
; in any other case, keep away from), - from one other factor, like
<label>
or<legend>
, or - from its contents.
- from an HTML elemnenty, equivalent to
At this level, Sara went into a quick (however fantastic) tangent on <button>
semantics. Buttons are labelable components and might get their accName through the use of an aria-label
attribute, an aria-labelledby
attribute, its contents, or perhaps a <label>
factor.
ARIA takes priority over HTML which is why we need to keep away from it solely the place we’ve got to. We will see the priorities and overrides for accessible names in DevTools underneath the Accessibility tab when inspecting components.
However observe: the order of precedence outlined within the accName computation algorithm doesn’t outline the order of precedence that you must observe when offering an accName to components. The steps ought to like be reversed if something. Prioritize native HTML!
CSS generated content material
Keep away from utilizing CSS to create significant content material. Right here’s why:
<a href="#" class="information">CSS generated content material</a>
.information::earlier than {
content material: "ⓘ" / "Data: ";
/* or */
content material: url('path-to-icon.svg') / "Data: ";
}
/* Contents: : Data: CSS generated content material. */
However it’s extra nuanced than that. For one, we’re unable to translate content material generated by CSS into totally different languages, not less than through automated instruments. One other one: that content material is gone if CSS is unavailable for no matter motive. I didn’t suppose this could ever be too massive a priority till Sara jogged my memory that some contexts fully strip out CSS, like Safari’s Reader Mode (one thing I depend on virtually day-after-day, however want I didn’t must).
There are additionally edge circumstances the place CSS generated content material may be inaccessible, together with in Pressured Colours environments (learn: colour conflicts), or if a damaged picture is handed to the url()
perform (learn: alt
textual content of the picture shouldn’t be proven rather than the damaged picture, not less than in most browsers, but it nonetheless contributes to the accName, violating SC 2.5.3 Label in Identify). Adrian Roselli’s article on the subject consists of complete check outcomes of the brand new characteristic, displaying totally different outcomes.
Inline SVG might be higher! However we will additionally do that to assist with icons that should be ornamental to not repeat redundant data. However it’s inconsistent so far as browser implementation (however Sara says Safari will get it proper).
/* like: <img src="icon.svg" alt=""> */
.icon {
content material: url('path/to/icon.svg') / "";
}
So, what can we do to assist forestall awkward and inaccessible conditions that use CSS generated content material?
- Keep away from utilizing CSS pseudo-elements for significant content material — use HTML!
- Cover ornamental and redundant CSS content material by giving it an empty
alt
textual content (when assist is there and conduct is constant).
CSS can fully strip a component of its accName…
…if the supply of the identify is hidden in a method that removes it from the accessibility tree.
For instance, an <enter>
can get its accName from a <label>
, however that label is hidden by CSS in a method that doesn’t expose it to a11y APIs. In different phrases, the <label>
is not rendered and neither are its contents, so the enter winds up with no accName.
BUT! Per spec:
By default assistive applied sciences don’t relay hidden data, however an writer can explicitly override that and embrace hidden textual content as a part of the accessible identify or accessible description through the use of
aria-labelledby
oraria-describedby
.
So, on this case, we will reuse the label even whether it is hidden by tacking on aria-labelledby
. We may use the .visually-hidden
utility, however the label remains to be accessible and can proceed to be introduced.
CSS does not have an effect on the state of a component within the accTree
If we use a <button>
to point out/cover one other factor, for instance, the <button>
factor state wants to reveal that state. Content material on hover or focus violates SC 1.4.13 which requires a option to dismiss the content material. And customers should be capable of transfer their cursor away from the textual content and have it persist.
CSS-only modals utilizing the checkbox hack are horrible as a result of they don’t lure focus, don’t make the web page content material inert, and don’t handle keyboard focus (with out JavaScript).
Popovers created with the Popover API are at all times non-modal. If you wish to create a modal popover, a <dialog>
is the fitting option to go. I’m enamored with Jhey Tompkins’s demo utilizing the popover
for a flyout navigation part, a lot in order that I used it in one other article. However, utilizing popover for modal-type stuff — together with for one thing like a flyout nav — we nonetheless must replace the accessible states.
There’s rather more to contemplate, from focus traps to inert content material. However we will additionally take into account eradicating the popover’s ::backdrop
for fewer restrictions, like making background content material inert or trapping focus. Then once more, one thing like a popover
-based flyout navigation violates SC 2.4.12 Focus Not Obscured if it covers or obscures one other factor with focus. So, sure, visibility is necessary for usability however we should always shoot for higher usability that goes past WCAG conformance. (Sara elaborates on this in a remark down beneath.)
So… shut the popover
when focus leaves it. Sara talked about an article that Amit Sheen wrote for Smashing Journal the place it’d be smart to pay shut consideration to how a change is communicated to the person when a <choose>
menu <possibility>
is chosen to replace colours on the web page. That poses points about SC 3.2.2 the place one thing modifications on enter. When the person interacts with it, the person ought to know what’s going to occur.
Last ideas
Yeah, let all that sink in. It feels good, proper? Once more, what I like most about Sara’s presentation (or any of them, for that matter) is that she isn’t pointing any condemning fingers at anybody. I care about oodles accessible experiences however know simply how a lot I don’t know, and it’s sensible stuff like this the place I see clear connections to my work that may make me higher.
I took another observe from Sara’s discuss and didn’t fairly know the place to place it, however I believe the conclusion is smart as a result of it’s a stable reminder that HTML, CSS, and, sure JavaScript, all have seats on the desk and might every contribute positively to accessible expertise:
- Hacking round JavaScript with CSS can introduce accessible obstacles. JavasScript remains to be helpful and required for this stuff. Use the fitting software for the job.
The “Different” C in CSS initially revealed on CSS-Methods, which is a part of the DigitalOcean household. It is best to get the e-newsletter.