The team at Figma has created a new resource for “learning, creating and evangelizing design systems” called Design Systems that already has a good collection of interviews and articles by some folks thinking about these things.
I particularly liked Jeroen Ransijn’s post on how to convince your company it’s ready for a design system, where he writes:
Building a design system is not about reaching a single point in time. It’s an ongoing process of learning, building, evangelizing and driving adoption in your organization.
Jetpack is an official WordPress plugin directly from Automattic. It’s an interesting plugin in that it doesn’t just do *one thing* — it does a whole slew of things that enhance what your WordPress site can do. *Any* WordPress site, that is, and often with extremely little effort. Those easy win features Jesse Friedman calls light switch features, meaning you literally flip a switch in Jetpack’s settings and start benefitting. I love that.
There are dozens of features in Jetpack, and I personally make use of most of them and see the benefit in all of them. Allow me to share with you five of my favorites and how they are actively used right here on this site. It’s actually a bit hard to pick, so perhaps I’ll do this again sometime!
1) Related Posts
This seems like such a simple little feature, but it’s anything but. Something has to analyze all the content on your site and figure out what is most related to the current content. That kind of thing can be incredibly database intensive and bring even powerful hosting to its knees. WP Engine, by all accounts a powerful and WordPress-tuned host, bans many of them outright:
Almost all “Related Posts” plugins suffer from the same fundamental problems regarding MySQL, indexing, and search. These problems make the plugins themselves extremely database intensive.
Jetpack handles this by offloading the work off your servers and onto theirs. Your site has no additional load for this super useful feature. I find it does a great job.
I’m quite serious about that. I’ve been involved with far too many sites where old content was mired with old crufty HTML or otherwise formatted in a way that held them back, and cleaning up that content was an impractically large job. You avoid that situation entirely if you create your content in Markdown (and stick to Markdown syntax).
Things like <span style="font-weight: bold; font-family: Georgia; color: red;"> around seemingly random sentences. <div class="content-wrap-wrap"> wrapping every single blog post because it was just “what you did”. Images force-floated to the right because that made sense three designs ago. Headers with class names on them that don’t even exist anymore. Tables of data spit into content with all the whitespace stripped out and weird alignment attributes you barely recognize. An about page that was pasted in from Microsoft Word.
Content like this will not and cannot last.
With Jetpack, you flip on Markdown support and you’re good!
Almost more importantly, it feels like the Markdown option you can trust. There are other plugins out there that add Markdown support, and that’s great, but they leave open questions. How long is the plugin going to be supported? What variety of Markdown did they pick? Is that variety going to continue to be supported? Does it work in comments? These kind of questions make me nervous.
Choosing Jetpack feels safe because it’s the official Markdown choice of WordPress, in a plugin we can be sure will be updated forever.
It’ll be interesting to see what Markdown + Gutenberg is like!
3) Social Sharing
This is a multi-pronged feature.
One, it can easily add sharing buttons to your posts. This isn’t a particularly difficult thing to do for any developer worth their salt, but having it abstracted away in a plugin is nice.
Two, it can share your posts directly to social sites like Twitter and Facebook. That’s a much harder thing to write from scratch. It’s a thing I used a paid third-party service for years. It was a pleasant surprise when I discovered Jetpack’s ability to do this.
The „official” buttons can be nice as they have the most integrated functionality with the services themselves, but I dig that the other options are like „Responsible Social Sharing Links” in that they have the least possible performance overhead.
It allows you to customize the mesasge, and does smart stuff like includes the Featured Image as image attached to the social post.
4) Comment Improvements
I’m a little uncomfortable using a third-party comment system on my sites. I like control. Comments are content and I like making sure those are in my own database. Yet, I think users have a little higher expectations of comment thread UX than they used to. Having to manually type in your name and email and all that feels kinda old school in a not-so-great way.
Fortunately, Jetpack can replace your comment form with a modernized version:
Now users can log in with their social accounts, making leaving a comment a much easier flow. Not to mention the fact that it’s all the less work you have to do styling the comment form.
Notice the „Notify me of new comments via email” checkbox there too. Guess what powers that? Jetpack. That’s a nice feature for people who are leaving question-style comments on your site. They very likely want to be notified of about the conversations happening in comments as it evolves.
5) Security
I’ve been deep into the world of web development for many years. The more I know, the more I can see that I don’t know. We all have to focus on certain things to get done what we need to on our own journeys. I fully admit I know very little about server-side web security. I’d rather leave that exertise to others, or ideally, software that I trust.
Here’s some fun statistics from here on CSS-Tricks:
It’s nice to know my site is being protected that way from malicious logins. Spam, an even more direct problem, is also taken care of by Akismet, the spam-blocking plugin that my Jetpack subscription covers.
Should anything happen to the site, I know it’s backed up off my server by VaultPress, which is also part of my Jetpack subscription.
See how much it does!?
Again, this is just a handful of the features of Jetpack. There are so many niceties tucked into it I consider it a no-brainer plugin. Probably the first and most important plugin you’ll install on any self-hosted WordPress site.
Clever microsite from Burke Holland and Sarah Drasner that highlights some of VS Code’s coolest features. All fifteen of them are pretty darn cool. Here’s a few other compelling features I’ve seen people use/love:
Personally, I’m still on Sublime. I gave VS Code the college try last year but failed. I can’t even remember why now, which means it’s probably about time to try again. If it was slowness, maybe it was because I was using too many add-ons.
Plus, for better or worse, people like having links that are styled to match the look of other true buttons on the site
<a href="#0" class="button">Button</a>
One challenge is getting all those elements to look and layout exactly the same. We’ll cover that a few ways.
Another challenge is getting people to use them correctly
This is a bit surprising to me — but I hear it often enough to worry about it — is that more and more developers are using <div>s for buttons. As in, they just reach for whatever generic, styling-free HTML is handy and build it up as needed. Andy Bell explains why a real button is better:
So, <button> elements are a pain in the butt to style right? That doesn’t mean you should attach your JavaScript events to a <div> or an <a href="#"> though. You see, when you use a <button>, you get keyboard events for free. You’re also helping screen reader users out because it’ll announce the element correctly.
And here’s Andy again helping you out with a chunk of CSS that’ll get you a cleanly styled button:
It’s that styling that just might be the mental roadblock
It’s a bit understandable. Buttons are weird! They have a good amount of default styling (that come from the „User Agent Stylesheet”) that varies from browser to browser and means you have work to do to get them exactly how you want.
See all the weirdness there?
Without any styling, the button is kinda little and has that native border/border-radius/box-shadow thing going on.
Just by setting the font-size, we lose all those defaults, but it’s got a new default look, one with a border and square corners, a gradient background, and no box-shadow. This is essentially -webkit-appearance: button;.
Buttons have their own font-family, so don’t inherit from the cascade unless you tell it to.
Here’s Chrome’s user agent stylesheet for buttons:
Firefox behaves a bit differently. See in the video above how setting border: 0; removed the border in Chrome, but also the background? Not the case in Firefox:
I only point this out to say, I get it, buttons are truly weird things in browsers. Factor in a dozen other browsers, mobile, and the idea that we want to style all those different elements to look exactly the same (see the opening of the article), and I have a modicum of empathy for people wanting to avoid this.
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
I was a tiny bit surprised to see WTF, Forms? not cover buttons, only because of how much weirdness there is. But the form elements that project whips into shape are even more notoriously difficult!
A Style-Testing Kinda Thingy
I feel like the answer to this is basically a big ol’ block of CSS. That’s what Andy provided, and you could very likely come to one on your own by just being a little heavier handed than the usual of setting style rules with your buttons.
Still, I felt compelled to make a little tester machine thingy so you can toggle styles on and off and see how they all go together in whatever browser you happen to be in:
The biggest point here is to use the correct native elements, as you get a bunch of functionality and accessibility for free. But you might as well get the styling right, too!
Warning: Be careful when marking up links with the button role. Buttons are expected to be triggered using the Space key, while links are expected to be triggered through the Enter key. In other words, when links are used to behave like buttons, adding role="button" alone is not sufficient. It will also be necessary to add a key event handler that listens for the Space key in order to be consistent with native buttons.
You don’t need role="button" on <button> because they are already buttons, but if you’re going to make any other element button-like, you have more work to do to mimic the functionality.
Plus, don’t forget about :hover and :focus styles! Once you’ve wrangled in the styles for the default state, this shouldn’t be so hard, but you definitely need them!
I find the concept of subgrid a little hard to wrap my mind around.
I do understand the idea that we want to use nested semantic markup as we like and have elements participate in one grid so we don’t have to flatten our markup just for layout reasons. But that is largely handled by display: contents;.
Rachel Andrew explains it in a way that finally clicked for me:
I have an item spanning three column tracks of the grid, it is also a Grid Container with three column tracks – however these do not line up with the tracks of the parent…
If the nested grid columns were to be defined as a subgrid, we would use the subgrid value of grid-template-columns on that child element. The child would then use the three column tracks that it spanned, and its children would lay out on those tracks.
It’s not that the parent disappears, it’s that it shares grid lines with the parent so that getting internal elements to line up with everything else happens naturally.
An institution’s motto, an artist’s intro, a company’s tagline, a community’s principle, a service’s greeting… all of them have one thing in common: they’re one brief paragraph displayed on a website’s home page — or at least the about page!
It’s rare that just one word or one line of text welcomes you to a website. So, let’s look at some interesting ways we could style the lines of a paragraph.
To see how things currently are, let’s try giving borders to all the lines of some text in an inline span and see how it looks:
<p><span>Hummingbirds are birds from...</span></p>
The edges appear broken, which they technically are, as the inline box has been fragmented into multiple lines. But we can fix those broken edges with box-decoration-break!
The box-decoration-break property in CSS can decorate the edges of fragments of a broken inline box (as well as of a page, column, and region boxes).
Its value, clone, does that with the same design that appears in the box’s unbroken edges, and its default value, slice, does not copy the decorations at the edges, keeping the break very visible like you saw in the demo above.
The property affects not only the border but also the shadow, spacing, and background of the broken edges.
Let’s play with the background first. While writing the post on knockout text, I was working with the background-clip property and wanted to see if the design held up for multiple lines of text. It didn’t.
The background gradient I applied was not replicated in every line, and after clipping it, only the first one was left with a background. That is, unless box-decoration-break: clone is added:
The background-clip property with the text value clips a background to the shape of its foreground text. Since we used box-decoration-break, the gradient background is shown and clipped uniformly across all the lines of the text.
Going back to the border, let’s see how its shape and shadow can be copied across the broken edges, along with padding:
<img src="tree.png">
<p><span>Supertrees are tree-like structures...</span></p>
<img src="tree.png">
<p><span>Supertrees are tree-like structures...</span></p>
In the second paragraph of the demo, the background is cropped until the content box (background-clip: content-box). As you can see, the crop happens in the broken edges as well, because of box-decoration-break: clone.
Another way we can style borders is with images. You might see a gradient border around the lines of text below, covering the broken edges, if the browser you’re now using supports border-image and the application of box-decoration-break over its result.
<p><span>The Malaysia–Singapore Second Link...</span></p>
An additional behavior we can tap into for decorating individual lines is of outline’s. In supported browsers, box-decoration-break can add an outline to every line of the text, including the broken edges, which is useful for creating bicolored dashed borders.
As observed in the demo, box-decoration-break withstands animation.
Besides borders and backgrounds, box-decoration-break can also manage shapes applied over elements. There is not much use for it in inline boxes, and is maybe better used in a column or page box, although the application is not yet widely supported in browsers.
But to show an example of what that does, let’s try applying the clip-path property to the span.
The property clip-path itself is only fully supported by Firefox, so only in it you might see an expected outcome. But following are two images: the results of applying a circular clip path over the span, without and with box-decoration-break.
span {
clip-path: circle(50% at 202.1165px 69.5px);
...
}
Circular clip-path on a span with box-decoration-break: clone
You’ll notice in the first image that the 50% radius value is derived from the width of the inline box (the longest line) where box-decoration-break is not used.
The second image shows how box-decoration-break: clone redefines the computed value for 50% by basing them on the widths of the individual lines while keeping the center same as before.
And here’s how the inset function of clip-path (an inset rectangle) applied over the span clips it without and with box-decoration-break:
Inset clip-path on a span with box-decoration-break: clone
Without box-decoration-break, only a portion of the first line that matches the length of the shortest is visible, and with box-decoration-break: clone, the first line is fully visible while the rest of the box is clipped.
So, maybe if you ever want to show only the first line and hide the rest, this can come in handy. But, as I mentioned before, this application is more suitable for other types of boxes than ones that are inline. Either way, I wanted to show you how it works.
Browser Support
As we’ve seen here, box-decoraton-break can be super useful and opens up a lot of possibilities, like creating neat text effects. The property enjoys a lot support with the -webkit prefix, but is still in Working Draft at the time of this writing and lacks any support in Internet Explorer and Edge. Here’s where you can vote for Edge 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
Chrome
Opera
Firefox
IE
Edge
Safari
69*
11
32
No
No
TP*
Mobile / Tablet
iOS Safari
Opera Mobile
Opera Mini
Android
Android Chrome
Android Firefox
11.3*
11
all
62*
66*
57
Wrapping Up
The box-decoration-break: clone copies any border, spatial, and background designs applied on a fragmented inline box’s unbroken edges to its broken ones. This creates an even design across all the lines of the text, decorating them uniformly and can be super useful for all those blurbs of text that we commonly use on websites.
Jonathan Snook on the complexity of animating the <progress> element. If you’re unfamiliar, that’s the element that spits out a bar chart-like visual that indicates a position between two values:
This example has custom styles, but you get the point.
Jonathan’s post shows off a method for animating a change in progress value using CSS and a touch of JavaScript while making sure that it animates properly in every modern browser. The demo he made looks pretty neat. I’m sure this is going to be one of those posts I come back to again and again.
Or the priority navigation pattern, or progressively collapsing navigation menu. We can name it in at least three ways.
There are multiple UX solutions for tabs and menus and each of them have their own advantages over another, you just need to pick the best for the case you are trying to solve. At design and development agency Kollegorna we were debating on the most appropriate UX technique for tabs for our client’s website…
We agreed it should be a one-liner because the amount of tab items is unknown and narrowed our options down to two: horizontal scroll and adaptive with “more” button. Firstly, the problem with the former one is that horizontal scroll as a feature is not always visually obvious for users (especially for narrow elements like tabs) whereas what else can be more obvious than a button (“more”), right? Secondly, scrolling horizontally using a mouse-controlled device isn’t a very comfortable thing to do, so we might need to make our UI more complex with additional arrow buttons. All considered, we ended up choosing the later option:
Planning
The main intrigue here is if it’s possible to achieve that without JavaScript?Partly yes, however the limitations that it comes with probably make it only good for a concept museum rather than real life scenarios (anyway, Kenan did a really nice job). Still, the dependency on JS doesn’t mean we can’t make it usable if for some reason the technology is not available. Progressive enhancement and graceful degradation for the win!
Since the amount of tab items is uncertain or volatile, we will make use of Flexbox which ensures the items are nicely spread in the container element without setting the widths.
Initial Prototype
There are two lists both visually and technically: one is for items that fit in the container, and one for items that don’t. Since we’ll depend on JavaScript, it’s totally fine to have our initial markup with a single list only (we will duplicate it with JS):
With a tiny touch of flex-based CSS things are starting to get serious here. I’ll skip the decorative CSS properties in my examples here and place here what really matters:
Now before enhancing it progressively with JavaScript, let’s make sure it degrades gracefully if there is no JS available. There multiple of reasons for JS absence: it’s still loading, it has fatal errors, it failed to be transferred over the network.
And once JavaScript is here, the --jsfied class name is added to the container element which neutralizes the CSS above:
container.classList.add('--jsfied')
Turns out the horizontal scroll strategy that I mentioned before might make a fine use here! When there’s not enough room for menu items the overflowing content gets clipped inside the container and scrollbars are displayed. That’s way better than empty space or something that’s broken, isn’t it?
Missing Parts
First off, let’s insert the missing DOM parts:
Secondary (dropdown) list which is a copy of the main list;
Here we are nesting secondary list into primary and using some aria-* properties. We want our navigation menu to be accessible, right?
There’s also an event handler attached to the „more” button that toggles the --show-secondary class name on the container element. We’ll use it to show and hide the secondary list. Now let’s style the new parts. You may want to visually accent „more” button.
Obviously, we need some code that hides and shows the tabs…
Hiding and Showing Tabs in the Lists
Because of Flexbox, the tab items will never break into multiple lines and will shrink to their minimum possible widths. This means we can walk through the each item one by one, add up their widths, compare it to the width of .tabs element and toggle the visibility of particular tabs accordingly. For that we will create a function called doAdapt and wrap in the code below in this section.
To begin width, we should visually reveal all the items:
On a side note, .--hidden works the way you’ve probably expected:
.tabs .--hidden {
display: none;
}
Math time! I’ll have to disappoint you if you expected some advanced mathematics. So, as described previously, we walk through the each primary tab by adding up their widths under stopWidth variable. We also perform a check if the item fits in the container, hide the item if not and save its index for later use.
Hereafter, we need to hide the equivalent items from the secondary list that remained visible in the primary one. As well as hide “more” button if no tabs were hidden.
I could probably end my article here, but there is an extra mile we can walk to make it better and some things to note…
Enhancements
It has been implemented in the demo above, but we haven’t overviewed a small detail that improves the UX of our tabs widget. It’s hiding the dropdown list automatically if user clicks anywhere outside the list. For that we can bind a global click listener and check if the clicked element or any of its parents is the secondarylist or „more” button. If not, the dropdown list gets dismissed.
document.addEventListener('click', (e) => {
let el = e.target
while(el) {
if(el === secondary || el === moreBtn) {
return;
}
el = el.parentNode
}
container.classList.remove('--show-secondary')
moreBtn.setAttribute('aria-expanded', false)
})
Edge Cases
Long Tab Titles
You might have been wondering how the widget behaves with long tab titles. Well, you have at least two options here…
Let titles wrap to the next line which is how they behave by default (you can also enable word wrapping with word-wrap: break-word):
Or you can disable all kinds of wrapping in the primary list with white-space: nowrap. The script is flexible enough to put the too-long items to the dropdown (where the titles are free to wrap) by stepping aside the shorter siblings:
Many Tabs
Even though the secondary list is position: absolute it doesn’t matter how long your document’s height is. As long as the container element or its parents are not position: fixed, the document will adapt and the bottom items will be reachable by scrolling down the page.
A Thing to be Aware Of
Things may become tricky if the tabs are buttons rather than anchors semantically, which means their response to clicks are decided by JavaScript, e.g.: dynamic tabs. The problem here is that tab button event handlers aren’t duplicated along with the markup. I see at least two approaches to solve that:
Place dynamic event handler attachments right after the adaptive tab code;
Use an event delegation method instead (think of jQuery’s live()).
Unfortunately, events occur in quantity: most likely your tabs will have a selected state that visually indicates the current tab so it’s also important to manage the states simultaneously. Otherwise, flip the tablet and you’re lost.
Browser Compatibility
Even though I used ES6 syntax in the examples and demo, it should be converted to ES5 by a compiler such as Babel to significantly widen the browser support (down to IE9 including).
You can also expand the Flexbox implementation with an older version and syntax (all the way down to IE10). If you need to also support non-Flexbox browsers you can always do feature detection with CSS @supports, apply the technique progressively, and rely on horizontal scroll for older browsers.
Roel Nieskens released a tool that lets you upload a font file and see what’s inside, from how many characters it contains to the number of languages it supports. Here’s what you see once you upload a font, in this case Covik Sans Mono Black:
Why is this data useful? Well, I used this tool just the other day when I found a font file in a random Dropbox folder. What OpenType features does this font have? Are there any extra glyphs besides the Roman alphabet inside? Wakamai Fondue answered those questions for me in a jiffy.
CSS is getting increasingly powerful, and with features like CSS grid and custom properties (also known as CSS variables), we’re seeing some really creative solutions emerging. Some of those solutions focus around not only making the web prettier, but making it more accessible, and making styling accessible experiences better. I’m definitely here for it!
A common UI pattern that we see on the web are dropdown menus. They’re used to display related information in pieces, without overwhelming the user with buttons, text, and options. Somewhere that we see these a lot is inside of headers or navigation areas on websites.
A Google search for „dropdown menu” yields many examples
Let’s see if we can make one of these menus with CSS alone. We’ll create a list of links within a nav component like so:
We now have our two-tiered navigation system. In order to have the content hidden and displayed when we want it to be visible, we’ll need to apply some CSS. All style properties have been removed from the following example for clarity on interaction:
li {
display: block;
transition-duration: 0.5s;
}
li:hover {
cursor: pointer;
}
ul li ul {
visibility: hidden;
opacity: 0;
position: absolute;
transition: all 0.5s ease;
margin-top: 1rem;
left: 0;
display: none;
}
ul li:hover > ul,
ul li ul:hover {
visibility: visible;
opacity: 1;
display: block;
}
ul li ul li {
clear: both;
width: 100%;
}
Now, the submenu dropdown is hidden, but will be exposed and become visible when we hover over its correlating parent in the navigation bar. By styling ul li ul, we have access to that submenu, and by styling ul li ul li, we have access to the individual list items within it.
The Problem
This is starting to look like what we want, but we’re still far from finished at this point. Web accessibility is a core part of your product’s development, and right now would be the perfect opportunity to bring this up. Adding role="navigation" is a good start, but in order for a navigation bar to be accessible, one should be able to tab through it (and focus on the proper item in a sensible order), and also have a screen reader accurately read out loud what is being focused on.
You can hover over any of the list items and clearly see what is being hovered over, but this isn’t true for tab navigation. Go ahead and try to tab through the example above. You lose track of where the focus is visually As you tab to Two in the main menu, you’ll see a focus indicator ring, but when you tab to the next item (one of its submenu items), that focus disappears.
Now, it’s important to note that theoretically you are focused on this other item, and that a screen reader would be able to parse that, reading Sub-One, but keyboard users will not be able to see what’s going on and will lose track.
The reason this happens is because, while we’re styling the hover of the parent element, as soon as we transition focus from the parent to one of the list items within that parent, we lose that styling. This makes sense from a CSS standpoint, but it’s not what we want.
Luckily, there is a new CSS pseudo class that will give us exactly what we want in this case, and it’s called :focus-within.
The Solution: `:focus-within`
The :focus-within pseudo selector is a part of the CSS Selectors Level 4 Spec and tells the browser to apply a style to a parent when any of its children are in focus. So in our case, this means that we can tab to Sub-One and apply a :focus-within style along with the :hover style of the parent and see exactly where we are in the navigation dropdown. In our case it would be ul li:focus-within > ul:
ul li:hover > ul,
ul li:focus-within > ul,
ul li ul:hover {
visibility: visible;
opacity: 1;
display: block;
}
Now, when we tab to the second item, our submenu pops up, and as we tab through the submenu, the visibility remains! Now, we can append our code to include :focus states alongside :hover to give keyboard users the same experience as our mouse users.
In most cases, such as on direct links, we usually can just write something like:
a:hover,
a:focus {
...
}
But in this case, since we’re applying hover styles based on the parent li, we can again utilize :focus-within to get the same look at feel when tabbing through. This is because we can’t actually focus on the li (unless we add a tabindex="0"). We’re actually focusing on the link (a) within it. :focus-within allows us to still apply styles to the parent li when focusing on the link (pretty darn cool!):
li:hover,
li:focus-within {
...
}
At this point, since we are applying a focus style, we can do something that’s typically not recommended (remove the styling of that blue outline focus ring). We can do this by:
li:focus-within a {
outline: none;
}
The above code specifies that when we focus within list items via the link (a), do not apply an outline to the link item (a). It’s pretty safe to write it this way, because we’re exclusively styling the hover state, and with browsers that do not support :focus-within, the link will still get a focus ring. Now our menu looks like this:
Final menu using :focus-within, :hover states, and customizing the focus ring to disappear
If you’re familiar with accessibility, you may have heard of ARIA labels and states. You can use these to your advantage to also create these types of dropdowns with built-in accessibility at the same time! You can find an excellent example here by Heydon Pickering. When including ARIA markup, your code would look a little more like this:
You’re adding aria-haspopup="true" to the parent of the dropdown menu to indicate an alternative state, and including aria-label="submenu" on the actual dropdown menu itself (in this case our list with class="dropdown".
These properties themselves will give you the functionality you need to show the dropdown menu, but the downside is that they only work with JavaScript enabled.
Browser Support Caveat
Speaking of caveats, let’s talk about browser support. While :focus-within does have pretty good browser support, it’s important to note that Internet Explorer and Edge are not supported, so your users on those platforms will not be able to see the navigation.
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
Chrome
Opera
Firefox
IE
Edge
Safari
60
47
52
No
No
10.1
Mobile / Tablet
iOS Safari
Opera Mobile
Opera Mini
Android
Android Chrome
Android Firefox
10.3
No
No
No
64
57
The ultimate solution here would be to use both ARIA markup and CSS :focus-within to ensure a solid dropdown experience for your users.
If you want to be able to use this feature in the future, please upvote it on Edge User Voice! And upvote :focus-ring while you’re at it, so that we’ll be able to style that focus ring and create a beautiful interactive web experience for all 😀
More on `:focus-within` and A11Y
Scott O’Hara wrote about :focus-within, highlighting demos like highlighted <table> rows and dropdown menus