A11Y 101:编写CSS时要考虑可访问性

发布于 大漠

构建可访问性Web应用时,很多人都可能会认为这应该是HTML的事情,或者说是WAI-ARIA的事情。或许也会问,可访问性和CSS又有啥关系呢?虽然CSS有很多特性(特别是发展到今天)可以让我们美化Web页面或应用程序变得更简单和更灵活,但这些强大的特性也可能让我们的用户体验变得特别的糟糕。实际上,仅用一行代码*{outline:none 0}就可以使一个网站或Web应用的可访问性变得非常的糟糕。也就是说,编写CSS可以直接影响Web的可访问性。在这篇文章中,我收集了一些技术、注意事项和方法来帮助你在编写CSS时不会影响Web可访问性,反而提高Web的可访问性。

可访问的CSS

让我们从CSS开始吧!

众所周知,CSS是级联样式,使用CSS可以使任何HTML元素看起来像任何东西,但这并不意味着我们就可以这么做。正如在《A11Y 101:编写HTML时要考虑可访问性》一文中和大家探讨的一样,虽然构建Web页面或应用有近186个元素可选择,任何标签元素都可以帮助我们搭建好页面所需的骨架,但我们却不能这么做。我们应该尽可能的选择最能表达语义的元素标签。如果不这样估,它可能会导致混乱和可用性问题,对每个人,尤其是有访问应用有障碍的人士。使用正确的语义与用户期望有很大的帮助 —— 元素的外观和功能会根据它们的功能进行某些方式的显式,而且用户期望这些常见的约定

例如,如果开发人员没有适当地使用标题元素标记内容,则屏幕阅读器用户无法通过标题元素导航页面。同样,如果对标题进行样式设置,则标题将失去其视觉目的,使其看起来不像标题。经验法则是,您可以更新页面功能的样式以适应您的设计,但不要更改它太多,使其不再按预期的外观或活动。

虽然CSS样式允许我们修改现有HTML元素的特征,表面上看上去很简单,但其中的弯弯绕绕一点不简单。简单地说吧,被运用于某个元素上的样式,就分很多个层级。所有Web浏览器都有一个内置的样式表,用于定义所有元素的默认样式。”HTML在没有使用任何额外的CSS时,也会根据不同语义标签呈现不同效果(比如、字号、字体、间距和颜色等)“,比如:

这就是浏览器客户端内置样式表(User Agent Stylesheet)渲染出来的效果。事实上所有的HTML标签都是在这个样式表中定义的,它们的大小颜色位置其他样式都在其中定义。当页面应用了开发者自己写的样式时就会覆盖这个内置样式,并告诉浏览器以不同的方式来渲染。

而我们所熟悉的CSS又常被称为级联,那是因为样式应用有层次和优先级(即层叠和继承)这样的概念:

对于每个Web页面应用的CSS层次结构如下:

这是从最低优先级到最高优先级排序的,这意味着每个后续步骤中定义的样式将覆盖以前的样式。

**重要的是:**最终用户始终对其查看的页面样式具有最终控制权。对于可访问性,我们需要定义可访问的样式,但也允许在我们的设计中为最终用户定制提供灵活性。

那么,为什么最张用户要定义自己的样式呢?低视力的用户可以定义更大的文本大小,以便阅读文本内容。对于色盲或视力低下的用户可能会覆盖页面颜色、以便他们能够感知特定颜色或高对比度的页面内容。有认知或学习障碍的用户可能会忽略定位、字体、图像等以确保更基本的表示。简而言之,用户可能会覆盖默认或开发者定义的样式原因有很多。此外,屏幕阅读器几乎忽略了所有的CSS。

内容和样式分离

CSS的主要好处之一是它允许开发者将内容与其样式分离。内容是指构建Web页面或应用的文本图像其他元素。样式是指Web内容在客户端上呈现的方式。内容应该在HTML中定义,样式应该在CSS中定义。这样做的好处之一是,如果有人禁用或覆盖CSS,内容仍然可以完全可访问的

在《A11Y 101:编写HTML时要考虑可访问性》中我们也特意提到这一点:在编写HTML的时候不要被UI视觉迷惑,应该根据内容、功能来选择最合适的HTML标签元素

HTML和样式分离在社区有很多优秀的案例,其中最经典的应该要属禅意花园(CSS Zen Garden,展示了CSS的强大,社区数百名CSS爱好者在同一份具有逻辑顺序和语义标签上用不同CSS构建出不同的页面风格)。因为页面使用了正确的语义化标签元素,所以页面当样式被禁用时,仍然具备可访问性:

内容和样式分离除了对我们开发Web应用有益处(可维护,可扩展等),在一些有关于可维护性相关的法律法规则中对这方面有明确的规定,比如美国在1973年颁布的**Section 508 of the same U.S. Rehabilitiation Act of 1973**就规定:

文件的组织应该使其在不需要相关样式表的情况下可读。即,Web应用在没有样式情况下也是可读的

同时Web内容可访问性指南(WCAG)中也有说过:

组织文档,使其可以在没有样式表的情况下可读。例如,当HTML文档在没有关联样式表的情况下渲染时,仍然必须能够读取该文档。

为了实现这一点,你可以将CSS看到一个表示层,你可以删除它,但仍然保留可读和可理解的内容。通过将样式性标记移动到样式表中,HTML文档就有了干净的语义标签。这使人们更容易使用诸如纯文本浏览器、听觉浏览器和屏幕阅读器等设备来使用Web应用。

只有与具有语义化HTML一起使用时,CSS才能带来好处。在我们构建一个Web应用时,首先构建一个不带任何样式的页面,注意页面的顺序和结构。在编写HTML的时候不要被UI视觉迷惑,应该根据内容、功能来选择最合适的HTML标签元素。有关于这方面的更多细节,可以阅读《A11Y 101:编写HTML时要考虑可访问性》一文。

如何编写可访问性的CSS

前面简单的和大家探讨了可访问性CSS的作用和存在的意义,那么接下来我们实际出发,来看看在编写CSS时,我们应该如何使用CSS技术,才能用来提高Web应用的可访问性。

构建易读到可读的文本

文本是Web网站或应用的主要内容之一,文本的可读性也直接会影响到一个应用的可访问性。在Web中设置文本的样式主要是依赖于**CSS Fonts Module Level 3**提供的属性。也就是说,花大量的时间设计样式、测试和微调字体属性是很重要的,因为无论在什么设备上,文本都必须是可读的。

font-size的设置

font-size是用来设置文本字号大小的,在文本的可读性方面有着直接决定性的作用。我们在给Web中的文本设置font-size是有一定的设计依据的,如果处理不好,会影响文本的可读性,也就直接影响了Web的可访问性。对于font-size的设置,我们可以从以下几个方面来做。

增加font-size的大小

一直以来,浏览器默认的文本字号大多数情况下都是16px(只要用户没有修改浏览器的字体大小的情况之下),不过设计师喜欢将文本字号设置为12px,但随着更高分辨率的设备兴起,font-size的大小在一段时间中稳定在15px18px(注意,这个区间的值并不是浏览器默认的font-size,主要是设计师将字号提高到这个区间)。近年来,设计师将Web中文本的font-size再次上升到20px以上。这其实是一件好事。文本必须足够大,以便在智能手机上阅读,并随着屏幕尺寸的增大而增大,以便在更大的屏幕(比如电视的屏幕)上仍然可以远距阅读

由于给文本设置的字体(font-family)不同,可能在设备上渲染会有着不同的效果,所以定义一个标准的最小尺寸是没有任何意义的,但是对于较小屏幕尺寸来说,将文本的font-size设置在18px20px之间可能是一个很好的起点。

用相对单位来设置基本字体大小

CSS中的单位有很多类型:

有关于CSS中的单位更多的内容可以阅读**CSS Values and Units Module Level 4**规范。

那么我们回到这个话题中来,什么是基本字体大小?

基本字体大小就是所有其他字体大小的派生字体大小。我们通常在html中设置基本字体大小:

html {
    font-size: 100%; // 浏览器默认的值是`16px`,所以100% = 16px
}

那么我们就可以在其他元素上使用相对单位(比如emrem)来设置文本的font-size。这一点非常重要,因为这意味着更改基本字体大小也将更改所有其他元素的font-size。比如,html中设置的font-size值为100%,如果将h1h2font-size的值分别设置为2rem1rem

html {
    font-size: 100%; // 相当于16px
}

h1 {
    font-size: 2rem; // 2rem = 2 × 16px = 32px
}

h2 {
    font-size: 1rem; // 1rem = 1 × 16px = 16px
}

如果我们想通过调整基本字体大小让文本适应更大的屏幕,我们可在借助CSS媒体特性在不同的断点中重新给基本字体大小设置值。比如:

html {
    font-size: 100%; // 100% = 16px
    
    @media (min-width: 768px) {
        font-size: 112.5%; // 112.5% × 16px = 18px
    }
}

这个时候对应的h1h2的值也会随着改变。默认情况下,h1font-size值为32px100%16px2 x 16px = 32px),h2font-size值为16px100%16px1 x 16px = 16px);当浏览器屏幕尺寸达到@media中设置的值(min-width: 768px)时,htmlfont-size的值为112.5%(即18px),这个时候h1font-size的值为36px112.5%16 x 112.5% = 18px2 x 18px = 36px),h2font-size的值为18px112.5%16px x 112.5% = 18px1 x 18px = 18px)。

但社区中也有另外一种声音,那就是在bodyfont-size使用固定单位的值,即px,然后在其他元素的font-size上使用相对单位em。使用em会相对于父容器的font-size的值计算。

em的计算简单但繁锁:

但是调整元素大小却是非常灵活的:

这两种观点差异性还是很大的。就我个人而言,我更坚持不要以像素单位(或别的固定单位)来设置基本字体大小。这样做将覆盖浏览器的默认字体大小。但是浏览器的默认字体大小到底是多少呢?在上面的代码示例中,我们将基本字体大小设置为100%,但也我说过,在大多数情况之下,浏览器的默认字体大小才是16px。因为用户要是修改了浏览器字体大小的话,那么所谓的浏览器默认字体大小就会得到改变:

随着用户的设置不同,浏览器默认的font-size的值也会随之改变。

这样做对于Web可访问性是非常有益的。假设你的Web应用刚好被视力受损的人士浏览的话,用户可能为了便于更好的浏览,会手动将浏览器的默认字体大小设置为更大。如果我们在CSS中将基本字体大小设置为像素值(或别的固定单位的值),那么该值将会覆盖浏览器的默认字体大小的设置。也就强迫用户只能在一个固定的值(比如说16px)阅读,而无法用更大的字号来阅读。这对于视力有障碍的人士是不友好的。

如果要一个最佳的实践体验的话应该是:

html元素上使用%(或其他相对单位)来设置font-size,然后在其他的元素上使用emrem来设置font-size

使用CSS锁定流式排版

随着多种式样的设备终端的面世,我们在Web排版更需要流式的排版方式,流式排版能更好的适配不同的设备,能更好的提供可阅读性,但流式排版中最难控制的也是font-size的设置。

虽然我们可以通过添加大量的媒体查询特性在不同的断点中设置font-size,但这并不是最佳的方案。好在视窗单位的出现,我们可以让流式排版中的font-size设置变得更容易。在社区中有一种流行的方案:

使用CSS锁定(CSS Locks)流式排版

CSS锁定流式排版这种方案设置了最小的font-size和对应的屏幕宽度(Minimun Viewport),最大font-size和对应的屏幕宽度(Maximum Viewport),以及两者之间的所有可变font-size

font-size的大小不会在左右区域发生变化,它们只会在中间区域缩放。下栅极(Lower Gate)是最小的屏幕大小,我们对它应用固定的font-size,同样的,上栅极(Upper Gate)是最大的屏幕宽度,对应也采用固定的font-size

另外该技术方案好比在运河和河流航行中,船闸是一种在不同水位的水域之间升降船只的装置。

该方式设置font-size可以通过一个计算公式来完成,在CSS中借助calc()函数来实现,将会给这个函数传四个变量:最小字号、最大字号、最小视窗宽度和最大视窗宽度

调整浏览器视窗大小看到的效果如下:

如果你对流式排版感兴趣的话,可以阅读下面这些文章:

当然,关于font-size还有很多细节可说,在仅仅一篇文章中是无法把所有有关于font-size知识介绍完。如果你感兴趣的话,可以阅读@Christian Miller的《Your Body Text Is Too Small》一文。

设置line-height

CSS的line-height可以用来控制多行文本的行间距,其设置和font-size类似,也会决定Web的可读性,也就决定Web的可访问性。但在CSS的世界中,line-height要比font-size复杂的多。

浏览器中的默认的行高大约为1.2。根据WCAG的描述来说,段落内的文本块行高至少为1.5

line-height设置的好,不仅可读性更好,而且视觉上也更吸引人

我见过很多开发人员都认为line-height是一种独立的特性,所以他们倾向于把行高的设置建立在看起来不错的基础上,甚至喜欢将line-heightpx来设置值。事实上,影响line-height的因素很多,比如font-sizefont-family等。而且line-height使用不同的单位计算方式也是略有差异的。比如@Russ Weakley分享的《Line Height》(可以点击这里下载PDF版本的PPT)话题中用实例告诉我们不同单位之间计算的差异性:

从上图中可以看出,设置line-height的最佳实践是不带任何单位设置行高的值。社区中很多同学推荐文本段落的行高通常在1.3~1.7之间。当然,这也取决于许多因素:

  • 如果你选择的字体看起来很轻,并且它的x字母高度很小,那么行高的设置应该更接近1.3
  • 如果你选择的字体看起来很重或光学大字体,那么行高的设置应该更接近1.7
  • 如果文本颜色是深色,也需要在线条之间留出更多的空间,行高的设置就要更大一些
  • 你也应该根据不同的语言选择不同的行高

比如下面几个场景实例:

相同的字体,相同的字号,深颜色的文本的行高要比浅色的文本更高

相同的字体,相同的字号,相同的文本颜色,行的长度越长,所需的行高就越大。(稍后我们就会聊聊行长(Line Length)对可访问性的影响)。

不同的字体,相同的字号,相同的文本颜色。看起来更重的字体需要更大的行高

相同的字体,相同的文本颜色,不相同的字号,字号越小的应该设置更大的行高

另外,段落文本的line-height除了和文本的字体(font-family)、字号(font-size)、粗细(font-weight)、行长(每行的字数)、词间距(word-spacing)、字间距(letter-spacing)以及文本颜色(color)有关之外,和设备也有一定的关系。比如在手机端上,由于某些原因,很多同学更倾向于设置更大的行高。但事实效果呢,并非如此。因为在手机端上,段落宽度更小,所以行高可能比桌面显示的还要小。加上在较小的屏幕上,读者眼睛从一行的结尾跳到下一行的开头的距离要更短得多。如果行高过大,会让用户有一种段落跳跃感。

从上面的内容我们可以再次感知到line-height并不是一个独立特性,在Web排版中,影响line-height的因素很多。也正因为如此,设置line-height要比font-size更复杂的多。但line-height对于Web的可读性和可访问性又是非常重要的。正如@Dmitry Fadeyev所说的那样:

正确使用段落文本的行高已被证明可使用户的理解能力提高20%,合理的行高让文本有一个较好的间距,可以给用户提供一个更容易消化的内容,然后去掉无关的细节

行长(Line Length)

排版方面的印刷术有近千年的历史了,一直都围绕着水平和垂直眼球运动关系在探讨。@Jan Tschichold在1928年就废除了文本居中的排版,从而提倡左对齐的排版。他认为,这将有助于读者提供一个一致的左(水平和垂直)边缘,让眼球在完成每个水平线后返回(从上一行换到下一行)到左边缘。

对于有阅读困难的用户来说,一个常见的问题是,如果一行太长,他们会在换行时跳到错误的一行。换句话说,你找不到从一行的结尾到下一行的开头路径,就会造成阅读的错误。避免这个问题最简单的方法就是保持段落简短。另一个重要的准则是保持段落行长度够短。每行50~75个字符(包括间距)对于大屏幕来说是一个不错的行长度准则。在移动端屏幕上行长度会更短一些。而理想的标准是:

每行的长度大致是45~75个字符;对于移动设备,每行应该是30~40个字符

下面这个示例就是两个不同站点行长度的效果截图。左侧是每行使用了50~75个字符(对于打印或PC端,这个是最理想的标准),而右侧每行是30~40个字符(对于移动端,手机终端这个值是最理想的标准):

我们有多种规则来促进水平阅读,其中之一就是将文本设置在一个合理的范围内。正如@James Craig在他的《Designing With Type》一书中所写:

阅读一行很长的文本会导致疲劳。读者必须在每一行的末尾移动到下一行的头部,这需要一定的时间寻找。太短的一行会破坏作为一个整体阅读的单词或短语。

获得正确的行长度非常简单,但遗憾的是,大多数网站仍然有错误。理想的文本行长度是45~75个字符(包括空格)。任何超过这个范围的东西都很难阅读。当行的长度太短时,会有更多的换行;当行的长度太长时,眼晴就会更累。

阅读很长的文本对我们的眼晴来说是很累的。我们的眼睛需要不断的停顿,而这些停顿是由断行引起的。在切换到下一行的情况下,他们会有短暂的停顿。长行文本很能独自阅读,再加上视力受损或阅读障碍,这几乎是不可能的。

65个字符(是罗马字母的2.5倍)通常被认为是最完美的度量标准。从这个数字得出的理想范围是所有设计师都应该争取的。许多Web开发者将这一规则直接应用到Web应用中。然而,我发现我们可以更可靠地将Web页面每行的字符(包括空格和标点符号)扩展到45~85个字符。

在CSS中控制一个段落文本长度主要是通过 CSS Intrinsic & Extrinsic Sizing Module Level 3 规范中的属性,比如说widthmax-width,而且CSS的ch单位在该场景就很能派上用场。因为1ch相当于阿拉伯数字0字符的宽度。它会随着字体和字号大小而变化。如果是中文排版,使用em更适合一些。另外,CSS中的word-spacingletter-spacing也会影响行长度中所含字符个数。

p {
    max-width: 65ch;
}

花了很长的篇幅和大家探讨了font-sizeline-height以及行长(Line Length)对Web文本排版的影响。其实这是一个复杂性的话题,更因为他们都是变量。@Matej Latin早在2017年发表了一篇《The Equilateral Triangle of a Perfect Paragraph》文章,探讨了这三者之间的关系以及对Web排版的影响。

另外有一个小Demo,可以让你更好的体验这三者之间的关系以及对排版可读性方面的影响。

Rhythm在排版中的运用

Web排版是影响可访问性的因素之一。Web的排版涉及到的知识点以及细节是非常的多。比如在垂直方向,很多时候要处理元素之间的间距,比如paddingmarginline-height等。

在排版中有一个专业的术语,即Rhythm。Rhythm是一个较为复杂的课题,这里不会做较详细的阐述,如果您感兴趣的话,可以自己去深入了解这方面的知识。接下来我们只会简单的了解一下该方面的知识。

在排版中,不管是水平方向还是垂直方向都有Rhythm的身影:

在水平方向可以借助CSS的letter-spacingfont-kerningtext-aligntext-indenthanging-punctuationlist-style-positionfont-varialbe等属性来控制。

对于垂直方向的Rhythm相比于水平方向的要更复杂的多,也正因为其复杂,很多开发同学难于掌握该方面的技巧,甚至选择性的忽略。和水平方向有点类似,控制垂直方向的Rhythm涉及到的CSS属性主要会有font-sizeline-heightmargin-top/bottompadding-top/bottomborder-top/bottom以及字体和字体方面的baseline

如果您对Rhythm方面的知识感兴趣的话,可以阅读下面这些参考资料:

也可以使用线上的Gridlover工具直接帮你计算出来:

文本的断行

在Web排版中难免离不开长文本的运行,那么在排版的时候就会碰到长文本撑破容器,从而影响用户阅读的体验。比如下面这种现象:

我们可以像下面这样来解决:

.hyphenate {
    overflow-wrap: break-word;
    word-wrap: break-word;
    hyphens: auto;
}

而CSS中处理断行或处理文本的CSS属性还有word-breakoverflow-wraphyphenslink-breaktext-wrap。这些属性不同的运用会得到不同的效果:

排版影响可访问性的其他CSS属性

有关于文本对于可访问性还有一些其他的细节,这些细节都将会受到CSS样式的影响。

不要使用两边对齐

有的时候很多同学为了让同一行保持相同的字符数或者让两边看起来对齐,会将text-align的值设置为justify。但该方案虽然在视觉上看上去段落文本距离容器边缘是平齐的,但同时为了达到此视觉效果,造成词与词之间的距离不均匀:

这些不均匀的空格会影响可读生,而且也会让用户分心

不要使用斜体

建议不要在文本排版中整段整段的使用斜体(font-style:italic)。会让用户阅读感到吃力:

特别是在一些特殊字体渲染的时候,更会增加阅读难度。尤其对于视力有障碍的用户阅读这种排版的内容更感吃力。

CSS的font-smoothing

把CSS的font-smoothing属性的subpixel换成antialiased可以使网站上的字体看起来更轻、更平滑,尤其是轻字体。但并不是说该方法适应于任何场景。如果你的阅读模式在Light模式下,将subpixel换成antialiased效果反而不好(其实两个效果都不怎么好):

但如果是Dark模式下,运用antialiased的效果会更佳:

CSS的text-rendering

使用text-rendering可以提高文本的渲染速度,易读性,并且在将来还可以强调渲染类型的几何精度。将该属性的值设置为optimizeLegibility,用户代理将强调易读性,有时通过启用边接或调整字体的间距让文本具有更好的可读性。

有关于Web排版中可读性和可访问性方面更多的资料,还可以阅读:

最后再给大家上一张@Marcella Jalbert在她的博文《How to design for readability – a guide to successful web typography》中提供的一张图,该图中有些信息上面有聊到过,有些没有聊到过。

事实上文本排版所涉及的知识和信息量非常多,而且其中很多都和可访问性有关。在一篇文章中是无法把所有东西和大家聊清楚的。后续我们可以再花时间来和大家一起讨论排版和可访问性方面的话题。

颜色对比度

为网站选择配色方案时,请确保文本(color)颜色与背景颜色(background-color)对比度良好。您的设计可能看起来很酷,但如果有视觉障碍(如色盲)的人无法阅读您的内容,则设计就无一好可做。

有一个简单的方法来检查您的对比度是否足够大,不会引起问题。有许多对比检查工具可以在线输入您的前景和背景颜色,以检查它们。例如,WebAIM 的颜色对比度检查器易于使用,并说明了您需要满足有关颜色对比度的 WCAG 标准的内容。

注意:高对比度还允许任何使用带有光面屏幕的智能手机或平板电脑的人在明亮的环境中(如阳光)更好地阅读页面。

另一个提示是不要仅仅依靠颜色来提供路标/信息,因为对于那些看不到颜色的人来说,这没有什么用。例如,不要用红色标记所需的表单字段,而是用星号和红色标记它们。

有关于这方面的讨论,在《创建可访问性网站并不是想得那么难》中也有讨论过,不过后面我们会在设计对可访问性影响的章节中和大家讨论。

控制视觉布局

熟悉Web的同学都知道,CSS可以很好的控制页面中元素的位置。从最早的table布局、float布局、position布局到现在的Flexbox布局和Grid布局。这些方案都可以让我们的页面布局或者视觉上的效果和设计师提供的UI风格是一致的,但这也意味着底层的源代码顺序(HTML源码结构)可能与视觉布局和显示顺序不匹配。另外,HTML的源码顺序它决定了屏幕阅读器的阅读顺序和键盘导航顺序。

就拿元素位置来说吧,在视觉上要改变他们的位置或者排列顺序,在CSS中的方法有很多。比如,Flexbox中的orderflex-directionflex-auto-flow等属性以及Grid中设置Grid项目位置的属性。这些属性虽然在视觉上能帮助我们改变顺序,但是也会造成DOM顺序和可视内容间的脱节。

不可预测的或错误的顺序不仅仅关系到键盘用户,也会影响屏幕阅读器的用户。或许你会问,屏幕阅读器不是按DOM顺序来读取内容,不受CSS的影响吗?你也可能会认为屏幕阅读器用户不关心内容的视觉表现。但事实并非如此,因为并不是所有使用屏幕阅读器的都是盲人。有些人有视力或学习障碍,也会使用屏幕阅读器来补充他们在屏幕上看到的内容。

上面所说的问题不仅在Flexbox和Grid中存在,而且在position中也存在。重要的是对内容进行排序,使其在没有样式的情况下有意义,然后检查它是否符合设计中的顺序。如果没有,你可能需要重新考虑你的设计。无论如何,不要因为无法在CSS中正确的定位元素而盲目地对HTML中的元素进行重新排序。

@Rob Dodson的《Does reordering content affect accessibility?》和@Adrian Roseelli的《Source Order Matters》在这方面做过深入的讨论,感兴趣的可以看看。

可点击区域应该足够大

可点击区域是不合理直接影响了用户和你的产品的交互,特别是在移动端。大家可能有碰到过,有些产品在按钮、链接、复选框或单选框等操作上就是失效,要点击很多次才能有效果。造成这种行为就是因为点击区域过小。可这种交互对于有行动障碍的用户来说也是致命的一种。

在社区中,有关于可点击区域大小给用户带来的体验是否合理,有较多的探讨,比如:

特别是在一些带可点击操作的图标上,Icon图标的实际尺寸并不适合一些系统的设计规范,在iOS上就提供Icon图标可点击区域应该是48px x 48px,如果你使用的图标小区该区域的话,我们就应该通过别的方式来进行扩展。其中在《伪元素能帮助我们做些什么》一文中介绍的伪元素就是一种很好的方式。

比如在一个卡片上,可以让整个卡片都具有可点击效应(click事件绑定在<button>或一个<a>)元素之上。如下图所示:

CSS伪类选择(或伪元素)助力表单控件的可访问性

表单是Web应用的重要组成部分之一。对于在线业务,它们是收集用户信息的有效方式。然而,用户常常在填写表单时犹豫不决。原因很多,比如糟糕的表单设计和太多的字段。为了获得访问者的信息,你需要一个简短的响应表单。它们应该是易于填充,而不是笨重或杂乱的。创建一个具有较好的用户体验的表单显得很重要,涉及的东西也比较多,比如响应、反应、感知和情绪等因素的组合。

表单设计有着诸多因素的结合,而且整个链路也较长。也正因为这些因素的存在,设计一个好的表单不易,设计一个具有可访问性的表单更不易。需要每一个环节都为其做出最好的设计。

有关于表单的最佳设计,这里不做更多的阐述,如果你感兴趣的话,可以阅读下面这些文章:

我们回到可访问性的表单中来。在《A11Y 101:编写HTML时要考虑可访问性》中也提到过,我们在构建表单模板是应该尽可能使用原生的表单控件

除了原生的表单控件标签元素之外,而且应该将相应的属性结合起来一起使用,这样除了能更好的利用好标签元素自带的属性之外,还可以减少我们额外的工作量。其中最为主要的是,使用这些原生的标签和相应的属性对于表单的可访问性能提供更好的体验。比如requiredminlengthpattern等就是原生的表单验证的一些属性。当用户在输入出错时,表单默认就会有一个很好的提示,如下图所示:

对于CSS来说,主要用来美化表单。其实在CSS中也有一些高级技巧,可以配合表单控件的一些属性来美化表单。比如CSS的一些伪类选择器

@Jonathan Harrell早在2017年就发表过一些高级CSS选择器对表单做的一些体验优化

上面所说的都是从一些原生的样式手段出发,其实要还原出一个更具可访问性的表单,要做的事情还是非常的多,不同的表单控件都有着不同的交互行为和UI效果,而且不同的平台还有差异性,比如我们所熟悉的<button>

也因为这个原因,为了让表单控件在不同的平台达到一致的UI风格,甚至是一致的交互效果,很多开发者采用自定义的方式来开发表单控件。采用自定义方式开发表单控件,除了增加了不少额外的工作量之外,对于可访问性也是一种伤害,特别是没有考虑可访问性细节的处理,更是如此。

正如上面所述,除了使用伪元素、伪类选择器之外,使用CSS设计表单控件UI时,我们应该尽可能的配合设计、交互以及可访问性来做。这样才能提供最好的可访问性表单。

有关于可访问性表单更多的介绍还可以阅读:

可聚焦元素样式设置

在《A11Y 101:构建可访问性应用的2W1H》一文中我们知道有一些用户群体属于行动障碍中的一部分:

对于有行动障碍的用户群体而言,访问性Web应用时主要依赖于键盘操作(还有一群高体依赖键盘的用户)。那么元素的焦点样式的设计对于这些群体来说是非常重要的。如果你阅读过《使用tabindex的正确姿势》一文的话,应该知道,在HTML原生标签元素中,有分可聚焦元素和非可聚焦元素之分。

对于不可聚焦的元素,如果想让其具有焦点,需要借助tabindex来增持。

可聚焦元素在不同的平台上有着自己独特的样式风格,比如说一个<input>,其获得焦点时,效果如下图所示:

如果希望在不同的平台上,让可聚焦元素在得到焦点时的样式趋于一致,我们可以在CSS中做几件事。

使用:focus给可聚焦元素添加样式

DOM元素可以继承下列任何状态:defaultfocushoveractive:

我们可以在上面的每一种状态下改变UI,比如我们使用:focus可以改变聚焦状态下的效果:

也就是说,我们可以使用:focus伪类选择器在可聚焦元素下设置样式,比如:

a:focus {
    background-color: #000;
    color: #fff; 
}

前面也提到了,不可聚焦的DOM元素也可以显式地在:focus状态下设置样式,只不过非聚焦元素无法使用Tab键获取焦点。

不同平台或者不同的设备客户端中默认焦点样式都是有差异的,甚至有些难看,而且在某些情况下它们不能很难达到设计师的要求。不过幸运的是,我们可以使用:focus来定制焦点样式,可以改进用户体验并适合您的设计需求。

不过有一点需要注意,不管你在:focus中怎么设计样式都可以,但不能用哪个是霸气的删除默认的outline样式,而不提供任何替代样式。因为这样做,对于依赖键盘作为主要导航方式的用户将无法知道自己在应用中的哪个位置(聚焦在哪个元素上),这样对于行动存有障碍的用户就不知道焦点在哪里。

这不仅仅是一个提示,而是一个AA级的标准

区分键盘用户和鼠标用户

正如前面所提到的,让设计师感到沮丧的事情之一是,浏览器之间在焦点样式方面有很多不致的地方;另一个令设计师沮丧的是,当用户在一些可聚焦元素上使用鼠标时,焦点样式也是可见的。对于使用鼠标的用户而言,设计师是不希望用户看到这样的焦点样式,因为这样的样式会分散用户的注意力,并造成审美上的不快。

这现象对于CSSer也是如此。

上一小节也提到过,无脑的删除outline属性并不是一个好的方案,因这样对于依赖于键盘的用户是不友好的,让他们无法知道访问的元素位置(用户并不知道导航到哪了)。更重要的是,我们需要的是一种区分键盘和鼠标用户的方法。在CSS选择器的Level4版本中提供了一个伪类 :focus-ring 可以开发者很好的区分键盘和鼠标用户。

/* 删除默认的outline样式 */
:focus {
    outline: none;
}

/* 只在应该可见的时候添加outline样式 */
:focus-ring {
    outline: 2px solid blue;
}

不幸的是,目前支持:focus-ring的浏览器并不多(Firefox可以使用-moz-focus-ring)。如果想提前使用该伪类选择器的话,可以使用Polyfill,它会在适当的时候添加一个.focus-ring类:

.js-focus-ring :focus:not(.focus-ring) {
    outline-width: 0;
}

有关于:focus-ring更多的细节可以阅读下面这些文章:

子元素获得焦点给父元素设置样式

有的时候我们希望某元素获得焦点的时候给该元素父容器或祖先容器添加样式。CSS的:focus-within可以很好的处理这样的需求:

代码很简单:

form:focus-within {
    box-shadow: 0 0 4px 6px rgba(80,88,156,0.2);
}

使用:focus-visible来选择性地显式焦点指示器

CSS的:focus-visible伪类选择器将在元素接收到焦点的任何时候应用,浏览器将通过启发式判断显示焦点指示器是否对用户有利。特别是,如果最近的用户交互是通过键盘进行的,并且按下的键不包含ALT/OPTIONCONTROL键,那么:focus-visible将能匹配到对应的元素。

button:focus-visible {  
    outline: 4px dashed orange;  
}  

有关于聚焦元素的焦点光环更多的介绍还可以参阅下面这些教程:

隐藏内容

在很多情况下,可视化设计需要并非同时显示所有内容。例如,我们有三个信息面板,但我们将它们放在彼此之上,并提供可以单击以显示每个选项卡的选项卡(也可以使用键盘 —— 您也可以使用 TabEnter/Return以选择它们)。

屏幕阅读器用户并不关心这些内容 , 只要资源的顺序有意义,他们就对内容感到满意, 并且他们可以获得所有内容。绝对定位(如本示例所示)通常被视为隐藏内容以进行视觉效果的最佳机制之一,因为它不会阻止屏幕阅读器访问它。

另一方面,不应使用 visibility:hiddendisplay:none,因为它们会隐藏屏幕阅读器中的内容。当然,除非您希望从屏幕阅读器中隐藏此内容,这是有充分理由的。

事实使用CSS隐藏元素(或图片替代文本)的方案还有很多种,具体的对比可以看下表:

众多方案中,我更推荐使用下面这种方案。该方案在让元素获得焦点的时候,隐藏的内容会显示出来,比如说使用tab键,定位到隐藏的元素时会显示出来:

.sr-only:not(:focus):not(:active) { 
    position: absolute; 
    height: 1px; 
    width: 1px; 
    clip: rect(1px 1px 1px 1px); 
    clip: rect(1px,1px,1px,1px); 
    clip-path: polygon(0px 0px, 0px 0px, 0px 0px); 
    overflow: hidden !important; 
}

该方案对于屏幕阅读器特别的友好。要是没使用sr-only来隐藏元素,而是采用aira-hidden="true"来隐藏元素的话,可以考虑@Nicolas Hoffmann提供的方案

有关于隐藏相关的话题还可以阅读:

针对特定的场景禁用动效

在Web中很多地方都能看到Web动效的身影,虽然动效应用好的话可以给Web起到锦上添花的效果,但是对于特定人群的话反而不是好事。因为有些动效对这些特殊的用户群体会造成不良的反应,会引起癫痫。为此,为了避免这种现象出现,媒体特性中提供了prefers-reduced-motion条件来做判断。只要用户在设备上开启了Reduce Motion功能:

并且在代码中显式的设置了:

@media (prefers-reduced-motion: reduce) {
    * {
        animation: none;
    }
}

那么Web中的动效就会自动失效,即没有动画效果。你也可以像下面这样来使用:

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.0s !important;
        transition-duration: 0.0s !important;
    }
}

有关于这方面更详细的使用可以阅读:

听觉样式

听觉样式这个概念我也是最近才听说过,有两个关键词Aural CSSSpeech CSS。在W3C规范中有相应的功能模块,即 CSS Speech Module

随着声音(音频)在Web使用的场景越来越多,大多数操作系统对Web Audio API有较好的支持,而且都有内置的旁白工具。像iOS的Siri这样的语音助手无处不在。对于这些音频,我们也需要面向音频的CSS,告诉数字化语言它应该如何读取内容,就像普通的CSS告诉浏览器如何渲染DOM元素一样。早期的听觉模块被弃用之后使用了CSS Speech模块。该模块与display: none一样,它是影响屏幕阅读器行为的一小部分CSS。它使用传统的CSS属性和值以及现有的声明来创建与可视盒模型等价的音频体验。比如:

code {
    background-color: #292a2b;
    color: #e6e6e6;
    font-family: monospace;
    speak: literal-punctuation; /* Reads all punctuation out loud in iOS VoiceOver */
}

同时也在 CSS Speech Module 中才得知原来还有听觉盒模型:

这是一个全新的概念和新的知识点,我也了解的不多,在这里只是想抛砖引玉,如果您感兴趣的话,可以阅读:

小结

作为CSS开发者而言,精确还原设计提供的UI稿子和实现业务逻辑之外还需要去关注用户体验,特别是Web可访问性。因为作为Web开发者,我们应该尽可能的去让每一位Web的访问者访问你的Web应用时具有平等的权利。

正如文章中所介绍的一样,开发一个具有可访问性的Web页面或应用,CSS方面的知识同等的重要,特别是在一些细节上。最后希望该文的内容有对于创建一个可访问性的Web应用有所帮助,如果你觉得这篇文章还不够过瘾的话,也可以花点时间阅读@Manuel Matuzovic的《Writing CSS with Accessibility in Mind》和MDN的《CSS 和 JavaScript 无障碍最佳实践》两篇文章。我想你会有所收获的。如果你在这方面有相关经验的话,也欢迎在下面的评论中与我们一起分享。