More accessible markup with display: contents

in code

CSS Grid Layout lets you turn an element into a grid, and place the element’s direct children onto it. Given that, it might be tempting to use flatter markup, but less meaning is usually less accessibility. With display: contents, we can place grand children on a grid, which lets us have accessible markup and beautiful layout. Let’s dive into the details!

Below, I will explain in more detail what I mean by children and grand children, and then show how we can use display: contents to improve this. Note: this is currently broken in supporting browsers, more details below

Grid works on direct children

In Grid Layout, when a grid is defined on a given element, only direct children of that element become grid items and are layed out on it. To refresh for those not familiar with the syntax, let’s look at an example and write a recipe. With this HTML:

Example layout 1
<div class="container">
  <h1 class="item">Penne with tomato sauce</h1>
  <p class="item">This simple recipe has few ingredients but tastes delicious.</p>
  <div class="item ingredients">
    <h2>You'll need</h2>
    <ul>
      <li>canned tomatoes</li>
      <li>onions</li>
      <li>garlic</li>
    </ul>
  </div>
</div>

we can have this CSS:

.container { 
  display: grid; /* element is now a grid container */
  grid-template-columns: repeat( 4, 1fr );  /* grid now has 4 columns */

.item:nth-child(1) {
  grid-columns: 1 / 2; /* Place item between grid line 1 and 2 */
}

.item:nth-child(2) {
  grid-columns: 2 / 4; /* Place item between grid line 2 and 4 */
}

.item:nth-child(3) {
  grid-columns: 4 / 5; /* Place item between line 4 and 5 */
}

I’ve used .container and .item as classnames, because that’s core to Grid Layout: there’s grid containers and grid items. Obviously, use any naming convention your projects require.

The reason we can position these items on the grid, is that they are direct children of the grid container. But look at what happens if we’d like to add a list of sponsors, like this:

Example layout 2

We could add the list to our markup:

<div class="container">
  <h1 class="item">Penne with tomato sauce</h1>
  <p class="item">This simple recipe has few ingredients but tastes delicious.</p>
  <div class="item ingredients">
    <h2>You'll need</h2>
    <ul>
      <li>canned tomatoes</li>
      <li>onions</li>
      <li>garlic</li>
    </ul>
  </div>
  <ul class="item sponsors">
    <li>Supermarket 1</li>
    <li>Supermarket 2</li>
  </ul>
</div>

But we won’t be able to position each sponsor onto the grid. This is because only the <ul> is a direct child of the container element and therefore a grid item. The <li>s are not: because they are not direct children of our grid container, they don’t get to participate in its grid game. But what if we really want to align the sponsors onto the grid?

Flatter markup

One obvious method of making the sponsors participate is to remove the <ul> and use a <div> for each sponsor. But what we would then do, it ‘flatten’ our markup. That’s throwing away the baby with the bathwater.

The benefit of using the <ul> (unordered list) element are plenty:

If we would make our markup flatter, we lose those benefits.

display: contents to the rescue

With display: contents, we can have our markup and our grid placement. This property makes the element so that it no longer seems to exist. It does not generate a box, so backgrounds, borders and other box-related properties will no longer work on it. Grid placement properties will also no longer work. But all of these things will work for the element’s children. The spec says the element behaves ‘as if it had been replaced […] by its contents’. If that sounds weird, I can recommend Ire Aderinokun’s detailed explainer.

Without display contents on ul it is a grid item, with display contents its children are grid items

Effectively, for our purposes here, using display: contents on an element does this: the element stops participating in the grid, and its contents start participating in it. It lets us specify our sponsors onto the grid, instead of the list they are contained in.

There’s some interesting edge cases listed in the spec, for if the property is used on elements like img and video.

Accessibility concerns with current browser implementations of display: contents

For people who use assistive technologies (AT), browsers expose accessibility properties, including the role of elements on the page. This is so that their AT knows what’s what on the page. Many elements come with a built-in role, for example lists have a role of list.

This is where it goes wrong in current browsers that support display: contents. They do not interpret display: contents as a lay-out thing only, they also derive meaning from it. This is problematic and a bug according to the spec’s comment on display affecting layout:

The display property has no effect on an element’s semantics: these are defined by the document language and are not affected by CSS. Aside from the none value, which also affects the aural/speech output and interactivity of an element and its descendants, the display property only affects visual layout: its purpose is to allow designers freedom to change the layout behavior of an element without affecting the underlying document semantics.

(emphasis mine)

Looking at our sponsor list example, it means that the item is no longer seen as a list, but as something else (test case in CodePen).

I’ve added my test results per browser below. In each of them, our <ul> gets the correct role without display: contents, but once the property is set, it loses its role.

Firefox 61

The list gets a role of text leaf (Firefox bug). Update: this is now fixed; it will ship in Firefox 62 in August 2018

Chrome 66

The list shows as ‘accessibility node not exposed, element not rendered’ (Chromium bug).

Safari

The list shows as ‘no accessibility information’ (Safari bug, Webkit bug)

The <ul> is just an example. it happens with any element that gets display: contents and had a role before.

If you feel strongly about being able to display: contents accessibly, please consider commenting on those bugs with use cases, +1s, et cetera. I hope for browsers to prioritise this.

Related to this issue is that display properties in CSS have impact on table semantics, as Adrian Roselli explains; see also Steve Faulkner’s explanation of where the responsibilities lie.

Conclusion

With display: contents, you can place grand children of a grid container on the grid. This allows for more semantic mark-up, which is great for accessibility. The more meaningful your mark-up, the more detail an assistive technology can provide to its users. However, there is one caveat: none of the browsers that currently support display: contents expose elements that have the property to the accessibility tree with their original role.

I believe the accessible roles should not disappear when setting display: contents, as that defeats a lot of the purpose of display: contents. I have filed bugs with Firefox, Chromium and Safari for this. I really hope we will be able to use display: contents while keeping the accessible roles of elements intact, so that we can have great layouts and great accessibility. To be continued, I hope!

Comments & mentions (80)

Job reposted this
Nivi Morales likes this
Job likes this
Jens Grochtdreis likes this
Deborah Edwards-Onoro replied: More accessible markup with display: contents hiddedevries.nl/en/blog/2018-0… #a11y #accessibility #CSS
UX Academy NL replied: Mooi overzichtje!
Steve Buell likes this
Šime Vidas replied: Could you link to the bugs in the article? Other people may want to chime in or check the response from browser vendors.
Hidde replied: the bugs are in the article (near the bottom)
Front-End Front replied: More accessible markup with display: contents hiddedevries.nl/en/blog/2018-0…
Fresh Frontend Links replied: More accessible markup with display: contents hiddedevries.nl/en/blog/2018-0…
UI Cortés replied: More accessible markup with display: contents
hiddedevries.nl/en/blog/2018-0…
Saurabh Shah replied: More #accessible markup with display: contents - hiddedevries.nl/en/blog/2018-0… #web #development #frontend #css
Jacky replied: More accessible markup with display: contents hiddedevries.nl/en/blog/2018-0…
Frontend United replied: CSS Layout is evolving rapidly - just read "More accessible markup with display: contents" by @hdv (buff.ly/2JkmZRB). If you want to learn more about the subject, there are still some tickets available for Hidde's #FrontendUnited #workshop buff.ly/2HtT88h
Frontend United replied: CSS Layout is evolving rapidly - just read "More accessible markup with display: contents" by @hdv (buff.ly/2JkmZRB). If you want to learn more about the subject, there are still some tickets available for Hidde's #FrontendUnited #workshop buff.ly/2HtT88h
Ana Hristian replied: #Webdesign #HTML #CSS #javascript
hiddedevries.nl/en/blog/2018-0…
HJ Chen replied: this is a superb use case for how display: contents and display: grid can work together
HJ Chen likes this
고경희(Kyunghee Ko) replied: More Accessible Markup with display hiddedevries.nl/en/blog/2018-0…
Adrian Roselli replied: Sweet! Thanks! Gonna read this when I am not fighting with the stove.
Marco Zehe replied: Ah, thanks! :)
Hidde replied: tl;dr: for me, _the_ use case for display:contents is increased accessibility, which now works nowhere, because of these bugs.
Fabrizio Calderan reposted this
Iain van der Wiel likes this
Fabrizio Calderan likes this
Mathis Wiehl likes this
SelenIT likes this
Stefan Judis reposted this
Félix Zapata replied: More accessible markup with display: contents hiddedevries.nl/en/blog/2018-0…
Jonathan Torke replied: More accessible markup with display: contents hiddedevries.nl/en/blog/2018-0… #CSS
Web 2 Robot replied: More accessible markup with display: contents hiddedevries.nl/en/blog/2018-0… #CSS
Richnou replied: More accessible markup with display: contents #css hiddedevries.nl/en/blog/2018-0…
Trevor Pierce replied: hiddedevries.nl/en/blog/2018-0… #a11y #CSSGrid
CSS-Tricks replied: `display: contents;`

Can make for more accessible markup: hiddedevries.nl/en/blog/2018-0…

But don't use it as a reset: adrianroselli.com/2018/05/displa…

Is kinda of an answer for non-flattened markup for grids: css-tricks.com/will-flattenin…
jemoraz replied: More accessible markup with display: contents hiddedevries.nl/en/blog/2018-0…, see more tweetedtimes.com/jemoraz?s=tnp
Armando Rivera replied: More accessible markup with display: contents hiddedevries.nl/en/blog/2018-0…
Sonia Cabral replied: Top story: More accessible markup with display: contents hiddedevries.nl/en/blog/2018-0…, see more tweetedtimes.com/justcreative/n…
Kathouz.Net Studio replied: Shared Top sStory: More accessible markup with display: contents hiddedevries.nl/en/blog/2018-0…, see more tweetedtimes.com/justcreative/n…
Carsten Warga replied: More accessible markup with display: contents hiddedevries.nl/en/blog/2018-0…
Simon Lidster replied: More accessible markup with display: contents hiddedevries.nl/en/blog/2018-0…
GravityDrive replied: More accessible markup with display: contents
hiddedevries.nl/en/blog/2018-0…
HsiangHui replied: More accessible markup with display: contents #markup #accessible #css hiddedevries.nl/en/blog/2018-0…
A11YChi Meetup replied: More accessible markup with display: contents

hiddedevries.nl/en/blog/2018-0…

#a11y #accessibility #webdev
Anneke Sinnema reposted this
Anneke Sinnema replied: Shout out to @hdv who not only documented the bugs on display: contents but actually *filed* them to help us all gain access to an awesome feature that *will* work for everyone adrianroselli.com/2018/05/displa…
Bramus! @ CSS Day reposted this
Bram Smulders likes this
julie vanopdenbosch @ cssday likes this
Marc Stalfoort replied: @hdv you'll kick ass, good luck dude and enjoy
replied: Up next: Hidde over Great Graphic Design! Hup @hdv ! #CSSday
Wilfred Nas replied: Waiting for @hdv at #cssday
HJ Chen @ CSS Day replied: Yay @hdv talking abt doing great graphic design on the web. Also some @mozilla representation ❤
#cssday
Greg Whitworth replied: Cool to hear that @hdv was inspired by @fantasai flex spec workshop that he ran similiar ones around the Netherlands. #cssday
Jenny Shen @ #cssday replied: Hidde @hdv talking about great graphic design and Jan Tschichold. I learned about Jan's design principles in my first year university studies!
Fronteers replied: Nu op het #CSSDay podium: @hdv met ‘The web is ready for great graphic design’. Hidde was jarenlang vrijwilliger voor Fronteers en draagt nog steeds veel bij aan de vereniging als lid en workshopgever.
Snook replied: ⁦⁦@hdv⁩ talking about great graphic design
Ruben Bos replied: Yes! It’s @hdv about Great Graphic Design (and names?!) on the Web. #CSSday
Jenny Shen @ #cssday replied: #CSSDay @hdv takes us way back in history of graphic design! Did you know this is the original @KLM logo?
Eric Meyer replied: Related to an example in @hdv’s #cssday talk: @jensimmons recreated Tschichold’s “Die Neue Typographie” poster using HTML+CSS: labs.jensimmons.com/2017/01-007.ht…
Peter van Grieken replied: Seriously, how great is @hdv’s talk?!
tink likes this
tink replied: Good to know. Thanks Hidde.
Hidde replied: thanks for the sound advice, as usual! It will be while before we can actually use it
Amelia Bellamy-Royds likes this
Jen Simmons replied: Don't use `display: contents` on a real project yet. It removes the content from the accessibility tree.

Can I Use now reflects this: caniuse.com/#feat=css-disp…, so we can track when the bug fix lands in browsers. It'll be in Firefox 62 Sept 5.

(More info: hiddedevries.nl/en/blog/2018-0…)
{this.props.N A V E E N replied: #CSSGrid Layout lets you turn an element into a grid, and place the element’s direct children onto it. With display: contents, we can place grand children on a grid, which lets us have accessible markup & beautiful layout. Let’s dive into the details! hiddedevries.nl/en/blog/2018-0…
Georg Portenkirchner replied: #CSS Grid Layout lets you turn an element into a grid, and place the element’s direct children onto it. With display: contents, we can place grand children on a grid, which lets us have accessible markup and beautiful layout. #accessibility hiddedevries.nl/en/blog/2018-0…
Unknown replied:
Rachel Andrew replied: More accessible markup with display: contents #WebU18 hiddedevries.nl/en/blog/2018-0…
Hector Osborne Rodriguez replied: More accessible markup with display: contents hiddedevries.nl/en/blog/2018-0…
Hidde de Vries replied:

The year is about to end, so it is time for another year in review post! I love reading what others write about their years, hopefully mine is interesting to some people.

Like last year, I’ve divided stuff into highlights and things I learned. To be clear, that doesn’t mean I had a year consisting of 100% highlights and learnings, there is also stuff that went wrong, wasn’t amazing or was personal, I just think they’re for elsewhere (in person over drinks).

Highlights

Projects

In 2018, I spent most of my time in Mozilla’s Open Innovation team, working specifically on the IAM project. For those unfamiliar with it, IAM is short for identity and access management, it is about how people proof who they are and get access to stuff with as little friction as possible. It’s been super exciting to build most of the front-end for a project codenamed “DinoPark”.

In the last quarter, I’ve also spent a day a week working at the City of The Hague, specifically helping with improving accessibility and profesionalising front-end development of their digital services. It’s been great to see improvements shipped both in the application’s code as well as the content management system product.

Other short engagements included:

  • teaming up with Jeroen and Peter, I helped NOS, the Dutch broadcaster, with an accessibility audit, user tests with visually impaired users and an in-house presentation on technical accessibility
  • I ran a one day workshop on accessibility guidelines at Zilveren Kruis
  • with Peter, I worked on JavaScript to power a chat-like interface for the Dutch government

Volunteering

I did not do a lot of volunteering this year, but I did translate the Inclusive Design Principles into Dutch and worked on improving MDN documentation on accessibility.

Conferences and events

This year, I attended these events:

I spoke multiple times, too:

I did my CSS Layout workshop three more times (for Fronteers and at Front-end United) and ran a new accessible components workshop (for Frozen Rockets).

Organisers, thanks so much for having me. The first time conference speaking was stressful, time-consuming and very scary, but also satisfying. I got great feedback, both praise and things I can improve on (thanks, you know who you are).

I’d love to speak more in 2019, please do get in touch if you want to have me present at your event or give a workshop.

Writing

I published 26 posts on this blog, not including this one. Like I said in last year’s review: I very much recommend writing, it can be helpful in many ways. It is also great to be able to do this on a domain you own, on pages you designed. If anyone needs mentoring around this, get in touch, I would love to help!

Some of the most read posts:

Reading

It felt a bit weird to have the Goodreads app keep me in check reading-wise, but it did the job. I managed to read more than the goal I set. Some that readers of this blog might find interesting:

Book covers of brotopia, klont, common sense and killing commendatore
  • Brotopia, about the ‘bros’ that founded some of the biggest Sillicon Valley corporations and the culture they created. I must admit some doubts towards the word ‘bro’ , but wow, the book taught me a lot about how I don’t want to be and where I don’t want to work.
  • Klont – if you read Dutch, get it! This novel brilliantly captures the phenomenon ‘datafication’ and how it endangers some of the basic concepts of free societies, as well as, unrelated, the phenomenon of ‘experts’ traveling the world to give talks
  • Common sense, the Turing test and the quest for real AI – sometimes fairly technical and academic, but I loved the hype-free thinking about artifical intelligence and what to expect from it
  • Killing Commendatore – if you’re into Murakami or want to start reading his work, this is great. It is a lot of pages, in two parts, but worthwile. I read the Dutch translation, it is available in many other languages, too.

For all the ‘big data’ and AI expertise that Amazon, which owns Goodreads, has, the app is still very bad at recommending new books. For me, it doesn’t go beyond what the most generic airport bookshops stock. The real human beings I have befriended there brought much more reading inspiration.

Things I learned

Some random things I learned:

  • I finally got my hands dirty in declarative client-side component frameworks. My framework of choice was Vue.JS. I learned concepts like routers, props down / events up, reactivity and lifecycle hooks, enjoyed working in this paradigm, but even within that, I mostly wrote just JavaScript, good markup and sensible CSS. I have a blog post upcoming on this.
  • I learned in multiple projects this year how hard it can be to explain the concept of focus. It exists as a thing in the browser (the document.activeElement), but also as a thing in people’s thinking, not necessarily the same way. And then I’m not even talking about indicating focus yet. In my talk in Groningen I spent a number of slides trying to get it crystal clear. I like Laura Carvajals “You wouldn’t steal their cursor” and tried a streetlights metaphor (they are not pretty, but if they’re not there, you can’t see where you’re going at night)
  • I worked with WCAG 2.1 in real projects (testing for the newly added success criteria and talking about them in slides)
  • I added CSPs to some sites (see also How I learned to stop worrying and love CSPs)
  • I did more background reading to better understand the world we’re developing front-ends for (super meta), inspired by various colleagues, conference speakers and friends

What I want to get better at next year:

  • writing and presenting
  • I want to try and build something with Rust
  • get more people excited about having a personal website with a blog

With that, I wish all readers a fantastic 2019! If anyone has written year in review posts, I’d love to hear about them in the comments/webmentions, and read what you have done.

Sara Soueidan replied: Ah I know those, but I thought something else does like display block or so. I don’t know why the tweet made me assume that.
Roger Johansson replied: Display:flex, display:block (I think), list-style:none.
Ian Devlin likes this
Kathleen McMahon likes this
Hidde replied: I was checking curiously checking this thread for the same reason, but looks like mostly display and list-style
Sara Soueidan replied: Yup, I got that too
PritiRohra likes this
Ilya Streltsyn likes this
Leave a comment
Posted a response to this?

This website uses Webmentions. You can manually notify me if you have posted a response, by entering the URL below.