增强焦点可见度 - 焦点 - 焦点或具有(:focus)?
#css #网络开发人员 #教程 #a11y

以前,我们已经看到如何使用CSS :focus:focus-visible伪级在焦点模式下样式元素,以提高可访问性。如果我们想在父母的孩子聚焦并在拥挤的页面上为用户的可见度更加出色时,该怎么样,该怎么办?我们有什么选择?

让我们在本文中找出答案,从:focus-within伪级开始。

表中的内容

使用:焦点 - 伪级

虽然:focus pseudo-class用于在焦点模式下选择一个元素时,:focus-within用于在dom树中选择该元素的祖先。简而言之,:focus-within将匹配其嵌套元素之一的任何元素(匹配:focus)。

让我们看一个搜索框的示例,其中我们有两个层次的嵌套。第一级是带有search-container类的div,第二个是label元素。

<div class="search-container">
    <label>
        Search a title
        <input 
           type="text" 
           placeholder="Search" 
           id="search-box" 
         />
    </label>
    <div>
        <button class="clear-btn">Clear</button>
        <button class="search-btn">Search</button>
    </div>
</div>

然后,我们将search-container类添加到顶级div:focus-within,并在label元素的:focus-within中添加一些大纲,如下:

.search-container:focus-within {
    outline: 2px solid rgba(66, 153, 225, 0.5);
    outline-offset: 5px;
}

label:focus-within {
    font-weight: 600;
}

这样,当我们专注于label中的input元素时,标签文本变为粗体,并且具有search-container类的顶级div的轮廓变得可见。当我们专注于按钮时,通过单击它们或使用Tab键,我们将看到只有带有class search-container的顶级div改变了其轮廓样式:

Different styles when focusing on input, and when focusing on buttons

要调试:focus-within的样式,我们可以前往DevTools,检查所需的元素并切换元素的:focus-within状态,该元素在Styles Tab -:hov部分下列出。我们还可以按照相同的方法切换孩子的:focus状态,并查看父母的样式如何变化:

Toggle focus-within state in the dev tools

现在我们了解了:focus-within伪级,让我们看看我们是否可以使用:has() pseudo-class实现相同的结果。

使用:has()伪级用于焦点

:has()是一个功能性伪级,接受相对选择器作为输入的列表。如果该元素有一个孩子(或后代),它允许我们选择和样式元素,该元素使用以下语法匹配给定的选择器列表:

:has(<selectors-list>) {
    /* styles */
}

例如,使用我们以前的搜索框,我们希望使用class search-container的顶级div样式,如果它具有与以下条件相匹配的子元素:

  • 孩子有一个班级名称,clear-btn
  • 孩子是焦点模式

我们可以使用:has()伪级来完成上述任务,如下所示:

.search-container:has(.clear-btn:focus) {
    outline: 2px solid rgba(66, 153, 225, 0.5);
    outline-offset: 5px;
}

,仅此而已。现在,只有当我们专注于Clear按钮时,我们才能看到带有class search-container的顶级div更改其轮廓样式,而其余元素的样式未触及:

Changing outline of the parent on button focused only

此外,我们还可以将多个选择器传递到:has()伪级,例如针对Clear按钮和Search按钮的焦点状态:

.search-container:has(.clear-btn:focus, .search-btn:focus) {
    outline: 2px solid rgba(66, 153, 225, 0.5);
    outline-offset: 5px;
}

太好了。到目前为止,我们已经看到了如何使用:focus-within:has()伪级的孩子的焦点状态设计父元素。这是一个问题,我们应该使用哪一个以及何时?

何时使用:focus-within and:has(:focus)?

在其一个孩子处于焦点中时,造型父元素可以显着提高:focus:focus-within之外的可见度。当在一长串组件中使用键盘(例如产品卡,文章等列表)导航时,为父元素添加额外的样式可以帮助用户快速识别集中的部分及其容器,从而更好地了解上下文。

Changing outline of the parent on button focused only

通常,使用:focus-within伪级是完成上述任务的最直接方法。但是,:focus-within匹配的焦点状态 ,这意味着,如果我们在焦点模式下有多个后代,祖先也将改变其样式。这并不总是理想的行为。

以我们的搜索框为例。当搜索输入焦点时,我们可能只想突出显示搜索框的标签,而不会在顶级div中添加任何额外的样式。当两个按钮之一 clear 搜索是焦点时,我们突出显示了容器div。只有:focus-within,实现这两种情况是不可能的

在这种情况下,在特定容器上使用:has(:focus)或在:has()中添加明确的选择器(例如:has(#search-box:focus))可以是一个更好的解决方案。

但是,这里有一个性能。根据相对选择器传递给它的复杂程度,:has()可能会昂贵,因为CSS引擎需要查询所有匹配元素以进行样式计算。通常,:focus-within():has(:focus)快,尽管差异可能并不重要。以下是列表中添加到同一元素li时,这是两个伪级的性能测试的屏幕截图:

  • 使用:focus-within伪级

Toggle focus-within state in the dev tools

  • 使用:has(:focus)伪级

Toggle focus-within state in the dev tools

尽管上述测试中的性能差异可能并不显着,但是当我们具有复杂的DOM结构以及是否需要指定儿童的重点状态或常规“抓住它们”时,值得一下。 :focus-within一样。

最后,Firefox中不支持:has()功能性伪级,因此您可能需要使用:focus-within或添加后备。

概括

在本文中,我们学会了如何使用两个伪级:focus-within:has(),以基于孩子的重点状态为父元素设计。我们还看到了它们之间的区别,何时可以比另一个更合适的选择。虽然可访问性影响有时可能是微妙而不明显的,例如直接焦点样式,但要增加对父元素的可见性,就像内部具有交互式组件的列表项目一样,始终是一个很好的考虑因素。使用键盘导航的用户将感谢您。

ð通过我的新书Learning Vue了解Vue。早期版本现在可以使用!

ð如果您想赶上我有时候,请在Twitter上关注我| Facebook | Threads

喜欢这篇文章还是发现它有帮助?分享ðð¼ð