Enable
>

Focus Styling

Focus states are used by keyboard users to know what interactive element they can currently manipulate. They are usually styled with

Focus Styling For Keyboard Users Only

This is recommended for use in both new and existing projects. It

When I am auditing a website for accessibility issues for the first time, lack of focus indicators is usually one of the first things I see. This is usually because a lot of designers and/or developers will think that focus indicators look ugly and will put in the following CSS to get rid of them:

☜ Scroll to read full source ☞

                    
                
Figure 1. Horrible code a lot of developers use to turn off focus states. Never do this.

This is a bad idea. Keyboard users need focus states need these focus indicators to know what interactive element currently has focus. "But VoiceOver has it's own focus indicator!" is what I hear some of you say. Not everyone who uses a keyboard uses VoiceOver. You absolutely need a visible focus indicator on all your interactive elements in order to pass WCAG 2.4.7.

What you can do is make focus indicators only appear for keyboard users? This can be done using the :focus-visible CSS pseudo-class. Here is how the Enable site codes them globally using TPGI's excellent method to use :focus-visible while ensuring browsers that don't support it fallback to using :focus gracefully:

☜ Scroll to read full source ☞

                    
                
Figure 2. Much better code that styles focus states for keyboard users, while minimizing its visibility for mouse users.

Is it just keyboard users that will see focus states styled with focus-visible? Kind of, but there are a few subtleties. Andy Adams has written a great article for CSS Tricks about :focus-visible that really goes into detail.

Increase Hit Areas Inside Focusable Elements

If you use a keyboard to navigate through the main navigation, you will notice the clickable hit-area of the top level navigation items are a lot bigger than they actually take up in the layout:

Screenshot of the Enable website's main navigation, with keyboard focus applied to the 'controls' navigation drawer.
Figure 3. The focus state of the "Controls" navigation button. Note the large hit area.

We increased the hit area to conform to WCAG 2.5.5: Target Size (we made it larger than 44 pixels x 44 pixels). Even though this is a AAA requirement, it is so easy to implement by increasing the padding and compensating visually with an equivalent negative margin, so why just conform to WCAG 2.5.8: Target Size (Minimum). (which only asks 24 pixels x 24 pixels)?

☜ Scroll to read full source ☞

                    
                

I encourage everyone reading this to implement this on all the websites they code. From a UX perspective, it just makes it easier for everyone to use the websites you code.

Issues with CSS Transitions and CSS outline in Safari

On a few projects, I have noticed that Safari focus states don't appear correctly when the element that is focused has the following CSS applied to it:

☜ Scroll to read full source ☞

                    
                
Figure 4. CSS transition: all code that should be avoided.

The above CSS can mess up Safari focus states: they may appear cut off or may not appear at all in Safari, while they may appear fine in other web browsers. The correct way to fix this is to never use transition: all in your CSS. Using all. There are many reasons why you should never use not use the all keyword for transitions (in this case, because of unwanted side-effects, but also for performance reasons). Philipp Nowinski has written a great write-up on why you shouldn't use the 'all' keyword in CSS transitions, and I suggest all developers read this.

If removing the all transition code will cause problems in your project, you can use the following hack to fix the code in Safari:

☜ Scroll to read full source ☞

                    
                
Figure 5. Fix for Safari to work around transition: all code issue.

Note that it is much better to remove the all keyword and just transition what you need instead. This solution should only be a band-aid solution until you can fix the issue properly.

Don't Forget Windows High Contrast Mode Users.

Sometimes, you will want to style focus states without the CSS outline property. If you do this, but instead of using outline: none to remove the default focus ring, developers should use outline with the transparent colour:
☜ Scroll to read full source ☞

                    
                
Figure 6. Adding a transparent outline along with your custom focus state that doesn't have an outline

Guaranteed Contrast on Focus Rings, Regardless of Background

If you don't know what colour background your focus rings will be on top of, there is a simple way of ensuring your focus rings will follow contrast rules: using outline and box-shadow at the same time.

Here is an example you can tab into to see this combo in action:

This is a dummy link This is a dummy link This is a dummy link This is a dummy link This is a dummy link This is a dummy link This is a dummy link

If you are using a mobile device, here are some screenshots you can look at to show how it looks:

Focus State Screenshot
No Element is Focused Two yellow blocky interactive elements on a gradient background. The gradient is starts on a light yellow on the left and ends with a darker red on the right.
Focus on Lighter Area of Gradient The same interactive elements on the same gradient background.  The interactive element on the left is focused, and the blue focus outline around it is easily seen in contrast with the light background.
Focus on Darker Area of Gradient The same interactive elements on the same gradient background.  The interactive element on the right is now focused, and the white box shadow that appears outside the darker blue focus outline ensures the focus ring has enough contrast with the dark background.
Figure 7. Dual-Coloured Focus States on a Gradient Background

Here is the markup that implements the double focus ring. Notice the use of both outline and box-shadow to create this effect (the box-shadow offsets must be greater than the outline thickness in order for this to work):

☜ Scroll to read full source ☞