简要介绍如何构建自适应、自适应、易于访问的多选组件,用于对用户体验进行排序和过滤。
在这篇博文中,我想分享一下如何构建多选组件。试用 演示。
<ph type="x-smartling-placeholder">如果你更喜欢视频,可以参阅此博文的 YouTube 版本:
概览
用户经常会看到一些项,有时是大量项, 因此建议您提供一种方法来缩减列表, 选择过载。这个 这篇博文探讨了通过过滤界面来减少选择。它通过 呈现用户可以选择或取消选择的商品属性,减少结果数量 从而减少选择过载。
互动次数
目的是为所有用户及其用户启用快速遍历过滤选项
不同的输入类型。这将通过一个可适应的、响应迅速的
一对组件包含桌面设备和键盘复选框的传统边栏
和屏幕阅读器,以及 <select
multiple>
。
这种针对触摸(而不是桌面)使用内置多选的决定可以节省工作量和创造工作,但我认为,与在一个组件中构建完整的响应体验相比,它可以减少代码负担,从而提供合适的体验。
轻触
触摸组件可节省空间,并有助于提高
。它可以将整个复选框边栏折叠为一个文本框,从而节省空间。
<select>
内置叠加层触摸体验。它通过显示
系统提供的大尺寸触摸叠加层体验。
键盘和游戏手柄
下面演示了如何通过键盘使用 <select multiple>
。
这种内置的多选选项无法设置样式,并且仅在紧凑型中提供 不适合呈现大量选项。看看您为什么不能真正 在这个小方框中看到了各种选项?你可以更改其大小 还是不如多选复选框的适用性
Markup
这两个组件将包含在同一个 <form>
元素中。通过
无论是复选框还是多选选项,都可以通过该表单观察和用于
过滤网格,但也可以提交到服务器。
<form>
</form>
复选框组件
多组复选框应封装在
<fieldset>
元素,并指定
<legend>
。
如果 HTML 以这种方式构建,屏幕阅读器和
FormData 将
并自动理解元素之间的关系。
<form>
<fieldset>
<legend>New</legend>
… checkboxes …
</fieldset>
</form>
完成分组后,为以下各项添加 <label>
和 <input type="checkbox">
:
每个过滤条件我选择将我的代码封装在 <div>
中,因此 CSS gap
属性
当标签变为多行时,标签可以相等间距并保持对齐。
<form>
<fieldset>
<legend>New</legend>
<div>
<input type="checkbox" id="last 30 days" name="new" value="last 30 days">
<label for="last 30 days">Last 30 Days</label>
</div>
<div>
<input type="checkbox" id="last 6 months" name="new" value="last 6 months">
<label for="last 6 months">Last 6 Months</label>
</div>
</fieldset>
</form>
<select multiple>
组件
<select>
元素中很少使用的功能是
multiple
。
当该属性与 <select>
元素一起使用时,用户可以执行以下操作
请从列表中选择多项这就像更改单选列表的互动
复选框。
<form>
<select multiple="true" title="Filter results by category">
…
</select>
</form>
如需在 <select>
中为群组加标签和创建群组,请使用
<optgroup>
元素,并为其指定 label
属性和值。此元素和属性
值类似于 <fieldset>
和 <legend>
元素。
<form>
<select multiple="true" title="Filter results by category">
<optgroup label="New">
…
</optgroup>
</select>
</form>
现在,将
<option>
过滤器的元素。
<form>
<select multiple="true" title="Filter results by category">
<optgroup label="New">
<option value="last 30 days">Last 30 Days</option>
<option value="last 6 months">Last 6 Months</option>
</optgroup>
</select>
</form>
使用计数器跟踪输入数据,以便为辅助技术提供信息
状态
角色
相关技术会用于跟踪和维护
屏幕阅读器和其他辅助技术的过滤器。YouTube 视频
演示这一功能。集成从 HTML 开始,并且属性
role="status"
。
<div role="status" class="sr-only" id="applied-filters"></div>
该元素会大声读出对内容所做的更改。我们可以更新 包含 CSS 文件的内容 计数器 当用户与复选框互动时触发为此,我们首先需要 计数器,其名称为输入的父元素和状态元素。
aside {
counter-reset: filters;
}
默认情况下,计数将为 0
,这个非常好,没有任何事情是 :checked
此设计中的默认行为
接下来,要递增新创建的计数器,我们将定位
值为 :checked
的 <aside>
元素。当用户改变输入状态时,
filters
计数器的计数将会计入。
aside :checked {
counter-increment: filters;
}
CSS 现在可以识别复选框界面和状态角色的常规计算
元素为空,正在等待值。由于 CSS 会在
内存、
counter()
函数允许从伪造对象访问
元素内容:
aside #applied-filters::before {
content: counter(filters) " filters ";
}
状态角色元素的 HTML 现在会读出“2 个过滤器”到屏幕 读取器这是一个良好的开端,但我们可以做得更好,例如分享 结果。我们将使用 JavaScript 执行这项工作 计数器的功能之外。
积累经验
计数器算法在 CSS 中效果很好 “nesting-1”,因为我可以放置所有 将逻辑整合到一个块中。感觉非常便携且集中,便于阅读和更新。
aside {
counter-reset: filters;
& :checked {
counter-increment: filters;
}
& #applied-filters::before {
content: counter(filters) " filters ";
}
}
布局
本部分介绍了这两个组件之间的布局。大部分 布局样式适用于桌面复选框组件。
表单
为提高用户可辨识度和可浏览性,表单最多可设置
设置为 30 个字符,实际上设置一个
过滤器标签。该表单使用网格布局和 gap
属性来间隔开
字段集。
form {
display: grid;
gap: 2ch;
max-inline-size: 30ch;
}
<select>
元素
在移动设备上列出的标签和复选框会占用过多空间。 因此,布局会检查用户的主要指控设备是否发生变化 提供触摸体验
@media (pointer: coarse) {
select[multiple] {
display: block;
}
}
值 coarse
表示用户将无法与
与主要输入设备进行高精度的交互。在
移动设备,则指针值通常为 coarse
,作为主要交互
就是触摸。在桌面设备上,指针值通常为 fine
,这是常见情况
才能连接鼠标或其他高精度输入设备。
字段集
包含 <legend>
的 <fieldset>
的默认样式和布局是唯一的:
通常,为了间隔子元素,我会使用 gap
属性,但唯一
<legend>
的位置会导致很难创建等距的集合。
儿童。不是 gap
,而是相邻的同级元素
selector 和
margin-block-start
。
fieldset {
padding: 2ch;
& > div + div {
margin-block-start: 2ch;
}
}
这样可以避免 <legend>
通过仅定位到
<div>
个儿童。
过滤条件标签和复选框
作为 <fieldset>
的直接子级并且不超过表单
30ch
,如果标签文本过长,可能会换行。自动换行是很好的做法,
文本和复选框之间的错位。Flexbox 是执行此类操作的理想选择。
fieldset > div {
display: flex;
gap: 2ch;
align-items: baseline;
}
![显示对勾标记如何对齐的屏幕截图
多行换行场景中的第一行文本。](https://web.developers.google.cn/static/articles/building/a-multi-select-component/image/screenshot-showing-the-c-b135285ef7d8a.png?authuser=0000&hl=fi)
动画网格
布局动画由 Isotope 完成。答 用于交互式排序和过滤的高性能插件。
JavaScript
除了帮助编排一个整洁的互动式网格外,JavaScript 用于抛光几个粗糙的边缘
规范化用户输入
这种设计有一个表单,提供两种不同的输入方式, 不 序列化 都一样不过,借助一些 JavaScript 对数据进行标准化处理。
我选择将 <select>
元素数据结构与已分组的复选框对齐
结构。为此,需要
input
事件监听器添加到了 <select>
元素,此时其为
selectedOptions
已映射。
document.querySelector('select').addEventListener('input', event => {
// make selectedOptions iterable then reduce a new array object
let selectData = Array.from(event.target.selectedOptions).reduce((data, opt) => {
// parent optgroup label and option value are added to the reduce aggregator
data.push([opt.parentElement.label.toLowerCase(), opt.value])
return data
}, [])
})
现在可以安全地提交表单了,对于此演示,请指示 Isotope 过滤条件。
完成状态角色元素
该元素仅根据复选框计算和读出过滤条件数量
但我认为另外分享一些
结果,并确保也计算 <select>
元素选择。
<select>
个元素选择反映在“counter()
”中
在数据标准化部分,输入时已经创建了一个监听器。在 此函数的末尾以及所选过滤器的数量和结果数量, 是已知的这些值可以传递给状态角色元素 就像这样
let statusRoleElement = document.querySelector('#applied-filters')
statusRoleElement.style.counterSet = selectData.length
结果反映在 role="status"
元素中
:checked
提供了一种内置方式,可将所选过滤条件的数量传递给
状态角色元素,但无法查看过滤后的结果数。
JavaScript 可以监视与复选框的交互并在过滤
网格中,像 <select>
元素一样添加 textContent
。
document
.querySelector('aside form')
.addEventListener('input', e => {
// isotope demo code
let filterResults = IsotopeGrid.getFilteredItemElements().length
document.querySelector('#applied-filters').textContent = `giving ${filterResults} results`
})
这项工作总共完成了“2 个过滤器给出 25 个结果”公告。
现在,我们卓越的辅助技术体验 无论他们如何与之互动
总结
现在您已经知道我是怎么做到的了,您该怎么做 ‽ 🙂?
让我们一起采用多样化的方法,学习所有在 Web 上构建应用的方法。 创建演示,在 Twitter 微博上添加链接,然后我会添加 到下面的社区混剪部分!
社区混剪作品
此处尚无任何可显示的内容!