纯 CSS 自定义复选框样式
这是系列文章的第十九篇,该系列文章探讨了过去 13 多年来我作为前端开发者所遇到的各种问题,并提出了相应的解决方案。访问ModernCSS.dev可以查看整个系列文章及其他资源。
我们将使用纯 CSS 创建自定义、跨浏览器、主题化、可扩展的复选框,内容如下:
currentColor
用于主题功能,包括 SVGem
相对尺寸单位- 使用 SVG 作为
:checked
指标 - CSS 网格布局用于对齐输入和标签
这里的许多概念与我们第 18 集中的自定义样式单选按钮重叠,另外还使用 SVG 表示状态
:checked
并包含状态:disabled
样式
现已推出:我的 Egghead 视频课程:无障碍跨浏览器 CSS 表单样式。你将学习如何将本教程中描述的技术提升到一个新的水平,创建一个可主题化的表单设计系统,并扩展到你的各个项目。
复选框 HTML
在单选按钮文章中,我们探讨了两种标记输入字段的有效方法。与此类似,我们将选择标签包裹输入框的方法。
对于我们的复选框,我们将使用内联 SVG 作为我们的自定义控件,因此这里是用于测试未选中和选中状态的基本 HTML:
<label class="checkbox">
<span class="checkbox__input">
<input type="checkbox" name="checkbox">
<span class="checkbox__control">
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' aria-hidden="true" focusable="false">
<path fill='none' stroke='currentColor' stroke-width='3' d='M1.73 12.91l6.37 6.37L22.79 4.59' /></svg>
</span>
</span>
<span class="radio__label">Checkbox</span>
</label>
<label class="checkbox">
<span class="checkbox__input">
<input type="checkbox" name="checked" checked>
<span class="checkbox__control">
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' aria-hidden="true" focusable="false">
<path fill='none' stroke='currentColor' stroke-width='3' d='M1.73 12.91l6.37 6.37L22.79 4.59' /></svg>
</span>
</span>
<span class="radio__label">Checkbox - Checked</span>
</label>
aria-hidden="true"
注意和的用法focusable="false"
,因为我们要把这个 SVG 当作一个装饰图标来处理。在这种情况下,底层的复选框仍然可用,以便提供可访问性的选中状态的语义。
原生复选框的常见问题
与单选按钮一样,复选框的外观在不同浏览器中也有所不同。
以下是 Chrome、Firefox 和 Safari 的基本样式(从左至右):
另外,与单选按钮一样,复选框不会随之缩放font-size
。
我们的解决方案将实现以下目标:
font-size
与标签提供的规模- 获得与标签相同的颜色,以方便主题化
- 实现一致的跨浏览器设计风格,包括
:focus
状态 - 保持键盘可访问性
我们的样式将以与单选按钮相同的变量开始并重置
标签样式
我们的标签使用了 类.checkbox
。我们在这里包含的基本样式是font-size
和color
。回想一下之前提到的,font-size
还不会对复选框输入的视觉大小产生影响。
我们使用异常大的尺寸font-size
只是为了强调教程演示中的视觉变化。
我们的标签也是我们设计的布局容器,我们将设置它使用 CSS 网格布局来利用网格间隙。
.checkbox {
display: grid;
grid-template-columns: min-content auto;
grid-gap: 0.5em;
font-size: 2rem;
color: var(--color);
}
这是我们在 Chrome 中捕获的进度,其中 Inspector 显示网格线:
由于我们将stroke
SVG 的颜色定义为,因此它也currentColor
拾取了该值。rebeccapurple
自定义复选框样式
为了准备这一点,我们将我们的 包裹input
在一个span
带有 类的中checkbox__input
。然后,我们还添加了一个 ,span
作为 的兄弟元素,input
带有 类checkbox__control
。控件 span 还包含复选标记 SVG。
这里的顺序很重要,当我们为、和设计样式时:checked
就会:focus
看到:disabled
。
步骤 1:隐藏原生复选框
我们需要隐藏本机复选框,但保持其在技术上可访问,以实现正确的键盘交互并保持对:checked
状态的访问:focus
。
为了实现这一点,我们将使用opacity
来在视觉上隐藏它,并将其宽度和高度设置为1em
。我们将保留宽度和高度,以确保触摸设备用户可以发现。
.checkbox__input {
input {
opacity: 0;
width: 1em;
height: 1em;
}
}
我强烈推荐Sara Soueidan 的这篇文章,它深入探讨了隐藏单选按钮和复选框的选项,并且还提供了对这些输入的自定义样式略有不同的看法。
步骤 2:自定义未选中复选框样式
对于我们的自定义复选框,我们将样式附加到 ,span.checkbox__control
即 之后的同级input
。
我们将其定义为一个inline-grid
元素,使用 调整大小,使其与应用于em
的 保持相对关系。我们还使用的值来保持相对外观。然后,我们使用来柔和地圆化边角。font-size
label
em
border-width
border-radius
.checkbox__control {
display: inline-grid;
width: 1em;
height: 1em;
border-radius: 0.25em;
border: 0.1em solid currentColor;
}
这是我们隐藏本机输入并为自定义复选框控件定义这些基本样式后的进度:
好吧,它display: inline-grid
发挥了神奇的作用,很好地包含了 SVG 复选标记,但是自定义控件与标签的对齐方式该如何处理呢?
由于我们在复选框输入上保留了width
和height
,并且仅用不透明度隐藏它,所以它仍然占用空间。
为了解决这个问题,我们将使用 CSS 网格布局将 定义.checkbox__input
为单个网格模板区域,并指示其所有子元素都占据该区域。这项技术是 的现代替代品position: absolute
。
.checkbox__input {
display: grid;
grid-template-areas: "checkbox";
> * {
grid-area: checkbox;
}
}
如果您发现由于使用的字体导致控件和标签之间存在一些垂直错位,请参阅单选按钮的相关部分以获取使用
transform
步骤 3:样式:checked
与未选中状态
我们使用opacity: 0
保留了本机复选框输入,可用于键盘交互以及点击/点击交互。
它还保留了:checked
使用 CSS 检测其状态的能力。
还记得我提到过顺序很重要吗?由于我们的自定义控件位于原生输入框之后,因此当原生控件处于🙌+
状态时,我们可以使用相邻的兄弟组合 - - 来设置自定义控件的样式。:checked
但是 - 由于我们使用内联 SVG 来显示:checked
指示器,我们实际上需要对其进行设置,以便 SVG 最初是隐藏的,并且仅在:checked
状态下显示。
我们将添加一个transition
来提供状态切换时的动画效果,并用于transform: scale(0)
进行初始隐藏:
.checkbox__control svg {
transition: transform 0.1s ease-in 25ms;
transform: scale(0);
transform-origin: bottom left;
}
接下来,我们需要添加:checked
样式以将其放大到视图中:
.checkbox__input input:checked
+ .checkbox__control svg {
transform: scale(1);
}
以下是动画交互的演示:checked
:
步骤 4::focus
状态
对于:focus
状态,我们将使用box-shadow
与单选按钮相同的双重技术。这使我们能够利用currentColor
基本自定义复选框和:focus
样式,同时确保两者之间的区别。
.checkbox__input input:focus
+ .checkbox__control {
box-shadow: 0 0 0 0.05em #fff, 0 0 0.15em 0.1em currentColor;
}
box-shadow 定义的顺序意味着我们首先创建一个细白边框的外观,它出现在一个羽化阴影上方,该阴影采用了 的值currentColor
。
以下是外观的演示:focus
:
:disabled
步骤5:复选框样式
我们在单选按钮教程中错过的一步是状态样式:disabled
。
这将遵循与我们之前的状态类似的模式,这里的变化主要是将颜色更新为灰色。由于我们所有的颜色都与currentColor
值绑定,因此对于自定义控件来说,这是一个简单的更新:
:root {
--disabled: #959495;
}
.checkbox__input input:checkbox:disabled
+ .checkbox__control {
color: var(--disabled);
}
但我们遇到了一个问题。由于标签是父元素,目前我们无法在 CSS 中单独根据状态来设置其样式:disabled
。
对于纯 CSS 解决方案,我们需要在已知复选框已禁用的情况下,为标签添加一个额外的类。由于用户无法更改此状态,因此这通常是可接受的额外步骤。
.checkbox--disabled
我们将创建要添加到 HTML 标签元素的类。
.checkbox--disabled {
color: var(--disabled);
}
演示
这是一个包含样式的演示:disabled
,它展示了 CSS 变量的强大功能以及如何使用currentColor
简单的内联样式重新设置单个复选框的主题。这对于快速更改错误状态等操作非常有用。