我们将创建自定义的表单输入和文本区域样式,这些样式在各种顶级浏览器中具有近乎相同的外观。我们将特别为text
、date
和file
的输入类型设置样式,并为readonly
和disabled
的状态设置样式。
继续阅读,学习如何:
- 重置输入样式
- 使用
hsl
,对输入状态进行主题设计 - 确保所有状态符合对比度要求
- 为Windows高对比度模式保留一个可感知的
:focus
状态
本地输入样式的常见问题
与我们看到的单选、复选和选择相比,文本输入样式之间有更多的相同点,但还是有不一致的地方。
下面是我们今天要解决的无样式输入的截图,从左到右分别是Chrome、Safari和Firefox。
我们将寻求统一各浏览器和常见字段类型的初始外观。
date
字段是独特的,因为Chrome和Firefox提供了格式化和一个弹出的日历可供选择,而Safari没有提供类似的功能。我们也不能在CSS中创建这个,所以我们在这里的目标是尽可能地创建一个类似的初始外观。请看日期/时间输入的caniuse。
基础HTML
我们涵盖了很多字段类型,所以请查看CodePen的完整列表。但这里是一个文本输入和一个文本区域的基本HTML。
<label for="text-input">Text Input</label>
<input class="input" id="text-input" type="text" />
<label for="textarea">Textarea</label>
<textarea class="input" id="textarea"></textarea>
为了简化我们的样式并准备与级联工作,我们只添加了一个CSS类--input
,它直接放在文本输入和文本区域上。
标签不是我们样式练习的一部分,但它是作为一般要求包括在内的,值得注意的是,for
属性的值是输入端上的id
。
为主题创建CSS变量
在本教程中,我们将通过使用hsl
值来尝试一种有点不同的主题化技术。
我们将为边框设置一个灰色,然后将一个要在我们的:focus
状态下使用的蓝色分解成它的hsl值,包括:h
的 "色调",s
的 "饱和度",以及l
的 "亮度":
:root {
--input-border: #8b8a8b;
--input-focus-h: 245;
--input-focus-s: 100%;
--input-focus-l: 42%;
}
我们的每个表单字段的教程都融入了一点不同的主题化方法,这些方法都可以被提取出来,并不仅仅用于表单!
可访问的对比度#
正如所有的用户界面元素一样,输入框需要与周围环境有至少3:1的对比。
而且,:focus
,如果涉及到改变边框的颜色或根据WCAG 2.2草案,厚度大于或等于2px
,则需要与非聚焦状态有3:1的对比。
WCAG 2.2的草案对:focus
的要求做了一些轻微的调整,我鼓励你去审查这些要求。
重置样式
正如我所有的教程中所包含的现代最佳实践一样,我们首先添加以下重置:
*,
*::before,
*::after {
box-sizing: border-box;
}
从各浏览器的字段初始状态中可以看出,一些突出的差异是在边框类型、背景颜色和字体属性方面。
有趣的是,font-size
和font-family
并不像排版元素那样从文档中继承,所以我们需要明确地设置它们作为我们重置的一部分。
同样值得注意的是,一个输入的font-size
应该至少计算为16px,以避免在移动Safari浏览器中的交互时被触发缩放。我们通常可以假设1rem
等于16px
,但我们会明确地将其设置为回退,然后使用更新的CSS函数 max
来设置16px
作为最小值,以防它比1em
小(这个想法要感谢Dan Burzo)。
.input {
font-size: 16px;
font-size: max(16px, 1em);
font-family: inherit;
padding: 0.25em 0.5em;
background-color: #fff;
border: 2px solid var(--input-border);
border-radius: 4px;
}
我们将我们的border
,以使用主题变量,还创建了一个略微圆滑的角落。
经过这次更新,我们已经看起来很不错了:
在那张截图中可能很难注意到,但另一个区别是每个字段的高度。这里有一个文本输入和文件输入的比较,可以更好地看到这种差异。
让我们用下面的方法来解决这个问题,只要不放在textarea
,我们就把它应用到我们的.input
类上:
.input:not(textarea) {
line-height: 1;
height: 2.25rem;
}
我们把line-height: 1
,因为当它不是textarea
,输入就不可能是多行的。由于考虑到特别是文件输入类型,我们还在rem
中设置了我们的高度。如果你知道你不会使用文件输入类型,你可以在这里使用em
来代替,以便灵活地创建各种尺寸的输入。
但是,关键的是,我们已经失去了可编辑和disabled
输入类型之间的区别。我们还想在定义readonly
时更多地暗示它也是不可编辑的,但仍然是互动的。而且,我们还有一些工作要做,以使文件输入类型更加平滑。而且,我们想创建我们的主题:focus
状态。
文件输入 CSS
让我们再看看只是我们在Chrome、Safari和Firefox上的文件输入。
我们不能对浏览器创建的按钮进行样式设计,也不能改变提示文字,但到目前为止,我们提供的复位确实做了一点工作,使我们的自定义字体得以使用。
我们再做一个调整,把字体缩小一点,因为当与其他字段类型一起查看时,继承的按钮看起来相当大,font-size
,这是我们剩下的唯一解决方法。通过这样做,我们需要调整顶部的padding,因为我们设置的padding是基于em
。
input[type="file"] {
font-size: 0.9em;
padding-top: 0.35rem;
}
如果你希望有一个更高级的解决方案,有很多人已经介绍了这些。我在这里的目的是为你提供一个基线,你可以在此基础上建立。
readonly
CSS样式
虽然不经常使用,但readonly
属性可以防止用户的额外输入,尽管可以选择值,而且它仍然可以被辅助技术发现。
让我们添加一些样式,以使更多的人知道这个字段基本上是一个先前输入值的占位符。
要做到这一点,我们将针对任何.input
,也有[readonly]
的属性。属性选择器是一种非常方便的方法,应用广泛,绝对值得在你的CSS工具箱中添加(或更新你的认识)。
.input[readonly] {
border-style: dotted;
cursor: not-allowed;
color: #777;
}
除了换成dotted
边框外,我们还为它指定了not-allowed
光标,并强制使用了中灰色的文本颜色。
从下面的GIF中可以看出,除了高亮/复制数值外,用户不能与该字段互动。
禁用的输入和文本区域样式
与readonly
,我们将使用一个属性选择器来更新禁用字段的样式。我们把它附在.input
类上,所以它也适用于文本区域和其他输入类型。
我们将利用我们的CSS变量来更新边框的颜色为柔和的灰色,字段背景为非常浅的灰色。我们还将再次应用not-allowed
光标,作为一个额外的提示,表明该字段不是交互式的。
.input[disabled] {
--input-border: #ccc;
background-color: #eee;
cursor: not-allowed;
}
下面是文本输入和文本区域的结果:
文本区样式
我们的textarea
,但有一个属性我想提一下,因为它是文本区固有行为的独特之处。
该属性是 resize
,它允许你指定textarea
可以调整的方向,或者它是否可以。
虽然你肯定应该允许textarea
,在一般情况下保留调整大小的功能,但你可以限制它只在垂直方向上调整大小,以防止用户拖动它非常宽的布局破坏,比如说。
我们将通过对我们的.input
类进行范围定位来应用这个属性,当它被应用在textarea
。
textarea.input {
resize: vertical;
}
在最后的CodePen演示中试试吧!
:focus
状态样式
好了,我们已经完成了输入和文本区的初始样式,但我们需要处理一个非常重要的状态::focus
。
我们将采用一个组合效果,将边框的颜色改为符合3:1对比度的值,以对抗非聚焦状态,同时也添加一个box-shadow
,以获得额外的突出效果。
这就是为什么我们在hsl中定义了焦点状态的主题色:这意味着我们可以通过更新亮度值来创造一个边框颜色的变体。
首先,我们通过从各个CSS变量值中构建完整的hsl值来定义边框颜色。
.input:focus {
border-color: hsl(var(--input-focus-h), var(--input-focus-s), var(--input-focus-l));
}
然后,我们加入box-shadow
,它将只使用模糊来创造本质上的双边框效果。calc()
可以接受在hsla
内使用,所以我们用它将原始值减淡40%,同时也允许有一点alpha透明度。
.input:focus {
/* ...existing styles */
box-shadow: 0 0 0 3px hsla(var(--input-focus-h), var(--input-focus-s), calc(var(--input-focus-l) +
40%), 0.8);
}
请注意,我们现在为我们的对比增加了一个新的背景,即:focus
边框与:focus
box-shadow
,所以如果使用这种方法,请确保你选择的颜色的计算差异至少为3:1。
可以选择跳回到.input
规则,并添加一个transition
,以使box-shadow
:
.input {
/* ...existing styles */
transition: 180ms box-shadow ease-in-out;
}
最后,我们不想忘记Windows高对比度模式,它不会看到box-shadow
,也无法检测到边界颜色的变化。因此,我们为这些用户加入一个透明的轮廓:
.input:focus {
outline: 3px solid transparent;
}
我们在涉及按钮样式的那一集里也使用了这种技术。
这里有一个聚焦于文本输入的GIF演示。
这里是readonly
字段的外观,因为它有一个不同的border-style
。
在CodePen的HTML中,有一个使用内联样式定义更新视觉的例子,如错误状态。同样,请记住,我们是将提供的--input-focus-l
值减弱了40%,而且聚焦的边框颜色必须与非聚焦的颜色形成至少3:1的对比,所以当你改变CSS变量值时要考虑这一点。
输入模式和自动完成
除了使用正确的输入类型(例如:电子邮件)之外,还有两个额外的属性可以帮助改善用户体验,尤其是在移动端。
第一个是定义inputmode
,它提供了一个改变的键盘或小键盘,更好地匹配预期数据。在MDN上阅读关于可用的inputmode
值 >
其次是autocomplete
,它比on
或off
有更多的选择。例如,我一直很欣赏在iPhone上,当谷歌通过文本向我发送确认码时,键盘 "就知道 "这个值是什么。结果发现,这要归功于autocomplete="one-time-code"
!
查看autocomplete
的完整列表,它允许你提示预期的值,并真正提高你的表单的用户体验,让用户使用自动填写的值。
演示
首先,这是我们的解决方案在Chrome、Safari和Firefox上的最终外观(从左至右)。当并排观看时,文件输入仍然有点突出,但在单个浏览器上的表单流程中,这绝对是可以接受的。