Stacey
Posted on March 22, 2022
This year’s axe-con featured two talks about new and upcoming CSS changes and their potential impacts on accessibility, Rachel Andrew‘s “New CSS with accessibility in mind” and Stephanie Eckles’ "Modern CSS Upgrades To Improve Accessibility.” Both were great and absolutely worth the watch (registering with the con for free gets you access to previous sessions). Here are a few of the key takeaways I noted from the talks.
display: contents
The contents
value was discussed by Rachel Andrew in “New CSS with accessibility in mind.” Supported by modern browsers, display: contents
drops the wrapping “box” from elements to allow the children to inherit the flex behavior of their grandparent.
Take the following example:
<div class="container" style="display: flex">
<div class="nested-div">A direct child div</div>
<ul style="display: contents">
<li>One List Item</li>
<li>A Second List Item</li>
</ul>
</div>
Here we have a div with a class “container” that has two directly nested elements: another div, and an unordered list. If we give the container
a display: flex
and the unordered list the display: contents
property and value, the list items contained therein will appear inline with the nested div as if they were immediate children of the container
div.
Here’s a Codepen example if you’d like to play with it yourself.
Note that this specifically applies to the display
of the children and not necessarily other properties. If I were to include a style like .container > * { margin-left: 5rem }
the immediate child div would have a margin-left of 5rem
, but the more deeply nested li
elements would not.
From an accessibility perspective, from Andrew’s talk, I learned this was originally implemented incorrectly by browsers where the element was set to display: none
and children were “put back” on the page—but they were all effectively hidden from screen readers. As of 2020, According to a blog post by Adrian Roselli, this was fixed in Chromium browsers, while Firefox and Safari still had issues when this was applied to tables. The lesson here being that whenever a fun new contents
value is released, check how it is interpreted by assistive technologies to make sure the browser isn’t stripping the element’s role or removing it completely.
color-contrast()
The new bit of CSS I was most excited about from the talk was the one with the least amount of support. The functional notation color-contrast()
is currently only implemented in Safari Technology Preview but has awesome potential! It compares one color with a list of other potential colors and picks the one match with the highest contrast. MDN Web Docs give the following example:
color: color-contrast(wheat vs tan, sienna, #d2691e)
Here, the color wheat
is compared against a list containing two named colors and a hex value— tan
, sienna
and #d2691e
—where it will ultimately return sienna
as the color
on the element.
This will be especially helpful when combined with CSS custom properties and the new prefers-color-scheme
media query, also discussed in the talk. prefers-color-scheme
detects the user’s OS preference for a light or dark theme, allowing you to customize your website to accommodate those preferences while still using brand colors. This means you could potentially do something like this in the near future:
:root {
--background-color: #eeb4b3;
}
@media (prefers-color-scheme: dark) {
:root {
--background-color: #2f242c;
}
}
body {
background-color: var(--background-color);
color: color-contrast(var(--background-color) vs #c179b9, #a42cd6, #502274);
}
To test this, you will need to make sure you have Experimental Features → CSS color-contrast() enabled in your Safari Technology Preview.
prefers-color-scheme and prefers-contrast vs forced-colors
Touched on above, prefers-color-scheme
is a newer media query supported by most modern browsers that checks for the user’s OS preference for dark or light theme, and allows us to adjust styles based on the users preference. However, as Andrew noted in her talk, just because a user prefers a dark color scheme on their OS does not mean your dark color scheme will be the most accessible combination for the user, so it is important to give users an option to toggle between your website’s light and dark themes.
By... contrast, prefers-contrast
checks for the user’s color contrast settings at the OS level. This experimental media feature introduced in Stephanie Eckles’ talk, Modern CSS Upgrades to Improve Accessibility, accepts the values less
, more
, or no-preference
(not set in OS). In her talk, Eckles also cited custom
, meaning the user set preferences in the OS, though that is not currently listed on MDN Web Docs. These primarily help to serve users with light sensitivity where less
will decrease the contrast and more
will increase the contrast to help users better distinguish details.
Interestingly, Eckles said that these queries can be chained (once support is more universal, of course). In this case, a user can define a style for someone with a dark color scheme who prefers high contrast like so:
@media (prefers-color-scheme: dark) and (prefers-contrast: more) {
.container {
background-color: "darkslategray";
color: "white"
}
}
On the same token, there is another new media query, forced-colors
which is meant to specifically check for Windows’ users High Contrast setting. It has two potential values: none
or active
, where active
indicates that forced colors mode is active on the user's machine.
Helpfully, Eckles explained the primary difference betweenprefers-contrast
and force-colors
: prefers-contrast
presumes that the user still wants to see your design and colors, where force-colors
requires you to use the user’s set color palette.
spacing with min()
and clamp()
Moving back from the experimental to something more applicable in code today, Eckles gave some great tips for harnessing more modern CSS methods for responsive spacing.
clamp()
, from Eckles’ example, is a great way to control the padding and keep it proportionate at different breakpoints/zoom levels. The example she uses is this:
padding: clamp(1rem, 5%, 1.5rem)
In this example, the padding value will be no smaller than 1rem
, no larger than 1.5rem
, and maintain 5%
as an “ideal.” This saves us the trouble of having to define “pixel-perfect” padding tweaks at every breakpoint to ensure the boxes still look as expected in browser resize.
Similarly, for spacing between boxes, such as a series of <section>
elements, she gives the following example:
section + section {
margin-top: min(128px, 15vh)
}
Full disclosure: math functions like min()
generally make my brain hurt. My rudimentary understanding is that the browser will interpret the lowest of the comma-separated expressions to use when applicable. web.dev has a great demo of how this can work on Codepen. The tricky bit is that despite most examples using 2, min()
can actually take any number of arguments, though it gets much harder to parse what is happening with more arguments added.
For accessibility specifically, the main takeaway here is that as users adjust their zoom or browser window size to accommodate their needs, the CSS will preserve the desired ratio between elements. If we were to instead define margin between sections with a set pixel measurement, the space between elements would appear larger and larger as users zoom, perhaps even pushing elements out of the viewport and thus making users unaware that more content even exists.
Take more away
While these were the new tricks that arguably blew my mind the most, these are absolutely not the end all be all of either talk. I highly recommend catching the recordings if you can. As of writing, you can still register for free even though the live event has passed, and view these sessions (as well as some great sessions from 2021!)
this post was cross-posted from my site and edited to fix typos
Posted on March 22, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
August 16, 2024
August 4, 2024