focus – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Sat, 30 Mar 2024 02:12:36 +0000 en-US hourly 1 https://wordpress.org/?v=6.4.3 https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1 focus – CSS-Tricks https://css-tricks.com 32 32 45537868 Accessible Forms with Pseudo Classes https://css-tricks.com/accessible-forms-with-pseudo-classes/ https://css-tricks.com/accessible-forms-with-pseudo-classes/#comments Fri, 22 Mar 2024 18:52:31 +0000 https://css-tricks.com/?p=377565 Hey all you wonderful developers out there! In this post, I am going to take you through creating a simple contact form using semantic HTML and an awesome CSS pseudo class known as :focus-within. The :focus-within class allows for …


Accessible Forms with Pseudo Classes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Hey all you wonderful developers out there! In this post, I am going to take you through creating a simple contact form using semantic HTML and an awesome CSS pseudo class known as :focus-within. The :focus-within class allows for great control over focus and letting your user know this is exactly where they are in the experience. Before we jump in, let’s get to the core of what web accessibility is.


Form Accessibility?


You have most likely heard the term “accessibility” everywhere or the numeronym, a11y. What does it mean? That is a great question with so many answers. When we look at the physical world, accessibility means things like having sharps containers in your bathrooms at your business, making sure there are ramps for wheel assisted people, and having peripherals like large print keyboards on hand for anyone that needs it.

The gamut of accessibility doesn’t stop there, we have digital accessibility that we need to be cognizant of as well, not just for external users, but internal colleagues as well. Color contrast is a low hanging fruit that we should be able to nip in the bud. At our workplaces, making sure that if any employee needs assistive tech like a screen reader, we have that installed and available. There are a lot of things that need to be kept into consideration. This article will focus on web accessibility by keeping the WCAG (web content accessibility guidelines) in mind.

MDN (Mozilla Developer Network)

The :focus-within CSS pseudo-class matches an element if the element or any of its descendants are focused. In other words, it represents an element that is itself matched by the :focus pseudo-class or has a descendant that is matched by :focus. (This includes descendants in shadow trees.)

This pseudo class is really great when you want to emphasize that the user is in fact interacting with the element. You can change the background color of the whole form, for example. Or, if focus is moved into an input, you can make the label bold and larger of an input element when focus is moved into that input. What is happening below in the code snippets and examples is what is making the form accessible. :focus-within is just one way we can use CSS to our advantage.

How To Focus


Focus, in regards to accessibility and the web experience, is the visual indicator that something is being interacted with on the page, in the UI, or within a component. CSS can tell when an interactive element is focused.

“The :focus CSS pseudo-class represents an element (such as a form input) that has received focus. It is generally triggered when the user clicks or taps on an element or selects it with the keyboard’s Tab key.”

MDN (Mozilla Developer Network)

Always make sure that the focus indicator or the ring around focusable elements maintains the proper color contrast through the experience.

Focus is written like this and can be styled to match your branding if you choose to style it.

:focus {
  * / INSERT STYLES HERE /*
}

Whatever you do, never set your outline to 0 or none. Doing so will remove a visible focus indicator for everyone across the whole experience. If you need to remove focus, you can, but make sure to add that back in later. When you remove focus from your CSS or set the outline to 0 or none, it removes the focus ring for all your users. This is seen a lot when using a CSS reset. A CSS reset will reset the styles to a blank canvas. This way you are in charge of the empty canvas to style as you wish. If you wish to use a CSS reset, check out Josh Comeau’s reset.

*DO NOT DO what is below!

:focus {
  outline: 0;
}

:focus {
  outline: none;
}


Look Within!


One of the coolest ways to style focus using CSS is what this article is all about. If you haven’t checked out the :focus-within pseudo class, definitely give that a look! There are a lot of hidden gems when it comes to using semantic markup and CSS, and this is one of them. A lot of things that are overlooked are accessible by default, for instance, semantic markup is by default accessible and should be used over div’s at all times.

<header>
  <h1>Semantic Markup</h1>
  <nav>
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/about">About</a></li>
    </ul>
  </nav>
</header>

<section><!-- Code goes here --></section>

<section><!-- Code goes here --></section>

<aside><!-- Code goes here --></aside>

<footer><!-- Code goes here --></footer>

The header, nav, main, section, aside, and footer are all semantic elements. The h1 and ul are also semantic and accessible.

Unless there is a custom component that needs to be created, then a div is fine to use, paired with ARIA (Accessible Rich Internet Applications). We can do a deep dive into ARIA in a later post. For now let’s focus…see what I did there…on this CSS pseudo class.

The :focus-within pseudo class allows you to select an element when any descendent element it contains has focus.


:focus-within in Action!

HTML

<form>
  <div>
    <label for="firstName">First Name</label><input id="firstName" type="text">
  </div>
  <div>
    <label for="lastName">Last Name</label><input id="lastName" type="text">
  </div>
  <div>
    <label for="phone">Phone Number</label><input id="phone" type="text">
  </div>
  <div>
    <label for="message">Message</label><textarea id="message"></textarea>
  </div>
</form>

CSS

form:focus-within {
  background: #ff7300;
  color: black;
  padding: 10px;
}

The example code above will add a background color of orange, add some padding, and change the color of the labels to black.

The final product looks something like below. Of course the possibilities are endless to change up the styling, but this should get you on a good track to make the web more accessible for everyone!

First example of focus-within css class highlighting the form background and changing the label text color.

Another use case for using :focus-within would be turning the labels bold, a different color, or enlarging them for users with low vision. The example code for that would look something like below.

HTML

<form>
  <h1>:focus-within part 2!</h1>
  <label for="firstName">First Name: <input name="firstName" type="text" /></label>
  <label for="lastName">Last Name: <input name="lastName" type="text" /></label>
  <label for="phone">Phone number: <input type="tel" id="phone" /></label>
  <label for="message">Message: <textarea name="message" id="message"/></textarea></label>
</form>

CSS

label {
  display: block;
  margin-right: 10px;
  padding-bottom: 15px;
}

label:focus-within {
  font-weight: bold;
  color: red;
  font-size: 1.6em;
}
Showing how to bold, change color and font size of labels in a form using :focus-within.

:focus-within also has great browser support across the board according to Can I use.

Focus within css pseudo class browser support according to the can i use website.

Conclusion

Creating amazing, accessible user experience should always be a top priority when shipping software, not just externally but internally as well. We as developers, all the way up to senior leadership need to be cognizant of the challenges others face and how we can be ambassadors for the web platform to make it a better place.

Using technology like semantic markup and CSS to create inclusive spaces is a crucial part in making the web a better place, let’s continue moving forward and changing lives.

Check out another great resource here on CSS-Tricks on using :focus-within.


Accessible Forms with Pseudo Classes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/accessible-forms-with-pseudo-classes/feed/ 12 377565
Standardizing Focus Styles With CSS Custom Properties https://css-tricks.com/standardizing-focus-styles-with-css-custom-properties/ https://css-tricks.com/standardizing-focus-styles-with-css-custom-properties/#comments Fri, 10 Dec 2021 16:00:48 +0000 https://css-tricks.com/?p=357373 Take two minutes right now and visit your current project in a browser. Then, using only the Tab key, you should be able to navigate between interactive elements including buttons, links, and form elements.

If you are sighted, you should


Standardizing Focus Styles With CSS Custom Properties originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Take two minutes right now and visit your current project in a browser. Then, using only the Tab key, you should be able to navigate between interactive elements including buttons, links, and form elements.

If you are sighted, you should be able to visually follow the focus as it jumps between elements in the DOM. But if you do not see any visual change, or only a barely noticeable visual change, then you’ve found the one thing you can do to make a big difference for your visitors.

We’re going to look at a technique to make your focus styles more manageable across your project by using CSS custom properties and learn about a modern CSS focus selector. But first, let’s learn more about why visible focus styles are important.

Meeting WCAG Focus Style Criteria

Visible focus states are covered in the Web Content Accessibility Guidelines (WCAG) Success Criterion 2.4.7 – Focus Visible. The Understanding doc for 2.4.7 states the following in the intent of this criteria:

The purpose of this success criterion is to help a person know which element has the keyboard focus. It must be possible for a person to know which element among multiple elements has the keyboard focus.

In the upcoming WCAG 2.2, a new criterion is being added to clarify “how visible the focus indicator should be.” While currently in draft, getting familiar with and applying the guidelines in 2.4.11 – Focus Appearance (Minimum) is definitely a positive step you can take today to improve your focus styles.

Managing focus style with CSS custom properties

A technique I’ve started using this year is to include the following setup early in my cascade on the primary base interactive elements:

:is(a, button, input, textarea, summary) {
  --outline-size: max(2px, 0.08em);
  --outline-style: solid;
  --outline-color: currentColor;
}

:is(a, button, input, textarea, summary):focus {
  outline: var(--outline-size) var(--outline-style) var(--outline-color);
  outline-offset: var(--outline-offset, var(--outline-size));
}

This attaches custom properties that allow you the flexibility to customize just parts of the outline style as needed to ensure the focus remains visible as the element’s context changes.

For --outline-size, we’re using max() to ensure at least a value of 2px, while allowing the possibility of scaling relative to the component (ex. a large button or link within a headline) based on 0.08em.

A property you might not be familiar with here is outline-offset which defines the space between the element and the outline. You can even provide a negative number to inset the outline, which can be very useful for ensuring contrast of the focus style. In our rule set, we’ve set that property to accept an optional custom property of --outline-offset so that it can be customized if needed, but otherwise it has the fallback to match the --outline-size.

Improvements for outline appearance

Over my career, I’ve both been asked to remove outlines and removed them myself because they were considered “ugly”.

There are now two reasons outline should absolutely never have cause to be removed (in addition to the accessibility impact):

  1. outline now follows border-radius in Chromium and Firefox! 🎉 This means you can considering removing any hacks you may have used, such as faking it with a box-shadow (which has another positive accessibility impact of ensuring focus styles aren’t removed for Windows High Contrast Theme users).
  2. Using :focus-visible we can ask the browser to use heuristics to only show focus styles when it detects input modalities that require visible focus. Simplified, that means mouse users won’t see them on click, keyboard users will still have them on tab.

It’s important to note that form elements always show a focus style — they are exempt from the behavior of :focus-visible.

So let’s enhance our rule set to add the following to include :focus-visible. We’ll keep the initial :focus style we already defined for older browsers so that it’s not lost just in case.

:is(a, button, input, textarea, summary):focus-visible {
  outline: var(--outline-size) var(--outline-style) var(--outline-color);
  outline-offset: var(--outline-offset, var(--outline-size));
}

Due to the way browsers throw out selectors they don’t understand, we do need to make these separate rules and not combine them even though they define the same outline properties.

Finally, we also need this kind of funny-looking :focus:not(:focus-visible) rule that removes the regular focus styles for browsers that support :focus-visible:

:is(a, button, input, textarea, summary):focus:not(:focus-visible) {
  outline: none;
}

Of note is that the latest versions of Chromium and Firefox have switched to using :focus-visible as the default way to apply focus styles on interactive elements, and just recently was enabled as default in webkit so it should be in Safari stable soon! Our rules are still valid since we’re customizing the outline appearance.

For more guidance on visible focus styles, I recommend Sara Soueidan’s amazing and thorough guide to focus indicators because it considers the upcoming 2.4.11 criterion.

Focus styles demo

This Pen shows examples of each of these interactive elements and how to apply customizations using the custom properties, including a few swaps for dark mode. Depending on your browser support, you may not see a focus style due to :focus-visible unless you use the tab key.

One final note: button is a unique interactive element when it comes to focus styles because it has additional considerations across its states, particularly if you are relying on color alone. For help with that, try out the palette generator from my project ButtonBuddy.dev.


Standardizing Focus Styles With CSS Custom Properties originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/standardizing-focus-styles-with-css-custom-properties/feed/ 10 357373
A Deep Dive on Skipping to Content https://css-tricks.com/a-deep-dive-on-skipping-to-content/ https://css-tricks.com/a-deep-dive-on-skipping-to-content/#comments Tue, 03 Aug 2021 14:35:48 +0000 https://css-tricks.com/?p=345154 While most people browsing the web on a computer use a mouse, many rely on their keyboard instead. Theoretically, using a web page with the keyboard should not be a problem — press the TAB key to move the keyboard …


A Deep Dive on Skipping to Content originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
While most people browsing the web on a computer use a mouse, many rely on their keyboard instead. Theoretically, using a web page with the keyboard should not be a problem — press the TAB key to move the keyboard focus from one focusable element to the next then press ENTER to activate, easy! However, many (if not most) websites tend to have a menu of links at the top of the page, and it can sometimes take a lot of presses to get to the content that you want. Take the homepage of 20min for example, one of the biggest news sites here in Switzerland. You want to read the top story? That’ll be the best part of 40 key presses — not the best best use of anyone’s time.

So, if you want keyboard users to actually use your website rather than getting bored and going somewhere else, you need to do a bit of work behind the scenes to make skipping straight to your main content quicker and easier. You can find all sorts of techniques for this scattered across the web (including here at CSS-Tricks) but most are missing a trick or two and many recommend using outdated or deprecated code. So, in this article, I’m going to take a deep dive into skipping to content and cover everything in a 2021-friendly fashion.

Two types of keyboard users

Although there are numerous differences in the exact type of keyboard or equivalent switch device that people use to navigate, from a coding point of view, we only need to consider two groups:

  • People who use the keyboard in conjunction with a screen reader — like NVDA or JAWS on a PC, or VoiceOver on a Mac — that reads the content of the screen out loud. These devices are often used by people with more severe visual impairments.
  • All other keyboard users.

Our skip-to-content techniques need to cater to both these groups while not getting in the way of all the mouse users. We will use two complementary techniques to get the best result: landmarks and skip links.

Look at a basic example

I created an example website I’m calling Style Magic to illustrate the techniques we’re covering. We’ll start off with it in a state that works fine for a mouse user but is a bit of a pain for those using a keyboard. You can find the base site and the versions for each of the techniques in this collection over at CodePen and, because testing keyboard navigation is a little tricky on CodePen, you can also find standalone versions here.

Try using the TAB key to navigate this example. (It’s easier on the standalone page; TAB to move from one link to the next, and SHIFT+TAB to go backwards.) You will find that it’s not too bad, but only because there aren’t many menu items.

If you have the time and are on Windows then as I’d also encourage you to download a free copy of the NVDA screen reader and try all the examples with that too, referring to WebAIM’s overview for usage. Most of you on a Mac already have the VoiceOver screen reader available and WebAIM has a great intro to using it as well.

Adding landmarks

One of the things that screen reading software can do is display a list of landmarks that they find on a web page. Landmarks represent significant areas of a page, and the user can pull up that list and then jump straight to one of those landmarks.

If you are using NVDA with a full keyboard, you hit INS+F7 to bring up the “Elements List” then ALT+d to show the landmarks. (You can find a similar list on VoiceOver by using the Web Item Rotor.) If you do that on example site, though, you will only be presented with an unhelpful empty list.

An open dialog with a UI for viewing different types of content on the page in a screen reader, including links, headings, form fields, buttons, and landmarks. Landmarks is selected and there are no results in the window.
A disappointingly empty list of landmarks in NVDA

Let’s fix that first.

Adding landmarks is incredibly easy and, if you are using HTML5, you might already have them on your website without realizing it, as they are directly linked to the HTML5 semantic elements (<header>, <main>, <footer>, and so on).

Here’s a before and after of the HTML used to generate the header section of the site:

<div class="bg-dark">
  <div class="content-width flex-container">
    <div class="branding"><a href="#">Style Magic</a></div>
    <div class="menu-right with-branding">
      <a href="#">Home</a>
      <!-- etc. -->
      </div>
  </div>
</div>

Becomes

<div class="bg-dark">
 <header class="content-width flex-container">    
    <section class="branding"><a href="#">Style Magic</a></section>
    <nav aria-label="Main menu" class="menu-right with-branding">
      <a href="#">Home</a>
      <!-- etc. -->
    </nav>
  </header>
</div>

The classes used remain the same, so we don’t need to make any changes at all to the CSS.

Here’s a full list of the changes we need to make in our example site:

  • The <div> denoting the header at the top of the page is now a <header> element.
  • The <div> containing the branding is now a <section> element.
  • The two <div>s containing menus have been replaced with <nav> elements.
  • The two new <nav> elements have been given an aria-label attribute which describes them: “Main menu” for the menu at the top of the page, and “Utility menu” for the menu at the bottom of the page.
  • The <div> containing the main content of the page is now a <main> element.
  • The <div> denoting the footer at the bottom of the page is now a <footer> element.

You can see the full updated HTML on CodePen.

Let’s try that landmark list trick in NVDA again (INS+F7 then ALT+d — here’s the link to the standalone page so you can test yourself):

Open screen reader dialog window showing the landmarks on the current page, including "banner," "main," and "content info."
Hurrah for landmarks!

Great! We now have the banner landmark (mapped to the <header> element), Main menu; navigation (mapped to the top <nav> element, and displaying our aria-label), main (mapped to <main>) and content info (mapped to footer). From this dialog I can use TAB and the cursor keys to select the main landmark and skip straight to the content of the page, or even better, I can just press the D key when browsing the page to jump from one landmark role directly to the next. Users of the JAWS screen reader have it even easier — they can simply press Q when browsing to jump straight to the main landmark.

As an added bonus, using semantic elements also help search engines understand and index your content better. That’s a nice little side benefit of making a site much more accessible.

I expect you’re sitting back thinking “job done” at this point. Well, I’m afraid there’s always a “but” to consider. Google did some research way back in 2011 on the use of CTRL+f to search within a web page and found that a startling 90% of people either didn’t know it existed, or have never used it. Users with a screen reader behave in much the same way when it comes to landmarks — a large portion of them simply do not use this feature even though it’s very useful. So, we’re going to add a skip link to our site to help out both groups as well as all those keyboard users who don’t use a screen reader.

The basic requirements for what makes a good skip link are:

  • It should be perceivable to all keyboard users (including screen reader users) when it is needed.
  • It should provide enough information to the keyboard user to explain what it does.
  • It should work on as wide a range of current browsers as possible.
  • It should not interfere with the browsing of a mouse user.

Step 1: Improving the keyboard focus appearance

First up, we’re going to improve the visibility of the keyboard focus across the site. You can think of the keyboard focus as the equivalent to the position of the cursor when you are editing text in a word processor. When you use the TAB key to navigate the keyboard focus moves from link to link (or form control).

The latest web browsers do a reasonable job of showing the position of the keyboard focus but can still benefit from a helping hand. There are lots of creative ways to style the focus ring, though our goal is making it stand out more than anything.

We can use the :focus pseudo-class for our styling (and it’s a good idea to apply the same styles to :hover as well, which we’ve already done on the example site — CodePen, live site). That’s the very least we can do, though it’s common to go further and invert the link colors on :focus throughout the page.

Here’s some CSS for our :focus state (a copy of what we already have for :hover):

a:focus { /* generic rule for entire page */
  border-bottom-color: #1295e6;
}
.menu-right a:focus,
.branding a:focus {
  /* inverted colors for links in the header and footer */
  background-color: white;
  color: #1295e6;
}

Step 2: Adding the HTML and CSS

The last change is to add the skip link itself to the HTML and CSS. It consists of two parts, the trigger (the link) and the target (the landmark). Here’s the HTML that I recommend for the trigger, placed right at the start of the page just inside the <header> element:

<header class="content-width flex-container">
  <a href="#skip-link-target" class="text-assistive display-at-top-on-focus">Skip to main content.</a>
  <!-- etc. -->
</header>

And here’s the HTML for the target, placed directly before the start of the <main> content:

<a href="#skip-link-target" class="text-assistive display-at-top-on-focus" id="skip-link-target">Start of main content.</a>

<main class="content-width">
  <!-- etc. -->
</main>

Here’s how the HTML works:

  • The skip link trigger links to the skip link target using a standard page fragment (href="#skip-link-target") which references the id attribute of the target (id="skip-link-target"). Following the link moves the keyboard focus from the trigger to the target.
  • We link to an anchor (<a>) element rather than adding the id attribute directly to the <main> element for two reasons. First, it avoids any issues with the keyboard focus not moving correctly (which can be a problem in some browsers); secondly, it means we can provide clear feedback to the user to show that the skip link worked.
  • The text of the two links is descriptive so as to clearly explain to the user what is happening.

We now have a functioning skip link, but there’s one problem: it’s visible to everyone. We’ll use CSS to hide it from view by default, which keeps it out of the way of mouse users, then have it appear only when it receives the keyboard focus. There are lots of ways to do this and most of them are okay, but there’s a couple of wrong ways that you should avoid:

  • Do: use clip-path to make the link invisible, or use transform: translate or position: absolute to position it off screen instead.
  • Don’t: use display: none, visibility: hidden, the hidden attribute, or set the width or height of the skip link to zero. All of these will make your skip link unusable for one or both classes of keyboard users.
  • Don’t: use clip as it is deprecated.

Here’s the code that I recommend to hide both links. Using clip-path along with its prefixed -webkit- version hits the spot for 96.84% of users at time of writing, which (in my opinion) is fine for most websites and use cases. Should your use case require it, there are a number of other techniques available that are detailed on WebAIM.

.text-assistive {
  -webkit-clip-path: polygon(0 0, 0 0, 0 0, 0 0);
  clip-path: polygon(0 0, 0 0, 0 0, 0 0);
  box-sizing: border-box;
  position: absolute;
  margin: 0;
  padding: 0;
}

And to show the links when they have focus, I recommend using a version of this CSS, with colors and sizing to match your branding:

.text-assistive.display-at-top-on-focus {
  top: 0;
  left: 0;
  width: 100%;  
}
.text-assistive.display-at-top-on-focus:focus {
  -webkit-clip-path: none;
  clip-path: none;
  z-index: 999;
  height: 80px;
  line-height: 80px;
  background: white;
  font-size: 1.2rem;
  text-decoration: none;
  color: #1295e6;
  text-align: center;
}
#skip-link-target:focus {
  background: #084367;
  color: white;
}

This provides for a very visible display of the trigger and the target right at the top of the page where a user would expect to see the keyboard focus directly after loading the page. There is also a color change when you follow the link to provide clear feedback that something has happened. You can fiddle with the code yourself on CodePen (shown below) and test it with NVDA on the standalone page.

Taking this further

Skip links aren’t just for Christmas your main menu, they are useful whenever your web page has a long list of links. In fact, this CodePen demonstrates a good approach to skip links within the content of your pages (standalone page here) using transform: translateY() in CSS to hide and show the triggers and targets. And if you are in the “lucky” position of needing to support older browsers, then you here’s a technique for that on this CodePen (standalone page here).

Let’s check it out!

To finish off, here are a couple of short videos demonstrating how the skip links work for our two classes of keyboard user.

Here’s how the finished skip link works when using the NVDA screen reader:

Here it is again when browsing using the keyboard without a screen reader:


We just looked at what I consider to be a modern approach for accessible skip links in 2021. We took some of the ideas from past examples while updating them to account for better CSS practices, an improved UI for keyboard users, and an improved experience for those using a screen reader, thanks to an updated approach to the HTML.


A Deep Dive on Skipping to Content originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/a-deep-dive-on-skipping-to-content/feed/ 14 345154
Form Validation Styling on Input Focus https://css-tricks.com/snippets/css/form-validation-styling-on-input-focus/ https://css-tricks.com/snippets/css/form-validation-styling-on-input-focus/#comments Mon, 08 Mar 2021 16:03:44 +0000 https://css-tricks.com/?page_id=335874 /* Only show invalid ring while not focused */ input:not(:focus):not(:placeholder-shown):invalid { border-color: var(--color-invalid); } input:not(:focus):not(:placeholder-shown):invalid ~ .error-message { display: block; } /* Only show valid ring while not focused and if a value is entered */ /* :empty won't work


Form Validation Styling on Input Focus originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
/* Only show invalid ring while not focused */ input:not(:focus):not(:placeholder-shown):invalid { border-color: var(--color-invalid); } input:not(:focus):not(:placeholder-shown):invalid ~ .error-message { display: block; } /* Only show valid ring while not focused and if a value is entered */ /* :empty won't work here as that targets elements that have no childeren. Therefore we abuse :placeholder-shown */ input:not(:focus):not(:placeholder-shown):valid { border-color: var(--color-valid); }

Pulling this straight from the Weekly Platform News, where Šime Vidas covers two long ongoing issues with using :invalid to style form input validation. Apparently, what happens is…

  • [inputs] become :invalid while the user is still typing the value.
  • If a form field is required (), it will become :invalid immediately on page load.

Both of these behaviors are potentially confusing (and annoying), so websites cannot rely solely on the :invalid selector to indicate that a value entered by the user is not valid. However, there is the option to combine :invalid with :not(:focus) and even :not(:placeholder-shown) to ensure that the page’s “invalid” styles do not apply to the <input> until the user has finished entering the value and moved focus to another element.

Ryan Florence sums this up nicely in a tweet:

So, what this snippet does is enhance :invalid by combining it with :not(:focus) and :not(:placeholder-shown).

What does that mean? Let’s translate the code into something more readable.

input:not(:focus):not(:placeholder-shown):invalid {}

If an input is not in focus, its placeholder text isn’t shown, and the entered text is invalid… then you can use these styles.

In other words, this prevents the invalid style from being applied until text is entered and focus moves to another element.

input:not(:focus):not(:placeholder-shown):invalid ~ .error-message

Hey, let’s display the error message if those same conditions are met.

This is the exact same thing as above, but selects an .error-message class and sets it from display: none to display: block only after the text is entered and focus moves from the input to something else.

input:not(:focus):not(:placeholder-shown):valid

Oh, the text that’s entered is valid? OK, let’s apply these styles instead.

Again, the same sorta condition, but chained to :valid instead of :invalid. That way, we can give the user a different set of styles to indicate that what they typed is good to go!

According to Šime, this sort of snippet might be unnecessary in the future as a greater push is being made for :user-invalid and :user-valid. Firefox already intends to ship its un-prefixed solution. Tickets are open to do the same in Safari and Chrome.


Form Validation Styling on Input Focus originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/snippets/css/form-validation-styling-on-input-focus/feed/ 5 335874
Weekly Platform News: Focus Rings, Donut Scope, More em Units, and Global Privacy Control https://css-tricks.com/weekly-platform-news-focus-rings-donut-scope-ditching-em-units-and-global-privacy-control/ https://css-tricks.com/weekly-platform-news-focus-rings-donut-scope-ditching-em-units-and-global-privacy-control/#comments Thu, 04 Mar 2021 21:33:01 +0000 https://css-tricks.com/?p=335856 In this week’s news, Chrome tackles focus rings, we learn how to get “donut” scope, Global Privacy Control gets big-name adoption, it’s time to ditch pixels in media queries, and a snippet that prevents annoying form validation styling.

Chrome will…


Weekly Platform News: Focus Rings, Donut Scope, More em Units, and Global Privacy Control originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In this week’s news, Chrome tackles focus rings, we learn how to get “donut” scope, Global Privacy Control gets big-name adoption, it’s time to ditch pixels in media queries, and a snippet that prevents annoying form validation styling.

Chrome will stop displaying focus rings when clicking buttons

Chrome, Edge, and other Chromium-based browsers display a focus indicator (a.k.a. focus ring) when the user clicks or taps a (styled) button. For comparison, Safari and Firefox don’t display a focus indicator when a button is clicked or tapped, but do only when the button is focused via the keyboard.

The focus ring will stay on the button until the user clicks somewhere else on the page.

Some developers find this behavior annoying and are using various workarounds to prevent the focus ring from appearing when a button is clicked or tapped. For example, the popular what-input library continuously tracks the user’s input method (mouse, keyboard or touch), allowing the page to suppress focus rings specifically for mouse clicks.

[data-whatintent="mouse"] :focus {
  outline: none;
}

A more recent workaround was enabled by the addition of the CSS :focus-visible pseudo-class to Chromium a few months ago. In the current version of Chrome, clicking or tapping a button invokes the button’s :focus state but not its :focus-visible state. that way, the page can use a suitable selector to suppress focus rings for clicks and taps without affecting keyboard users.

:focus:not(:focus-visible) {
  outline: none;
}

Fortunately, these workarounds will soon become unnecessary. Chromium’s user agent stylesheet recently switched from :focus to :focus-visible, and as a result of this change, button clicks and taps no longer invoke focus rings. The new behavior will first ship in Chrome 90 next month.

The enhanced CSS :not() selector enables “donut scope”

I recently wrote about the A:not(B *) selector pattern that allows authors to select all A elements that are not descendants of a B element. This pattern can be expanded to A B:not(C *) to create a “donut scope.”

For example, the selector article p:not(blockquote *) matches all <p> elements that are descendants of an <article> element but not descendants of a <blockquote> element. In other words, it selects all paragraphs in an article except the ones that are in a block quotation.

The donut shape that gives this scope its name

The New York Times now honors Global Privacy Control

Announced last October, Global Privacy Control (GPC) is a new privacy signal for the web that is designed to be legally enforceable. Essentially, it’s an HTTP Sec-GPC: 1 request header that tells websites that the user does not want their personal data to be shared or sold.

The DuckDuckGo Privacy Essentials extension enables GPC by default in the browser

The New York Times has become the first major publisher to honor GPC. A number of other publishers, including The Washington Post and Automattic (WordPress.com), have committed to honoring it “this coming quarter.”

From NYT’s privacy page:

Does The Times support the Global Privacy Control (GPC)?

Yes. When we detect a GPC signal from a reader’s browser where GDPR, CCPA or a similar privacy law applies, we stop sharing the reader’s personal data online with other companies (except with our service providers).

The case for em-based media queries

Some browsers allow the user to increase the default font size in the browser’s settings. Unfortunately, this user preference has no effect on websites that set their font sizes in pixels (e.g., font-size: 20px). In part for this reason, some websites (including CSS-Tricks) instead use font-relative units, such as em and rem, which do respond to the user’s font size preference.

Ideally, a website that uses font-relative units for font-size should also use em values in media queries (e.g., min-width: 80em instead of min-width: 1280px). Otherwise, the site’s responsive layout may not always work as expected.

For example, CSS-Tricks switches from a two-column to a one-column layout on narrow viewports to prevent the article’s lines from becoming too short. However, if the user increases the default font size in the browser to 24px, the text on the page will become larger (as it should) but the page layout will not change, resulting in extremely short lines at certain viewport widths.

If you’d like to try out em-based media queries on your website, there is a PostCSS plugin that automatically converts min-width, max-width, min-height, and max-height media queries from px to em.

(via Nick Gard)

A new push to bring CSS :user-invalid to browsers

In 2017, Peter-Paul Koch published a series of three articles about native form validation on the web. Part 1 points out the problems with the widely supported CSS :invalid pseudo-class:

  • The validity of <input> elements is re-evaluated on every key stroke, so a form field can become :invalid while the user is still typing the value.
  • If a form field is required (<input required>), it will become :invalid immediately on page load.

Both of these behaviors are potentially confusing (and annoying), so websites cannot rely solely on the :invalid selector to indicate that a value entered by the user is not valid. However, there is the option to combine :invalid with :not(:focus) and even :not(:placeholder-shown) to ensure that the page’s “invalid” styles do not apply to the <input> until the user has finished entering the value and moved focus to another element.

The CSS Selectors module defines a :user-invalid pseudo-class that avoids the problems of :invalid by only matching an <input> “after the user has significantly interacted with it.”

Firefox already supports this functionality via the :-moz-ui-invalid pseudo-class (see it in action). Mozilla now intends to un-prefix this pseudo-class and ship it under the standard :user-invalid name. There are still no signals from other browser vendors, but the Chromium and WebKit bugs for this feature have been filed.


Weekly Platform News: Focus Rings, Donut Scope, More em Units, and Global Privacy Control originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/weekly-platform-news-focus-rings-donut-scope-ditching-em-units-and-global-privacy-control/feed/ 3 335856
How We Improved the Accessibility of Our Single Page App Menu https://css-tricks.com/how-we-improved-the-accessibility-of-our-single-page-app-menu/ https://css-tricks.com/how-we-improved-the-accessibility-of-our-single-page-app-menu/#comments Thu, 25 Feb 2021 15:43:54 +0000 https://css-tricks.com/?p=334666 I recently started working on a Progressive Web App (PWA) for a client with my team. We’re using React with client-side routing via React Router, and one of the first elements that we made was the main menu. Menus …


How We Improved the Accessibility of Our Single Page App Menu originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I recently started working on a Progressive Web App (PWA) for a client with my team. We’re using React with client-side routing via React Router, and one of the first elements that we made was the main menu. Menus are a key component of any site or app. That’s really how folks get around, so making it accessible was a super high priority for the team.

But in the process, we learned that making an accessible main menu in a PWA isn’t as obvious as it might sound. I thought I’d share some of those lessons with you and how we overcame them.

As far as requirements go, we wanted a menu that users could not only navigate using a mouse, but using a keyboard as well, the acceptance criteria being that a user should be able to tab through the top-level menu items, and the sub-menu items that would otherwise only be visible if a user with a mouse hovered over a top-level menu item. And, of course, we wanted a focus ring to follow the elements that have focus.

The first thing we had to do was update the existing CSS that was set up to reveal a sub-menu when a top-level menu item is hovered. We were previously using the visibility property, changing between visible and hidden on the parent container’s hovered state. This works fine for mouse users, but for keyboard users, focus doesn’t automatically move to an element that is set to visibility: hidden (the same applies for elements that are given display: none). So we removed the visibility property, and instead used a very large negative position value:

.menu-item {
  position: relative;
}

.sub-menu {
  position: absolute
  left: -100000px; /* Kicking off  the page instead of hiding visiblity */
}

.menu-item:hover .sub-menu {
  left: 0;
}

This works perfectly fine for mouse users. But for keyboard users, the sub menu still wasn’t visible even though focus was within that sub menu! In order to make the sub-menu visible when an element within it has focus, we needed to make use of :focus and :focus-within on the parent container:

.menu-item {
  position: relative;
}

.sub-menu {
  position: absolute
  left: -100000px;
}

.menu-item:hover .sub-menu,
.menu-item:focus .sub-menu,
.menu-item:focus-within .sub-menu {
  left: 0;
}

This updated code allows the the sub-menus to appear as each of the links within that menu gets focus. As soon as focus moves to the next sub menu, the first one hides, and the second becomes visible. Perfect! We considered this task complete, so a pull request was created and it was merged into the main branch.

But then we used the menu ourselves the next day in staging to create another page and ran into a problem. Upon selecting a menu item—regardless of whether it’s a click or a tab—the menu itself wouldn’t hide. Mouse users would have to click off to the side in some white space to clear the focus, and keyboard users were completely stuck! They couldn’t hit the esc key to clear focus, nor any other key combination. Instead, keyboard users would have to press the tab key enough times to move the focus through the menu and onto another element that didn’t cause a large drop down to obscure their view.

The reason the menu would stay visible is because the selected menu item retained focus. Client-side routing in a Single Page Application (SPA) means that only a part of the page will update; there isn’t a full page reload.

There was another issue we noticed: it was difficult for a keyboard user to use our “Jump to Content” link. Web users typically expect that pressing the tab key once will highlight a “Jump to Content” link, but our menu implementation broke that. We had to come up with a pattern to effectively replicate the “focus clearing” that browsers would otherwise give us for free on a full page reload.

The first option we tried was the easiest: Add an onClick prop to React Router’s Link component, calling document.activeElement.blur() when a link in the menu is selected:

const Menu = () => {
  const clearFocus = () => {
    document.activeElement.blur();
  }

  return (
    <ul className="menu">
      <li className="menu-item">
        <Link to="/" onClick={clearFocus}>Home</Link>
      </li>
      <li className="menu-item">
        <Link to="/products" onClick={clearFocus}>Products</Link>
        <ul className="sub-menu">
          <li>
            <Link to="/products/tops" onClick={clearFocus}>Tops</Link>
          </li>
          <li>
            <Link to="/products/bottoms" onClick={clearFocus}>Bottoms</Link>
          </li>
          <li>
            <Link to="/products/accessories" onClick={clearFocus}>Accessories</Link>
          </li>
        </ul>
      </li>
    </ul>
  );
}

This approach worked well for “closing” the menu after an item is clicked. However, if a keyboard user pressed the tab key after selecting one of the menu links, then the next link would become focused. As mentioned earlier, pressing the tab key after a navigation event would ideally focus on the “Jump to Content” link first.

At this point, we knew we were going to have to programmatically force focus to another element, preferably one that’s high up in the DOM. That way, when a user starts tabbing after a navigation event, they’ll arrive at or near the top of the page, similiar to a full page reload, making it much easier to access the jump link.

We initially tried to force focus on the <body> element itself, but this didn’t work as the body isn’t something the user can interact with. There wasn’t a way for it to receive focus.

The next idea was to force focus on the logo in the header, as this itself is just a link back to the home page and can receive focus. However, in this particular case, the logo was below the “Jump To Content” link in the DOM, which means that a user would have to shift + tab to get to it. No good.

We finally decided that we had to render an interact-able element, for example, an anchor element, in the DOM, at a point that’s above than the “Jump to Content” link. This new anchor element would be styled so that it’s invisible and that users are unable to focus on it using “normal” web interactions (i.e. it’s taken out of the normal tab flow). When a user selects a menu item, focus would be programmatically forced to this new anchor element, which means that pressing tab again would focus directly on the “Jump to Content” link. It also meant that the sub-menu would immediately hide itself once a menu item is selected.

const App = () => {
  const focusResetRef = React.useRef();

  const handleResetFocus = () => {
    focusResetRef.current.focus();
  };

  return (
    <Fragment>
      <a
        ref={focusResetRef}
        href="javascript:void(0)"
        tabIndex="-1"
        style={{ position: "fixed", top: "-10000px" }}
        aria-hidden
      >Focus Reset</a>
      <a href="#main" className="jump-to-content-a11y-styles">Jump To Content</a>
      <Menu onSelectMenuItem={handleResetFocus} />
      ...
    </Fragment>
  )
}

Some notes of this new “Focus Reset” anchor element:

  • href is set to javascript:void(0) so that if a user manages to interact with the element, nothing actually happens. For example, if a user presses the return key immediately after selecting a menu item, that will trigger the interaction. In that instance, we don’t want the page to do anything, or the URL to change.
  • tabIndex is set to -1 so that a user can’t “normally” move focus to this element. It also means that the first time a user presses the tab key upon loading a page, this element won’t be focused, but the “Jump To Content” link instead.
  • style simply moves the element out of the viewport. Setting to position: fixed ensures it’s taken out of the document flow, so there isn’t any vertical space allocated to the element
  • aria-hidden tells screen readers that this element isn’t important, so don’t announce it to users

But we figured we could improve this even further! Let’s imagine we have a mega menu, and the menu doesn’t hide automatically when a mouse user clicks a link. That’s going to cause frustration. A user will have to precisely move their mouse to a section of the page that doesn’t contain the menu in order to clear the :hover state, and therefore allow the menu to close.

What we need is to “force clear” the hover state. We can do that with the help of React and a clearHover class:

// Menu.jsx
const Menu = (props) => {
  const { onSelectMenuItem } = props;
  const [clearHover, setClearHover] = React.useState(false);

  const closeMenu= () => {
    onSelectMenuItem();
    setClearHover(true);
  }

  React.useEffect(() => {
    let timeout;
    if (clearHover) {
      timeout = setTimeout(() => {
        setClearHover(false);
      }, 0); // Adjust this timeout to suit the applications' needs
    }
    return () => clearTimeout(timeout);
  }, [clearHover]);

  return (
    <ul className={`menu ${clearHover ? "clearHover" : ""}`}>
      <li className="menu-item">
        <Link to="/" onClick={closeMenu}>Home</Link>
      </li>
      <li className="menu-item">
        <Link to="/products" onClick={closeMenu}>Products</Link>
        <ul className="sub-menu">
          {/* Sub Menu Items */}
        </ul>
      </li>
    </ul>
  );
}

This updated code hides the menu immediately when a menu item is clicked. It also hides immediately when a keyboard user selects a menu item. Pressing the tab key after selecting a navigation link moves the focus to the “Jump to Content” link.

At this point, our team had updated the menu component to a point where we were super happy. Both keyboard and mouse users get a consistent experience, and that experience follows what a browser does by default for a full page reload.

Our actual implementation is slightly different than the example here so we could use the pattern on other projects. We put it into a React Context, with the Provider set to wrap the Header component, and the Focus Reset element being automatically added just before the Provider’s children. That way, the element is placed before the “Jump to Content” link in the DOM hierarchy. It also allows us to access the focus reset function with a simple hook, instead of having to prop drill it.

We have created a Code Sandbox that allows you to play with the three different solutions we covered here. You’ll definitely see the pain points of the earlier implementation, and then see how much better the end result feels!

We would love to hear feedback on this implementation! We think it’s going to work well, but it hasn’t been released to in the wild yet, so we don’t have definitive data or user feedback. We’re certainly not a11y experts, just doing our best with what we do know, and are very open and willing to learn more on the topic.


How We Improved the Accessibility of Our Single Page App Menu originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/how-we-improved-the-accessibility-of-our-single-page-app-menu/feed/ 13 334666
Beautiful accessibility with Floating Focus https://css-tricks.com/beautiful-accessibility-with-floating-focus/ https://css-tricks.com/beautiful-accessibility-with-floating-focus/#comments Mon, 15 Feb 2021 15:38:04 +0000 https://css-tricks.com/?p=334376 Imagine if your :focus styles animated from element to element as you tab through a site. Like the focus ring up and flew across the page to the next element. The spirit of it is similar to smooth scrolling: it’s …


Beautiful accessibility with Floating Focus originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Imagine if your :focus styles animated from element to element as you tab through a site. Like the focus ring up and flew across the page to the next element. The spirit of it is similar to smooth scrolling: it’s easier to understand what is happening when movement accompanies the change¹. Rather than scrolling (or focus change) being an instant jump, movement guides you to the new location.

Guido Bouman thought this would be good for accessibility and looked at some options (e.g. Flying Focus) but ultimately created their own, Floating Focus:

After this exploration we had a good idea of what a good focus state needed. It needs to have a high contrast but not impair readability of the underlying components. It has to guide the user to the next focus target with a form of transition. And it only needs to show for users benefitting from the focus outline.

We’ve covered a similar thing before in 2019 when Maurice Mahan FocusOverlay.

Here’s what I wrote about it back then:

  • It’s a neat effect.
  • I can imagine it being an accessibility win since, while the page will scroll to make sure the next focused element is visible, it doesn’t otherwise help you see where that focus has gone. Movement that directs attention toward the next focused element may help make it more clear.
  • I can imagine it being harmful to accessibility in that it is motion that isn’t usually there and could be surprising and possibly offputting.
  • If it “just works” on all my focusable elements, that’s cool, but I see there are data attributes for controlling the behavior. If I find myself needing to sprinkle behavior control all over my templates to accommodate this specific library, I’d probably be less into it.

In that article, I covered a conditional loading idea for not loading this if prefers-reduced-motion was set to reduce. These days, you might do a conditional ES Modules import.

Don’t take any of this as advice that this movement-based focus stuff is 100% good for accessibility. I don’t feel qualified to make that determination. It is interesting though.

  1. This reminds me of “transitional interfaces” as well. Movement can really help make clear what is happening in a UI.

To Shared LinkPermalink on CSS-Tricks


Beautiful accessibility with Floating Focus originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/beautiful-accessibility-with-floating-focus/feed/ 4 334376
Focus management and inert https://css-tricks.com/focus-management-and-inert/ https://css-tricks.com/focus-management-and-inert/#comments Mon, 19 Oct 2020 13:56:27 +0000 https://css-tricks.com/?p=323076 Many forms of assistive technology use keyboard navigation to understand and take action on screen content. One way of navigating is via the Tab key. You may already be familiar with this way of navigating if you use it to …


Focus management and inert originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Many forms of assistive technology use keyboard navigation to understand and take action on screen content. One way of navigating is via the Tab key. You may already be familiar with this way of navigating if you use it to quickly jump from input to input on a form without having to reach for your mouse or trackpad.

Tab will jump to interactive elements in the order they show up in the DOM. This is one of the reasons why it is so important that the order of your source code matches the visual hierarchy of your design.

The list of interactive elements that are tabbable is:

An interactive element gains focus when:

  • It has been navigated to via the Tab key, 
  • it is clicked on, following an anchor that links to another focusable element,
  • or focus is programmatically set through element.focus() in JavaScript.

Focus is analogous to hovering over an element with your mouse cursor, in that you’re identifying the thing you want to activate. It’s also why visually obvious focus styles are so important.

Focus indication moving through a homepage wireframe. It starts on the logo, moves to products, then services, then careers, blog, contact, and stops on a Learn more button.

Focus management

Focus management is the practice of coordinating what can and cannot receive focus events. It is one of the trickier things to do in front-end development, but it is important for making websites and web apps accessible.

Good practices for focus management

99% of the time, you want to leave focus order alone. I cannot stress this enough. 

Focus will just work for you with no additional effort required, provided you’re using the <button> element for buttons, the anchor element for links, the <input> element for user input, etc.

There are rare cases where you might want to apply focus to something out of focus order, or make something that typically can’t receive focus events be focusable. Here are some guidelines for how to go about it in an accessible, intuitive to navigate way:

Do: learn about the tabindex attribute

tabindex allows an element to be focused. It accepts an integer as a value. Its behavior changes depending on what integer is used.

Don’t: Apply tabindex="0" to things that don’t need it

Interactive elements  that can receive keyboard focus (such as the <button> element) don’t need to have the tabindex attribute applied to them.  

Additionally, you don’t need to declare tabindex on non-interactive elements to ensure that they can be read by assistive technology (in fact, this is a WCAG failure if no role and accessible name is present). Doing so actually creates an unexpected and difficult to navigate experience for a person who uses assistive technology — they have other, expected ways to read this content.

? Do: Use tabindex="-1" for focusing with JavaScript

tabindex="-1" is used to create accessible interactive widgets with JavaScript.

A declaration of tabindex="-1" will make an element focusable via JavaScript or click/tap. It will not, however, let it be navigated to via the Tab key.

? Don’t: Use a positive integer as a tabindex value

This is a serious antipattern. Using a positive integer will override the expected tab order, and create a confusing and disorienting experience for the person trying to navigate your content. 

One instance of this is bad enough. Multiple declarations is a total nightmare. Seriously: don’t do it.

? Don’t: Create a manual focus order

Interactive elements can be tabbed to just by virtue of being used. You don’t need to set a series of tabindex attributes with incrementing values on every interactive element in the order you think the person navigating your site should use. You’ll let the order of the elements in the DOM do this for you instead.

Focus trapping

There may be times where you need to prevent things from being focused. A good example of this is focus trapping, which is the act of conditionally restricting focus events to an element and its children.

Focus trapping is not to be confused with keyboard traps (sometimes referred to as focus traps). Keyboard traps are situations where someone navigating via keyboard cannot escape out of a widget or component because of a nasty loop of poorly-written logic.

A practical example of what you would use focus trapping for would be for a modal:

Focus indication moving through a homepage wireframe and opening a modal to demonstrate focus trapping. Inside the modal are tab stops for the modal container, a video play button, a cancel button, a purchase button, and a close button. After the modal is closed focus is returned to the button that triggered the modal.

Why is it important?

Keeping focus within a modal communicates its bounds, and helps inform what is and is not modal content — it is analogous to how a sighted person can see how a modal “floats” over other website or web app content. This is important information if: 

  • You have low or no vision and rely on screen reader announcements to help communicate the shift in interaction mode.
  • You have low vision and a magnified display, where focusing outside of the bounds of the modal may be confusing and disorienting.
  • You navigate solely via keyboard and could otherwise tab out of the modal and get lost on the underlying page or view trying to get back into the modal.

How do you do it?

Reliably managing focus is a complicated affair. You need to use JavaScript to:

  1. Determine the container elements of all focusable elements on the current page or view.
  2. Identify the bounds of the trapped content, including the first and last focusable item.
  3. Remove both interactivity and discoverability from anything identified as focusable that isn’t within that set of trapped content.
  4. Move focus into the trapped content.
  5. Listen for events that signals dismissing the trapped content (save, cancel, dismissal/hitting the Esc key, etc.).
  6. Dismiss the trapped content area when triggered by a pertinent event.
  7. Restore previously removed interactivity. 
  8. Move focus back to the interactive element that triggered the trapped content. 

Why do we do it?

I’m not going to lie: this is all tricky and time-consuming to do. However, focus management and a sensible, usable focus order is a Web Content Accessibility Guideline. It’s important enough that it’s considered part of an international, legally-binding standard about usability.

Tabbable and discoverable

There’s a bit of a trick to removing both discoverability and interactivity. 

Screen readers have an interaction mode that allows them to explore the page or view via a virtual cursor. The virtual cursor also lets the person using the screen reader discover non-interactive parts of the page (headings, lists, etc.). Unlike using Tab and focus styles, the virtual cursor is only available to people using a screen reader.

When you are managing focus, you may want to restrict the ability for the virtual cursor to discover content. For our modal example, this means preventing someone from accidentally “breaking out” of the bounds of the modal when they’re reading it.

Discoverability can be suppressed via a judicious application of aria-hidden="true". However, interactivity is a little more nuanced.

Enter inert

The inert attribute is a global HTML attribute that would make removing, then restoring the ability of interactive elements to be discovered and focused a lot easier. Here’s an example of how it would work:

<body>
  <div 
    aria-labelledby="modal-title"
    class="c-modal" 
    id="modal" 
    role="dialog" 
    tabindex="-1">
    <div role="document">
      <h2 id="modal-title">Save changes?</h2>
      <p>The changes you have made will be lost if you do not save them.<p>
      <button type="button">Save</button>
      <button type="button">Discard</button>
    </div>
  </div>
  <main inert>
    <!-- ... -->
  </main>
</body>

I am deliberately avoiding using the <dialog> element for the modal due to its many assistive technology support issues.

inert has been declared on the <main> element following a save confirmation modal. What this means that all content contained within <main> cannot receive focus nor be clicked. 

Focus is restricted to inside of the modal. When the modal is dismissed, inert can be removed from the <main> element. This way of handling focus trapping is far easier compared to existing techniques.

Remember: A dismissal event can be caused by the two buttons inside our modal example, but also by pressing Esc on your keyboard. Some modals also let you click outside of the modal area to dismiss, as well.

Support for inert

The latest versions of Edge, Chrome, and Opera all support inert when experimental web platform features are enabled. Firefox support will also be landing soon! The one outlier is both desktop and mobile versions of Safari.

I’d love to see Apple implement native support for inert. While a polyfill is available, it has non-trivial support issues for all the major screen readers. Not great! 

In addition, I’d like to call attention to this note from the inert polyfill project’s README:

The polyfill will be expensive, performance-wise, compared to a native inert implementation, because it requires a fair amount of tree-walking. 

Tree-walking means the JavaScript in the polyfill will potentially require a lot of computational power to work, and therefore slow down the end-user experience. 

For lower power devices, such as budget Android smartphones, older laptops, and more powerful devices doing computationally-intensive tasks (such as running multiple Electron apps), this might mean freezing or crashing occurs. Native browser support means this sort of behavior is a lot less taxing on the device, as it has access to parts of the browser that JavaScript doesn’t. 

Safari

Personally, I am disappointed by Apple’s lack of support for inert. While I understand that adding new features to a browser is incredibly complicated and difficult work, inert seems like a feature Apple would have supported much earlier.

macOS and iOS have historically had great support for accessibility, and assistive technology-friendly features are a common part of their marketing campaigns. Supporting inert seems like a natural extension of Apple’s mission, as the feature itself would do a ton for making accessible web experiences easier to develop.

Frustratingly, Apple is also tight-lipped about what it is working on, and when we can generally expect to see it. Because of this, the future of inert is an open question.

Igalia

Igalia is a company that works on browser features. They currently have an experiment where the public can vote on what features they’d like to see. The reasoning for this initiative is outside the scope of this article, but you can read more about it on Smashing Magazine.

One feature Igalia is considering is adding WebKit support for inert. If you have been looking for a way to help improve accessibility on the web, but have been unsure of how to start, I encourage you to pledge. $5, $10, $25. It doesn’t have to be a huge amount, every little bit adds up.

Unfortunately, inert did not win the Open Prioritization experiment. This means that we are back to not knowing if Apple is working on it, or when we can expect to see it showing up in Safari Technology Preview.

iOS 15.4 will be shipping with support for the inert attribute disabled. This is amazing news, as it signals Apple is working on it.

Wrapping up

Managing focus requires some skill and care, but is very much worth doing. The inert attribute can go a long way to making this easier to do.

Technologies like inert also represents one of the greatest strengths of the web platform: the ability to pave the cowpaths of emergent behavior and codify it into something easy and effective.

Further reading


Thank you to Adrian Roselli and Sarah Higley for their feedback.


Focus management and inert originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/focus-management-and-inert/feed/ 7 https://css-tricks.com/wp-content/uploads/2020/10/focus-navigation.mp4 focus Archives - CSS-Tricks nonadult 323076
The :focus-visible Trick https://css-tricks.com/the-focus-visible-trick/ https://css-tricks.com/the-focus-visible-trick/#comments Fri, 16 Oct 2020 19:12:54 +0000 https://css-tricks.com/?p=323313 Always worth repeating: all interactive elements should have a focus style. That way, a keyboard user can tell when they have moved focus to that element.

But if you use :focus alone for this, it has a side effect that …


The :focus-visible Trick originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Always worth repeating: all interactive elements should have a focus style. That way, a keyboard user can tell when they have moved focus to that element.

But if you use :focus alone for this, it has a side effect that a lot of people don’t like. It means that when you click (with a mouse) on an interactive element, you’ll see the focus style. Arguably, you don’t need that feedback as a mouse user, because you just moved your cursor there and clicked. Whatever you think of that, it’s annoyed so many people over the years that they remove focus styles entirely, which is a gnarly net loss for accessibility on the web.

What if we could apply focus styles only when the keyboard is used to focus something, not the mouse? Lea Verou put a finger on this a few years back:

That was in response to Chrome dropping the feature behind a flag. Clever clever.

Fast forward a couple of years, Chrome is releasing it without a flag. They are on board with Lea’s idea:

By combining :focus-visible with :focus you can take things a step further and provide different focus styles depending on the user’s input device. This can be helpful if you want the focus indicator to depend on the precision of the input device:

/* Focusing the button with a keyboard will show a dashed black line. */
button:focus-visible {
  outline: 4px dashed black;
}
  
/* Focusing the button with a mouse, touch, or stylus will show a subtle drop shadow. */
button:focus:not(:focus-visible) {
  outline: none;
  box-shadow: 1px 1px 5px rgba(1, 1, 0, .7);
}

I might suggest trying those selectors without the button, making them globally applied!

There is more to dig into, so I’ll link up some more stuff here:

  • The Chromium Blog post covers the heuristics of the selector. It’s tricky. It’s like there is an algorithm to determine if :focus-visible is going to match or not, which you just largely need to trust. It also covers the idea that Firefox has long had :-moz-focusring, but the behavior is different enough that they don’t recommend using it if you’re shooting for consistent behavior.
  • Matthias Ott blogged about it with some good info, like using the official polyfill and how to look at the styles properly in DevTools (there is a new checkbox for it).
  • We’ve covered this before. In that, we noted Lea’s tweet that she thought usage would explode when it ships for real. Let’s see (and hope)!
  • Our almanac entry has a bunch of details.


The :focus-visible Trick originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/the-focus-visible-trick/feed/ 9 323313
Using a brightness() filter to generically highlight content https://css-tricks.com/using-a-brightness-filter-to-generically-highlight-content/ https://css-tricks.com/using-a-brightness-filter-to-generically-highlight-content/#comments Fri, 11 Sep 2020 22:29:34 +0000 https://css-tricks.com/?p=320864 Rick Strahl:

I can’t tell you how many times over the years I’ve implemented a custom ‘button’ like CSS implementation. Over the years I’ve used images, backgrounds, gradients, and opacity to effectively ‘highlight’ a control. All that works of


Using a brightness() filter to generically highlight content originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Rick Strahl:

I can’t tell you how many times over the years I’ve implemented a custom ‘button’ like CSS implementation. Over the years I’ve used images, backgrounds, gradients, and opacity to effectively ‘highlight’ a control. All that works of course, but the problem with most of these approaches is that one way or the other you’re hard coding a color value, image, or gradient.

You certainly have a lot more control if you specify exact colors, but if you can pull off brightening, darkening, or even a hue-shift in a way that feels cohesive on your site, it’s certainly a lot less code to maintain,

.button.specific-button {
  background: #4CAF50;
}
.button.specific-button:focus,
.button.specific-button:hover {
  background: #A5D6A7;
}

/* vs. */
.button:focus,
.button:hover {
  filter: brightness(120%);
}

/* or maybe you're super hardcore and do it everywhere */
:focus,
:hover {
  filter: brightness(120%) saturate(120%);
}

To Shared LinkPermalink on CSS-Tricks


Using a brightness() filter to generically highlight content originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/using-a-brightness-filter-to-generically-highlight-content/feed/ 2 320864
Copy the Browser’s Native Focus Styles https://css-tricks.com/copy-the-browsers-native-focus-styles/ https://css-tricks.com/copy-the-browsers-native-focus-styles/#comments Fri, 28 Aug 2020 14:49:08 +0000 https://css-tricks.com/?p=319992 Remy documented this the other day. Firefox supports a Highlight keyword and both Chrome and Safari support a -webkit-focus-ring-color keyword. So if you, for example, have removed focus from something and want to put it back in the same …


Copy the Browser’s Native Focus Styles originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Remy documented this the other day. Firefox supports a Highlight keyword and both Chrome and Safari support a -webkit-focus-ring-color keyword. So if you, for example, have removed focus from something and want to put it back in the same style as the browser default, or want to apply a focus style to an element when it isn’t directly in focus itself, this can be useful.

For example:

button:focus + span {
  outline: 5px auto Highlight;
  outline: 5px auto -webkit-focus-ring-color;
}

Looks good to me. It’s especially helpful with the sorta weird new Chrome double-outline style that would be slightly tricky to replicate otherwise.

Chrome 84
Safari 13.1
Firefox 80


Copy the Browser’s Native Focus Styles originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/copy-the-browsers-native-focus-styles/feed/ 3 319992
Quick Tips for High Contrast Mode https://css-tricks.com/quick-tips-for-high-contrast-mode/ Fri, 26 Jun 2020 22:30:11 +0000 https://css-tricks.com/?p=314409 Sarah Higley has some CSS tricks up her sleeve for dealing with High Contrast Mode on Windows, which I learned is referred to as WHCM.

Here’s the first trick:

[…] if the default CSS outline property doesn’t give you the


Quick Tips for High Contrast Mode originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Sarah Higley has some CSS tricks up her sleeve for dealing with High Contrast Mode on Windows, which I learned is referred to as WHCM.

Here’s the first trick:

[…] if the default CSS outline property doesn’t give you the visual effect you want [in WHCM] for focus states, there’s a very simple fix. Instead of overriding default browser focus styles with outline: none, make it transparent instead: outline 3px solid transparent.

That will essentially do nothing outside of WHCM, but in WHCM, it will be a thick white border, which is a strong, good visual focus style.

To Shared LinkPermalink on CSS-Tricks


Quick Tips for High Contrast Mode originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
314409
Having a Little Fun With Custom Focus Styles https://css-tricks.com/having-a-little-fun-with-custom-focus-styles/ https://css-tricks.com/having-a-little-fun-with-custom-focus-styles/#comments Mon, 02 Dec 2019 15:25:39 +0000 https://css-tricks.com/?p=298874 Every front-end developer has dealt or will deal with this scenario: your boss, client or designer thinks the outline applied by browsers on focused elements does not match the UI, and asks you to remove it. Or you might even …


Having a Little Fun With Custom Focus Styles originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Every front-end developer has dealt or will deal with this scenario: your boss, client or designer thinks the outline applied by browsers on focused elements does not match the UI, and asks you to remove it. Or you might even be looking to remove it yourself.

So you do a little research and find out that this is strongly discouraged, because the focus outline is there for a reason: it provides visual feedback for keyboard navigation (using the Tab key), letting users who can’t use a mouse or have a visual impairment know where they are on the screen.

This button shows a focus state with Chrome’s default outline style.

That doesn’t mean you’re stuck with this outline, though. Instead of removing it, you can simply replace it with something else. That way, you’ll keep your interface accessible and get more flexibility on how it looks, so you can better match your UI.

You can start by removing the default browser outline by selecting the focused state of the element and applying outline: none. Then, you may choose from each of the options ahead to replace it:

Change the background color

This works best for elements that can be filled, such as buttons. Select the focused state of the element and apply a contrasting background color to it. The higher the contrast the better because subtle changes may not be strong enough visual cues, particularly in cases where with color blindness and low-vision.

In the example below, both background and border color change; you may pick either or both.

Click or focus with the Tab key to view how this state looks.

See the Pen
Elements replacing native outline focus with background color
by Lari (@larimaza)
on CodePen.

Change the text color

If the element has any text, you can select the focused state and change its color. This also works for icons applied with mask-image; you can select the icon as a descendant of the focused element and change its background color, like the example button below.

See the Pen
Elements replacing native outline focus with text and icon color
by Lari (@larimaza)
on CodePen.

Again, contrast is key. You may also consider using an underline on text links and making it part of the changed state because, as the Web Content Accessibility Guidelines state:

Color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element. (Level A)
Understanding Success Criterion 1.4.1

Apply a box shadow

The box-shadow property can do exactly the same job as the outline, except it’s much more powerful — you can now control its color, opacity, offset, blur radius and spread radius. And if a border-radius is specified, the box shadow follows the same rounded corners.

See the Pen
Elements replacing native outline focus with box shadow
by Lari (@larimaza)
on CodePen.

You can get really creative with this technique (seriously though, don’t do this):

See the Pen
Elements replacing native outline focus with insane box shadow
by Lari (@larimaza)
on CodePen.

This works for virtually any type of focusable element, like toggles, checkboxes, radio buttons and slides.

See the Pen
Toggle and radio button replacing native outline focus with box shadow
by Lari (@larimaza)
on CodePen.

Increase the element’s size

As an alternative to color change, you may also resort to subtle size modification as focus feedback. In this example, we’re using transform: scale.

See the Pen
Elements replacing native outline focus with transform scale
by Lari (@larimaza)
on CodePen.

The key here is subtlety. Extreme size changes may cause content reflow, not to mention a poor experience for those who prefer reduced motion.

Replicate existing hover styles

If the element already has a contrasting hover style, you can simply take that style and apply it for the focused state as well. This is a rather elegant solution, as you don’t have to add any new colors or outlines to the interface.

Here’s an example where both the focus and hover states adopt a high contrast to the background of an element’s default style:

See the Pen
Elements replacing native outline focus with hover styles
by Lari (@larimaza)
on CodePen.

Bonus: Customize the default outline

Everything we’ve looked at so far takes the assumption that we want to remove the focus outline altogether. We don’t have to! In fact, it’s a border that we can customize.

button:focus {
  outline: 3px dashed orange;
}

That’s shorthand and could have been written this way if we want to fine-tune the styles:

button:focus {
  outline-width: 3px;
  outline-style: dashed;
  outline-color: orange;
}

One additional superpower we have is the outline-offset property, which is separate from the outline shorthand property but can be used alongside it to change the position of the focus ring:

button:focus {
  outline: 3px dashed orange;
  outline-offset: 10px;
}

Conclusion

You can mix and match all of these options to get custom styles that look appropriate for each component type within your interface.

And it’s worth repeating: Don’t forget to use stark color contrasts and other visual cues in addition to color when adopting custom focus states. Sure, we all want an experience that aligns with our designs, but we can adhere to good accessibility practices in the process. The W3C recommends this tool to test the contrast of colors values against the WCAG guidelines.


Having a Little Fun With Custom Focus Styles originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/having-a-little-fun-with-custom-focus-styles/feed/ 9 298874
Weekly Platform News: WebAPK Limited to Chrome, Discernible Focus Rectangles, Modal Window API https://css-tricks.com/weekly-platform-news-webapk-limited-to-chrome-discernible-focus-rectangles-modal-window-api/ Thu, 24 Oct 2019 22:07:56 +0000 https://css-tricks.com/?p=297829 In this week’s roundup: “Add to home screen” has different meanings in Android, Chrome and Edge add some pop to focus rectangles on form inputs, and how third-party sites may be coming to a modal near you.

Let’s get into …


Weekly Platform News: WebAPK Limited to Chrome, Discernible Focus Rectangles, Modal Window API originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In this week’s roundup: “Add to home screen” has different meanings in Android, Chrome and Edge add some pop to focus rectangles on form inputs, and how third-party sites may be coming to a modal near you.

Let’s get into the news.

WebAPKs are not available to Firefox on Android

On Android, both Chrome and Firefox have an “Add to home screen” option, but while Firefox merely adds a shortcut for the web app to the user’s home screen, Chrome actually installs the web app (as long as it meets the PWA install criteria) via a WebAPK.

Progressive Web Apps installed in such a way are added to the device’s app drawer, and URLs that are within the PWA’s scope (as specified in its manifest) open in the PWA instead of the default browser.

Tiger Oakes who is implementing PWA-related features at Mozilla, explains why Firefox cannot install PWAs on Android: “WebAPK is not available to us since we don’t own an app store like Google Play and Galaxy Apps.”

(via Tiger Oakes)

More accessible focus rectangles are coming to Chrome and Edge

Microsoft and Google have made accessibility improvements to various form controls. The two main changes are the larger touch targets on the time and date inputs, and the redesigned focus rectangles that are now easily discernible on any background.

The updated form controls are available in the preview version of Edge. Mac users may have to manually enable the “Web Platform Fluent Controls” flag on the about:flags page.

(via Microsoft Edge Dev)

A newly proposed API for loading third-parties in modal windows

The proposed Modal Window API would allow a website to load another website in a modal window (in a top-level browsing context) for the purposes of authentication, payments, sharing, access to third-party services, etc.

Only a single modal window would be allowed at a time, and the two websites could communicate with each other via message events (postMessage method).

This API is intended as a better alternative to existing methods, such as pop-ups, which can be confusing to users and blocked by browsers, and redirects, which cause the original context to be torn down and recreated (or completely lost in the case of an error in the third-party service).

(via Adrian Hope-Bailie)

More news…

Read even more news in my weekly Sunday issue that can be delivered to you via email every Monday morning.

More News →


Weekly Platform News: WebAPK Limited to Chrome, Discernible Focus Rectangles, Modal Window API originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
297829
:focus-visible https://css-tricks.com/almanac/selectors/f/focus-visible/ Fri, 11 Jan 2019 18:45:42 +0000 http://css-tricks.com/?page_id=281230 The :focus-visible pseudo-class (also known as the “Focus-Indicated” pseudo-class) is a native CSS way to style elements that:

  1. Are in focus
  2. Need a visible indicator to show focus (more on this later)

:focus-visible is used similarly to :focus: to …


:focus-visible originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The :focus-visible pseudo-class (also known as the “Focus-Indicated” pseudo-class) is a native CSS way to style elements that:

  1. Are in focus
  2. Need a visible indicator to show focus (more on this later)

:focus-visible is used similarly to :focus: to bring attention to the element that currently has the focus.

.element:focus-visible {
  background-color: pink; /* Something to get the user's attention */
}

:focus-visible is part of the CSS4 Selectors working draft. Prior to adoption, Mozilla introduced the :-moz-focusring pseudo-class to bring the functionality to Firefox ahead of a formal specification.

Why do we need :focus-visible?

Doesn’t :focus do this already? Yes, but there are problems. The clearest illustration is a button that fires some JavaScript. Imagine an image carousel with buttons to swap between images. Let’s say you’ve added a tabindex to the buttons so they can be selected with a keyboard, but when you go to test the carousel with your mouse, you see this outline around your gorgeous button:

Outline added by the browser on :focus

Not that you would want to do this (for accessibility concerns), but how do you get rid of it? By setting the :focus pseudo-class:

.next-image-button:focus {
  outline: none;
}

Now your button looks great when it is in focus, but what happens when a user tabs to your button without a mouse but a keyboard instead? They can’t see where they’ve tabbed! That’s a problem because now there’s no way to tell which button is focused for keyboard actions:

One of these is focused, but you can’t see it!

Is there a way to remove the blue focus outline but still show a focus that’s more in line with the site design? Sure, you can have your cake and eat it too, thanks to :focus-visible!

:focus-visible only applies when you actually want a visual indicator to help the user see where the focus is. In other words, it can’t hide the outline like :focus can. (Well, it could by blending it into the design, but whatever.) The two have to be used together in that sense. Let’s add one to our button:

.next-image-button:focus {
  outline: none;
}
.next-image-button:focus-visible {
  outline: 3px solid blanchedalmond; /* That'll show 'em */
}

Now, when the keyboard is used to tab to the button, there will be a visual indication of the focus:

:focus-visible makes focus visible!

How do browsers determine when something is :focus-visible?

Browsers are given a bit of leeway to determine when this pseudo-selector should be applied to a given element using their own heuristics. First, let’s look at the CSS4 working draft, and then we’ll try to break it down. From the specifications:

  • If a user has expressed a preference (such as via a system preference or a browser setting) to always see a visible focus indicator, the user agent should honor this by having :focus-visible always match on the active element, regardless of any other factors. (Another option may be for the user agent to show its own focus indicator regardless of author styles.)
  • Any element which supports keyboard input (such as an input element, or any other element which may trigger a virtual keyboard to be shown on focus if a physical keyboard is not present) should always match :focus-visible when focused.
  • If the user interacts with the page via the keyboard, the currently focused element should match :focus-visible (i.e. keyboard usage may change whether this pseudo-class matches even if it doesn’t affect :focus).
  • If the user interacts with the page via a pointing device, such that the focus is moved to a new element which does not support user input, the newly focused element should not match :focus-visible.
  • If the active element matches :focus-visible, and a script causes focus to move elsewhere, the newly focused element should match :focus-visible.
  • Conversely, if the active element does not match :focus-visible, and a script causes focus to move elsewhere, the newly focused element should not match :focus-visible.

If that’s a little abstract, here’s an interpretation:

SituationDoes :focus-visible apply?
The user says they always want the focus to be visible via a settingYes
An element needs a keyboard to function (like text <inputs>)Yes
The user is navigating with a keyboardYes
The user is navigating with a pointing device (like a mouse or finger on a touchscreen)No
A script causes focus to move from a :focus-visible element to another elementYes
A script causes focus to move from a non-:focus-visible element to another elementNo

It bears repeating: These are guidelines, and browsers will be able to make their own determination about what is selected by :focus-visible. We can expect that the obvious case of keyboard navigation will be handled in a predictable way, but the browsers have the ability to make the determination themselves, like any other feature.

Browser support

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

ChromeFirefoxIEEdgeSafari
864*No8615.4

Mobile / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
12312412315.4

Additional information


:focus-visible originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
281230