Sessions is temporarily moving to YouTube, check out all our new videos here.

Designed for Inclusion: Writing CSS with Accessibility in Mind

Manuel Matuzović speaking at React Vienna in September, 2017
Great talks, fired to your inbox đź‘Ś
No junk, no spam, just great talks. Unsubscribe any time.

About this talk

Let's look at some properties in CSS that we can use to improve the accessibility of our web projects, like font size, text-align, word spacing and so on.


Thank you for a great introduction. You heard the bad news, this talk isn't about React it isn't even about JavaScript it's just about CSS. But I hope that you will like it anyways. My name is Manuel Matuzovic. I'm a front-end developer and I love my job. I love the fact that I get to create something that people will use. I also hope that they will enjoy it while they're using it. I love the challenges and I also love the creativity the job demands. About 17 years ago I made my very first website. Some friends and I played an online game and we had a so-called clan and I made the website for this clan. The name is in French and it translates to "Eat Your Poo." You can tell that we were some badass 13 year olds playing that game but the website we had was pretty great and it had everything you need. Some cool looking buttons, a guest book. I informed users that it was optimised for 1024 x 768 resolution and, of course, it also had marquee text and some JavaScript stuff going on. So, pretty great for the 2000s. A few years later I made another website, my personal website, there is a lot of embarrassing stuff going on. I even removed some stuff because it's so bad. For example, my favourite movie "The Shinning," whatever that is. But what's important about this slide is that the site doesn't use any CSS at all. For a layout, of course, I created framesets with some columns and I embedded three HTML files. One for a navigation, one for the main content, and another one for the side bar because I needed a pick of the week and a place where I can display it. The main content was, of course, a table. And there's, again, no CSS involved. Just HTML attributes like align, background colour, border colour and I set the width to 442 because 100% is just not enough for me. Okay, now let's look at the overall layout. Still no CSS, just some HTML attributes. Link, background colour, alink and vlink for active and visited links. And, of course, the good old font tag for font styling. Size for the font size and face for the font family and another table of course, no CSS. I didn't use CSS because it didn't exist. It was there already for some years but I just didn't know about CSS and I didn't need it. A few years later when I was in University I finally learned all the great stuff CSS had like floating position, background properties, line height, and so on. And then, a few years later, I was introduced to the big game changer, to CSS3. All of a sudden we had box-shadow, border-radius, web fonts, of course, gradients, animation, transitions, and all that awesome stuff and the way the web looked changed significantly and it keeps changing because browsers are constantly shipping new features at a very high pace. We have stuff like filters, shapes, Flexbox and grid, of course, feature queries, custom properties, a lot of amazing tools and properties to create amazing experiences. But you know what Spiderman's uncle said? "With great power comes great responsibility." And at the same time we also have now many tools to create bad experiences. And that's exactly what I want to talk about tonight. I'm going to show you some properties in CSS that you can use to improve the accessibility of your web projects and some properties that you can misuse to change the experience for the worse. And I want to start with font-size. The standard font size in paragraphs was in the last few years, somewhere between 15 and 18 pixels for normal text. That has changed in recent years, font size keeps increasing. You can see that on Medium, for example, of CSS-Tricks. They have a minimum size of 20 pixels for their paragraphs and that's a great thing because 16 pixels is definitely not enough. Of course, it depends on the typeface but you should usually start somewhere between 18 to 20 pixels on a smartphone and increase the font size with the size of the screen. Because usually the bigger the screen, the bigger the distance between the screen and the user. So, for the usage on the smart TV, for example, you would want to have a really big font size so the text can be read from where the people are sitting, on a couch, for example. Next, line-height, the default line-height is roughly at 1.2 for paragraphs and Web Accessibility Initiative recommends something at about 1.5 for the line-height in paragraphs because if the line-height is higher, the text is easier to read and easier to scan. Now, of course, this also depends on the type face and the font-size but 1.5 is a good starting point and you can adjust from there. It's better for accessibility and if you compare the first one and the second one, the second one looks much nicer. Next thing, text-align. By default, text is aligned to the left or to the right depending on the writing mode or the direction. A thing that designers like to do is to justify text because it looks cleaner if you have same length lines. The problem here is what the browser does is it increases word spacing and word spacing is bad for accessibility because if word space... irregular word spacing is bad for accessibility because it's harder to read if the spaces between words aren't consistent. So please don't justify text even if you think that it looks better. It's harder to read for some people. Next thing, paragraph width. Here we have a paragraph, looks pretty nice. Great font size, line height but something is odd. And what's odd about this paragraph is that it's just too narrow. There's only a maximum of five or six words that fit per line and that's just not enough. It's not easy to read. On the other hand, if you have too many words in one line it's also hard to read so what you want to achieve is a count of 45 to 75 characters per line in a paragraph. That makes text easy to read. And, again, it looks nicer. You can control that with CSS, you can use the character unit for that. So you can set a maximum width of, for example, 65 characters per line and that way you can make sure that only a maximum of 65 characters will be in one line no matter the font size or the font family so that's pretty nice. Next thing, pseudo-elements. In CSS we have several pseudo-classes and pseudo-elements. Some of the more popular ones are before and after. They give us the ability to add content at the very beginning in an HTML element or at the very end. Now, following the separation of concerns there's one thing you definitely should not do. You should not add text content via CSS. Text belongs in an HTML file, in a database, or a JavaScript file in this context or coming from an API. But it shouldn't be in CSS, no text in CSS. That's a bad thing. But what's a good thing we can use is that we can use pseudo-elements to add icons, or glyphs or anything you like. Something that's presentational. What's important here is that we know that some screen readers in some browsers will read what's written in there. So if the thing you were injecting into the HTML document is fully presentational and only there for design reasons, make sure to hide it from screen readers. Here's an example, I have a simple unordered list. I removed the list items and I added spans to the list items and I added this cross, whatever it is, with CSS. And this is how it sounds like if you use JAWS in Chrome. - [Screen Reader] List of four items. Times item one, Times item two, Times item three, Times item four. - I don't know if you have heard it but it said, "Times item one, Times item two" and so on. As it turns out, this cross is not a cross but it's the icon for times, like in "three times four." And that can get very confusing for screen reader users because it sounds like all the items are being multiplied. Which is not the case. So what you want to do in such cases, you want to hide it from screen readers and you can do that by setting the aria-hidden attribute to true. It's still visually visible but it's hidden for assistive technology. And as a side note, in that specific example I showed you, it's better to use the good old list style type or list style image because screen readers will treat lists differently if the list-style is set to "none." So don't try to fake list items, use the native properties. The next thing I want to talk about is colour and colour contrast. Before I do it, let's get on the same page and find out why colour contrast is important. There are about 285 million people who are visually impaired. That's about roughly 4% of the population. 39 million are blind and 246 million have low vision. 7 to 12% of all men and less than 1% of women have some form of color-vision deficiency. Usually it's hard for them to differentiate colours like red and green, for example. Another reason why colour contrast is important is that people like to dim their screens to save battery, for example. And people use their smartphones outside, even when the sun is shining. If the sun is shining the smartphone is very hard to use if the colours don't have high enough contrast. But how much is high enough? The Web Accessibility Initiative defines it by "enough contrast between text and its background so "that it can be read by people with moderately low vision." Okay, moderately low vision, how much is that? We need a number. And there is a number. That so-called contrast ratio. And it works like that, the lowest ratio is 1:1. You get that if you use the same colour for text and background. So it's lowest one. The highest ratio is 1:21 and you get it if you use black text and white background colour or vice versa. The minimum ratio we should be using for normal text that is less than 24 pixels is 4.5:1 or for bold text that is less than 19 pixels, 3:1. Or for larger text, also 3:1. Ideally we would have a ratio of 7:1 for normal text and 4.5:1 for bold text. Of course, there is a formula to calculate it but you don't have to use your calculator, there are tools. For example, Lea Verou's contrast ratio. A browser tool you enter a colour for the background, a colour for the text and it will tell you the ratio. In this example it's 13.5:1, so high enough or very high. Another great tool that you will find in the browser in dev tools in Chrome is the redesigned Audits panel. It has Lighthouse baked in and you can use it to make several checks for PWAs, for performance and also for accessibility. It will check your website for best practises and give you a score and it will tell you what's wrong with the website and even show you some of the items that need to be looked at again. So here, those are all the items that have low contrast. What's funny about it is that the help text has incredibly low contrast so you can't even read it here. So, that's pretty awesome and it's also great for testing PWAs. Lighthouse, I think it's in the newest version of Chrome Canary. Another thing that's real awesome is you can show the contrast ratio directly in the colour picker in dev tools. As you can see here on this side, it will tell you the score and if you meet AA or AAA criteria. All you have to do is you have to enable Experiments in Chrome Canary, make some settings, press Shift seven timesand that's it. Really, you really have to press Shift seven times in order to get it working. Here's the explanation in a blog post by Remy Sharp. I'm going to share it with you afterwards. Now meeting the criteria is one thing but actually testing for contrast is another thing. What we can do in Windows, for example, is we can use a system setting called "High Contrast" and change the default theme to a very high contrasting theme. Like this one, for example, and the whole theme for the operating system changes and for the browser as well. If you do that you will see some very, or not see, some very interesting stuff. For example, I created a log in form. It's inspired by something I found on Dribble. Now what's interesting about that is that it has a grey background, you don't see the grey background because the colours are in low contrasting... That's kind of the point but you should actually see the background but it doesn't matter. And I used the form to test it in different themes. And what we can see here is that, in high contrast themes the button isn't recognisable any more as a button. We see the text, we see the centre text, but we don't have a background or a border or anything the like. If it wasn't for the placeholder text the users wouldn't see that there are input fields. A quick and easy fix was to add a default border for the input fields, a default white border, and a default, whatever that colour is, violet border for the button. Then the forms are much better usable in high contrast modes. - [Audience Member] - Another great tool is called NoCoffee. You can simulate blocked visual fields or colour deficiencies or you can blur the screen, for example, it's a plugin for Chrome and Firefox I think. Definitely Chrome. And you can use it to test different visual impairments which is pretty cool. So, why am I talking about colour contrast? Because you can see very interesting trends in the last years of using low contrasting colours. Something like grey text on light grey background. It looks nice, it looks Apple-ish, but it's bad for accessibility. So please try to use high contrasting colours. I really like the next thing I'm going to talk about because believe me or not, but people still print stuff out. And people even print websites. They print contact information, directions, recipes, blog posts, they print a lot. And we should try to give them some kind of experience on paper that is, in a way, at least accessible or maybe even great. Technically it's pretty easy, we just have to embed a media declaration in our CSS similar to using a media query and there we change some of our items or components for the special print display. For example, if we have a fixed header we can set it to static so it's not fixed on the paper somewhere. And if there are items that we don't need, like the navigation for example, because it's pretty useless on paper, we can hide it. You can even make something like that. You can select all direct child elements except for the main element and hide them, for example, the header and the footer. Because probably you don't need that information on paper. What's also great about print is that we finally get to use absolute units like centimetre and millimetre because it makes sense. We know how big paper is and even if the user prints A3, a much bigger format, we can query that using media queries. A difficult topic when it comes to prints are links, they aren't usable on paper because you can't click them, you can try to click them but it won't work. Really, believe me! And you don't see where they are leading. There's a nice workaround, nice and easy selector I'm using here. What it does, it selects all links that have an href attribute that starts with HTTP. That includes HTTPS as well, but it doesn't include anchor links or relative paths. We exclude all absolute links to our website so you will have to change domain here. And we use a pseudo-element to add the value of the href attributes in parentheses right next to the word. - [Audience Member] - Yes, but in this case it's great because you will see this on the screen, so the link, as you would expect it and on paper you get this. So I'm able to extract the value from the href attribute and put it next to a word. That's pretty cool. If you are like me you like to use the keyboard sometimes for navigating a website. For example, in a long form, because it's easier to jump from one form item to the other by using the keyboard instead of the mouse. The thing is, it works sometimes and sometimes it doesn't because developers like to do really, really bad things to forms. It seems like developers hate radio buttons, checkboxes, selects and buttons. I want to show you some of those bad things. Here we have two buttons and if I click the first button an alert pops up. If I click the second button you see the alert as well. Now, if I try to use the tab key to focus the buttons, I can focus the first one, but I can't focus the second one. The reason for that is that the first button is an actual HTML5 button element and is focusable, and the second button is a div that looks like a button and divs aren't focusable by default. Another problem here is that if you try to use the keyboard, the space key and the enter key to trigger the click event on the div, it won't work. But it works on the button because you get that for free with the button. And the button element is, of course, better for accessibility for screen reader users because if the screen reader gets to a button it will announce "This is a button." If it gets to a div, it will say something like "div" or nothing. So please use <button> if you need buttons. Here we have a simple page with some links and some form items with low contrast. If I tried to use the keyboard you don't see anything. From time to time you will see a cursor pop up in one of the input fields but that's about it. You don't know where in the page we are currently. The reason for that are those three lines. Select all items in the focus state and remove the outline. By using three lines of CSS you can exclude a whole group of people from being able to use your site. If we remove those lines, it will look like that. At every tab we can see where in the page we are because this nice looking outline will jump from link to link to input fields. Basically from every interactive element to another interactive element. The reason why developers or designers remove this outline in the first place is it's ugly. It just doesn't look nice. And another reason is that it isn't consistent across browsers. So here in Chrome you will see this blurry blue line, on Android you will see an orange line, and in Firefox you will see a dotted line. This inconsistency also is nice. So I get it why you do that, why people do it and remove it but if you remove it, provide alternative styling. For example, you can use a solid outline or background. Whatever it is, just show people where they are if they are using the keyboard. You can do that by using the focus pseudo-class. Or you can even use some of the newer stuff. The focus-within pseudo-class. You can see here that at some point the form shows a box-shadow and this only happens if one of its child items is currently being focused. So it's not about the form being focused, but one of its children so if one of the children is in focus, the form will receive a box-shadow. And that's possible to focus within pseudo-class. Support is pretty g... Okay, no, it's not pretty good it's okay. But you can use it today if you're not using it for something too critical. So if you need it, use it. One thing that's really annoying about focus styles is that sometimes you will see the blue outline even when you're not using the keyboard but the mouse. It will happen especially for custom focusable elements like this section here. What we need is a way to differentiate between keyboard and mouse users. And that's what the focus-ring pseudo-class is here. You will only select those items where it makes sense that they have an outline and the browser decides if it makes sense or not. Unfortunately, it doesn't work in any browser but there is a very lightweight polyfill. So, who are we making this for? For you and me, the power users? Of course, why not? But also for people who actually rely on the keyboard as their only way of navigation. Or for someone who would actually use a mouse but can't because they broke their arm, for example. Or maybe even a new parent who's holding their kid and has to check something online. Whatever it is, it's important for us to understand that there are permanent, temporary, and situational impairments. If we know that, that makes the group of people who depend on the keyboard much bigger. Alright, now let's get to some of the newer, more advanced stuff. Here we have a bunch of images. Some small images, a big version, a long image, and I put them in a list and I want to display them in a grid, a CSS grid layout that's really easy. I simply select the unordered list, I set the display to grid. I create as many columns as fit into the screen with a minimum width of 180 pixels. I create horizontal and vertical spacing and I set a default height of 184 rows. And that's what you get with four lines of CSS. And this is fully responsive. That's pretty cool but now we lost big images and the long images. No problem, I select the long images, I tell them to span two rows instead of just one. I select large images and tell them to span two rows, as well. And I'm going to place the first large image at the very end of the gallery and the second one at the very beginning. And this is what we get. Because of the different sizes of the images and the explicit placement I did, we get those gaps. No problem for a grid layout. We simply set grid-auto-flow to dense and the browser will try its best to fill those gaps. This is what we get. Magic. Five lines of CSS, fully responsive, incredibly awesome. But, it sucks because it's not usable for keyboard users. It's completely unpredictable where the focus will jump because grids did it's magic. Whatever you do, use it, use it now, but don't use it for very interaction sensitive stuff. Don't use it for forms or for a gallery. And if you do, test it with the keyboard and make sure that it's still usable and that the experience doesn't suck. Of course, this doesn't just apply for grid properties. Basically for every property that will change the order in some way. Flex properties, position, floatings or even negative margins. While we are at the topic, who of you uses grids already? Or tried grids? Okay, two people? Okay. So nobody uses it in production. Please do. Support is pretty great, all major desktop and smartphone browsers support grids except for Edge but Edge will ship it in the next version, in Edge 16. Thanks to progressive enhancement, you can use it right now. You can provide a very basic experience for browsers that are less capable and then enhance it with Flexbox or grids. To give you an example I made a simple demo. It's a very basic layout, a single column layout. It's basically what you would see on a smartphone. That's what it looks like and here we have controls to enhance the experience. Now I'm switching to floating and it looks nice, boring but nice. And we can enhance it some more. Use Flexbox. And now especially here, in the Latest Articles section, the layout is a little more interesting and we can switch to grids and break out of the layout and make all kind of cool stuff here and even make this part here a little more flexible. What's cool about that is that you don't have to write three or four different versions of your site. You provide a very basic experience by using float, for example, and then you just add grids. Because properties like float, column properties, vertical-align, display:table-cell, inline-block, don't have any effect on grid or flex items. They simply don't work so you don't have to use feature queries to reset floating, for example, it just doesn't work. So, most of the time you will only need feature queries to change properties like width or margin, for example. That's pretty cool. Grid is awesome, it has very nice features but it also leads us in new temptation. I will show you what I'm talking about. Let's say we want to make something like that. Just very simple layout with a heading and six items that are placed in a grid. I can use div and heading and unordered list and some list items and then I will again set display the grids, create some columns, a fixed-width column and two flexible columns. Some spacing and a placed heading. And it will look like that because only direct child items of a grid container are placed on the grid. So the <h2> and the unordered list but not the list items, of course. The worst thing you can do is to flatten the structure. You can remove the unordered list and transform the list items to divs. It will work but you shouldn't compromise semantics for design or user experience reasons. In a perfect, perfect world we would be able to use display: subgrids. Display: subgrids will make child items of a grid item act as if they were grid items themselves even though they aren't direct children of the grid container. Unfortunately, subgrid didn't make it into level one of the specification but it will, hopefully, come with level 2. Another option is display: contents. Display: contents will make child items of an item act as if their parent doesn't exist. That's pretty cool but only works in Firefox. Now, what we have to do now is we create another grid within the grid and define columns again and the gap. This isn't ideal but, yeah, it works. In this specific case, since the unordered list spans the whole grid. That's the first line here, 1 / -1. We can inherit all those properties from the parent grid and that's much easier and nicer. So, whatever you do, don't do that. Don't flatten the structure. And that's it. That's, of course, not everything you need to know about CSS and accessibility but it's more than just a starting point. If you, let's say, take two of those things I told you today and implement them in your next project and care about them, you are already doing a great job. And if you take two more things for your next project and care about them as well, you are working towards a better web. It's important for us as developers and designers to not just make web sites for the way we use it but to test it in different browsers and different devices, different operating systems, with different input devices and in different settings. Because, as my mentor Aaron Gustafson said, "Designing with constraints in mind "is simply designing well." If you want to learn about accessibility I have written some articles on Medium. The first one is called "Writing HTML with accessibility in mind." It's about HTML. And the second one is about JavaScript and accessibility. And the third one is about CSS and accessibility. It will be online next week I hope. Thank you.