前端优秀实践不彻底指南

本文其实应该叫,Web 用户体验设计提高指南。css

一个 Web 页面,一个 APP,想让别人用的爽,也就是所谓的良好的用户体验,我以为他可能包括但不限于:html

  • 急速的打开速度
  • 眼前一亮的 UI 设计
  • 酷炫的动画效果
  • 丰富的个性化设置
  • 便捷的操做b
  • 贴心的细节
  • 关注残障人士,良好的可访问性
  • ...

所谓的用户体验设计,实际上是一个比较虚的概念,是秉承着以用户为中心的思想的一种设计手段,以用户需求为目标而进行的设计。设计过程注重以用户为中心,用户体验的概念从开发的最先期就开始进入整个流程,并贯穿始终。前端

良好的用户体验设计,是产品每个环节共同努力的结果。git

除去一些很难一蹴而就的,本文将就页面展现交互细节可访问性三个方面入手,罗列一些在实际的开发过程当中,积攒的一些有益的经验。经过本文,你将能收获到:github

  1. 了解到一些小细节是如何影响用户体验的
  2. 了解到如何在尽可能小的开发改动下,提高页面的用户体验
  3. 了解到一些优秀的交互设计细节
  4. 了解基本的无障碍功能及页面可访问性的含义
  5. 了解基本的提高页面可访问性的方法

页面展现

就整个页面的展现,页面内容的呈现而言,有一些小细节是须要咱们注意的。web

总体布局

先来看看一些布局相关的问题。编程

对于大部分 PC 端的项目,咱们首先须要考虑的确定是最外层的一层包裹。假设就是 .g-app-wrapperelement-ui

<div class="g-app-wrapper">
    <!-- 内部内容 -->
</div>

首先,对于 .g-app-wrapper,有几点,是咱们在项目开发前必须弄清楚的:后端

  1. 项目是全屏布局仍是定宽布局?
  2. 对于全屏布局,须要适配的最小的宽度是多少?

对于定宽布局,就比较方便了,假设定宽为 1200px,那么:浏览器

.g-app-wrapper {
    width: 1200px;
    margin: 0 auto;
}

利用 margin: 0 auto 实现布局的水平居中。在屏幕宽度大于 1200px 时,两侧留白,固然屏幕宽度小于 1200px 时,则出现滚动条,保证内部内容不乱。

layout1

对于现代布局,更多的是全屏布局。其实如今也更提倡这种布局,即便用可随用户设备的尺寸和能力而变化的自适应布局。

一般而言是左右两栏,左侧定宽,右侧自适应剩余宽度,固然,会有一个最小的宽度。那么,它的布局应该是这样:

<div class="g-app-wrapper">
    <div class="g-sidebar"></div>
    <div class="g-main"></div>
</div>
.g-app-wrapper {
    display: flex;
    min-width: 1200px;
}
.g-sidebar {
    flex-basis: 250px;
    margin-right: 10px;
}
.g-main {
    flex-grow: 1;
}

layout2

利用了 flex 布局下的 flex-grow: 1,让 .main 进行伸缩,占满剩余空间,利用 min-width 保证了整个容器的最小宽度。

固然,这是最基本的自适应布局。对于现代布局,咱们应该尽量的考虑更多的场景。作到:

image

底部 footer

下面一种情形也是很是常见的一个情景。

页面存在一个 footer 页脚部分,若是整个页面的内容高度小于视窗的高度,则 footer 固定在视窗底部,若是整个页面的内容高度大于视窗的高度,则 footer 正常流排布(也就是须要滚动到底部才能看到 footer)。

看看效果:

margintopauto

嗯,这个需求若是可以使用 flex 的话,使用 justify-content: space-between 能够很好的解决,同理使用 margin-top: auto 也很是容易完成:

<div class="g-container">
    <div class="g-real-box">
        ...
    </div>
    <div class="g-footer"></div>
</div>
.g-container {
    height: 100vh;
    display: flex;
    flex-direction: column;
}

.g-footer {
    margin-top: auto;
    flex-shrink: 0;
    height: 30px;
    background: deeppink;
}

Codepen Demo -- sticky footer by flex margin auto

固然,实现它的方法有不少,这里仅给出一种推荐的解法。

处理动态内容 - 文本超长

对于全部接收后端接口字段的文本展现类的界面。都须要考虑全面(防护性编程:全部的外部数据都是不可信的),正常状况以下,是没有问题的。

image

可是咱们是否考虑到了文本会超长?超长了会折行仍是换行?

image

对于单行文本,使用单行省略:

{
    width: 200px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

image

固然,目前对于多行文本的超长省略,兼容性也已经很是好了:

{
    width: 200px;
    overflow : hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

image

处理动态内容 - 保护边界

对于一些动态内容,咱们常用 min/max-widthmin/max-height 对容器的高宽限度进行合理的控制。

在使用它们的时候,也有一些细节须要考虑到。

譬如常常会使用 min-width 控制按钮的最小宽度:

.btn {
    ...
    min-width: 120px;
}

image

当内容比较少的时候是没问题的,可是当内容比较长,就容易出现问题。使用了 min-width 却没考虑到按钮的过长的状况:

image

这里就须要配合 padding 一块儿:

.btn {
    ...
    min-width: 88px;
    padding: 0 16px
}

借用Min and Max Width/Height in CSS中一张很是好的图,做为释义:

min-width-2

0 内容展现

这个也是一个经常被忽略的地方。

页面常常会有列表搜索,列表展现。那么,既然存在有数据的正常状况,固然也会存在搜索不到结果或者列表无内容可展现的情形。

对于这种状况,必定要注意 0 结果页面的设计,同时也要知道,这也是引导用户的好地方。对于 0 结果页面,分清楚:

  • 数据为空:其中又可能包括了用户无权限、搜索无结果、筛选无结果、页面无数据
  • 异常状态:其中又可能包括了网络异常、服务器异常、加载失败等待

不一样的状况可能对应不一样的 0 结果页面,附带不一样的操做引导。

譬如网络异常:

image

或者确实是 0 结果:

image

关于 0 结果页面设计,能够详细看看这篇文章:如何设计产品的空白页面?

小小总结一下,上述比较长的篇幅一直都在阐述一个道理,开发时,不能仅仅关注正常现象,要多考虑各类异常状况,思考全面。作好各类可能状况的处理

图片相关

图片在咱们的业务中应该是很是的常见了。有一些小细节是须要注意的。

给图片同时设置高宽

有的时候和产品、设计会商定,只能使用固定尺寸大小的图片,咱们的布局多是这样:

image

对应的布局:

<ul class="g-container">
    <li>
        <img src="http://placehold.it/150x100">
        <p>图片描述</p>
    </li>
</ul>
ul li img {
    width: 150px;
}

固然,万一假设后端接口出现一张非正常大小的图片,上述不加保护的布局就会出问题:

image

因此对于图片,咱们老是建议同时写上高和宽,避免由于图片尺寸错误带来的布局问题:

ul li img {
    width: 150px;
    height: 100px;
}

同时,给 <img> 标签同时写上高宽,能够在图片未加载以前提早占住位置,避免图片从未加载状态到渲染完成状态高宽变化引发的重排问题。

object-fit

固然,限制高宽也会出现问题,譬如图片被拉伸了,很是的难看:

image

这个时候,咱们能够借助 object-fit,它可以指定可替换元素的内容(也就是图片)该如何适应它的父容器的高宽。

ul li img {
    width: 150px;
    height: 100px;
    object-fit: cover;
}

利用 object-fit: cover,使图片内容在保持其宽高比的同时填充元素的整个内容框。

image

object-fit 还有一个配套属性 object-position,它能够控制图片在其内容框中的位置。(相似于 background-position),m默认是 object-position: 50% 50%,若是你不但愿图片居中展现,可使用它去改变图片实际展现的 position 。

ul li img {
    width: 150px;
    height: 100px;
    object-fit: cover;
    object-position: 50% 100%;
}

image

像是这样,object-position: 100% 50% 指明从底部开始展现图片。这里有一个很好的 Demo 能够帮助你理解 object-position

CodePen Demo -- Object position

考虑屏幕 dpr -- 响应式图片

正常状况下,图片的展现应该没有什么问题了。可是对于有图片可展现的状况下,咱们还能够作的更好。

在移动端或者一些高清的 PC 屏幕(苹果的 MAC Book),屏幕的 dpr 可能大于 1。这种时候,咱们可能还须要考虑利用多倍图去适配不一样 dpr 的屏幕。

正好,<img> 标签是有提供相应的属性 srcset 让咱们进行操做的。

<img src='photo@1x.png'
   srcset='photo@1x.png 1x,
           photo@2x.png 2x,
           photo@3x.png 3x' 
/>

固然,这是比较旧的写法,srcset 新增了新的 w 宽度描述符,须要配合 sizes 一块儿使用,因此更好的写法是:

<img 
        src = "photo.png" 
        sizes = “(min-width: 600px) 600px, 300px" 
        srcset = “photo@1x.png 300w,
                       photo@2x.png 600w,
                       photo@3x.png 1200w,
>

利用 srcset,咱们能够给不一样 dpr 的屏幕,提供最适合的图片。

上述出现了一些概念,dpr,图片的 srcset ,sizes 属性,,不太了解的能够移步 前端基础知识概述

图片丢失

好了,当图片连接没问题时,已经处理好了。接下来还须要考虑,当图片连接挂了,应该如何处理。

处理的方式有不少种。最好的处理方式,是我最近在张鑫旭老师的这篇文章中 -- 图片加载失败后CSS样式处理最佳实践 看到的。这里简单讲下:

  1. 利用图片加载失败,触发 <img> 元素的 onerror 事件,给加载失败的 <img> 元素新增一个样式类
  2. 利用新增的样式类,配合 <img> 元素的伪元素,展现默认兜底图的同时,还能一块儿展现 <img> 元素的 alt 信息
<img src="test.png" alt="图片描述" onerror="this.classList.add('error');">
img.error {
    position: relative;
    display: inline-block;
}

img.error::before {
    content: "";
    /** 定位代码 **/
    background: url(error-default.png);
}

img.error::after {
    content: attr(alt);
    /** 定位代码 **/
}

咱们利用伪元素 before ,加载默认错误兜底图,利用伪元素 after,展现图片的 alt 信息:

image

OK,到此,完整的对图片的处理就算完成了,完整的 Demo 你能够戳这里看看:

CodePen Demo -- 图片处理

交互设计优化

接下来一个大环节是关于一些交互的细节。对于交互设计,一些比较通用的准则:

  • Don’t make me think
  • 符合用户的习惯与预期
  • 操做便利
  • 作适当的提醒
  • 不强迫用户

过渡与动画

在咱们的交互过程当中,适当的增长过渡与动画,可以很好的让用户感知到页面的变化

譬如咱们页面上随处可见 loading 效果,其实就是这样一种做用,让用户感知页面正在加载,或者正在处理某些事务。

滚动优化

滚动也是操做网页中很是重要的一环。看看有哪些能够优化的点:

滚动平滑:使用 scroll-behavior: smooth 让滚动丝滑

使用 scroll-behavior: smooth,可让滚动框实现平稳的滚动,而不是突兀的跳动。看看效果,假设以下结构:

<div class="g-container">
  <nav>
    <a href="#1">1</a>
    <a href="#2">2</a>
    <a href="#3">3</a>
  </nav>
  <div class="scrolling-box">
    <section id="1">First section</section>
    <section id="2">Second section</section>
    <section id="3">Third section</section>
  </div>
</div>

不使用 scroll-behavior: smooth,是突兀的跳动切换:

scrol

给可滚动容器添加 scroll-behavior: smooth,实现平滑滚动:

{
    scroll-behavior: smooth;
}

scroll2

使用 scroll-snap-type 优化滚动效果

sroll-snap-type 可能算得上是新的滚动规范里面最核心的一个属性样式。

scroll-snap-type:属性定义在滚动容器中的一个临时点(snap point)如何被严格的执行。

光看定义有点难理解,简单而言,这个属性规定了一个容器是否对内部滚动动做进行捕捉,而且规定了如何去处理滚动结束状态。让滚动操做结束后,元素中止在适合的位置。

看个简单示例:

固然,scroll-snap-type 用法很是多,可控制优化的点不少,限于篇幅没法一一展开,具体更详细的用法能够看看个人另一篇文章 -- 使用 sroll-snap-type 优化滚动

控制滚动层级,避免页面大量重排

这个优化可能稍微有一点难理解。须要了解 CSS 渲染优化的相关知识。

先说结论,控制滚动层级的意思是尽可能让须要进行 CSS 动画(能够是元素的动画,也能够是容器的滚动)的元素的 z-index 保持在页面最上方,避免浏览器建立没必要要的图形层(GraphicsLayer),可以很好的提高渲染性能

这一点怎么理解呢,一个元素触发建立一个 Graphics Layer 层的其中一个因素是:

  • 元素有一个 z-index 较低且包含一个复合层的兄弟元素

根据上述这点,咱们对滚动性能进行优化的时候,须要注意两点:

  1. 经过生成独立的 GraphicsLayer,利用 GPU 加速,提高滚动的性能
  2. 若是自己滚动没有性能问题,不须要独立的 GraphicsLayer,也要注意滚动容器的层级,避免由于层级太高而被其余建立了 GraphicsLayer 的元素合并,被动的生成一个 Graphics Layer ,影响页面总体的渲染性能

若是你对这点还有点懵,能够看看这篇文章 -- 你所不知道的 CSS 动画技巧与细节

点击交互优化

在用户点击交互方面,也有一些有意思的小细节。

优化手势 -- 不一样场景应用不一样 cursor

对于不一样的内容,最好给与不一样的 cursor 样式,CSS 原生提供很是多种经常使用的手势。

在不一样的场景使用不一样的鼠标手势,符合用户的习惯与预期,能够很好的提高用户的交互体验。

首先对于按钮,就至少会有 3 种不一样的 cursor,分别是可点击,不可点击,等待中:

{
    cursor: pointer;    // 可点击
    cursor: not-allowed;    // 不可点击
    cursor: wait;    // loading
}

image

除此以外,还有一些常见的,对于一些可输入的 Input 框,使用 cursor: text,对于提示 Tips 类使用 cursor: help,放大缩小图片 zoom-inzoom-out 等等:

image

一些经常使用的简单列一列:

  • 按钮可点击: cursor: pointer
  • 按钮禁止点击:cursor: not-allowed
  • 等待 Loading 状态:cursor: wait
  • 输入框:cursor: text;
  • 图片查看器可放大可缩小:cursor: zoom-in/ zoom-out
  • 提示:cursor: help;

固然,实际 cursor 还支持很是多种,能够在 MDN 或者下面这个 CodePen Demo 中查看这里看完整的列表:

CodePen Demo -- Cursor Demo

点击区域优化 -- 伪元素扩大点击区域

按钮是咱们网页设计中十分重要的一环,而按钮的设计也与用户体验息息相关。

考虑这样一个场景,在摇晃的车箱上或者是单手操做着屏幕,有的时候一个按钮,死活也点不到。

让用户更容易的点击到按钮无疑能很好的增长用户体验及可提高页面的访问性,尤为是在移动端,按钮一般都很小,可是受限于设计稿或者总体 UI 风格,咱们不能直接去改变按钮元素的高宽。

那么这个时候有什么办法在不改变按钮本来大小的状况下去增长他的点击热区呢?

这里,伪元素也是能够表明其宿主元素来响应的鼠标交互事件的。借助伪元素能够轻松帮咱们实现,咱们能够这样写:

.btn::before{
  content:"";
  position:absolute;
  top:-10px;
  right:-10px;
  bottom:-10px;
  left:-10px;
}

固然,在 PC 端下这样子看起来有点奇怪,可是合理的用在点击区域较小的移动端则能取到十分好的效果,效果以下:

608782-20160527112625428-906375003

在按钮的伪元素没有其它用途的时候,这个方法确实是个很好的提高用户体验的点。

快速选择优化 -- user-select: all

操做系统或者浏览器一般会提供一些快速选取文本的功能,看看下面的示意图:

layout3

快速单击两次,能够选中单个单词,快速单击三次,能够选中一整行内容。可是若是有的时候咱们的核心内容,被分隔符分割,或者潜藏在一整行中的一部分,这个时候选取起来就比较麻烦。

利用 user-select: all,能够将须要一次选中的内容进行包裹,用户只须要点击一次,就能够选中该段信息:

.g-select-all {
    user-select: all
}

给须要一次选中的信息,加上这个样式后的效果,这个细节做用在一些须要复制粘贴的场景,很是好用:

layout4

CodePen -- user-select: all 示例

选中样式优化 -- ::selection

固然,若是你想更进一步,CSS 还有提供一个 ::selection 伪类,能够控制选中的文本的样式(只能控制color, background, text-shadow),进一步加深效果。

layout5

CodePen -- user-select: all && ::selection 控制选中样式

添加禁止选择 -- user-select: none

有快速选择,也就会有它的对立面 -- 禁止选择。

对于一些可能频繁操做的按钮,可能出现以下尴尬的场景:

  • 文本按钮的快速点击,触发了浏览器的双击快速选择,致使文本被选中:

btn-click

  • 翻页按钮的快速点击,触发了浏览器的双击快速选择:

img-click

对于这种场景,咱们须要把不可被选中元素设置为不可被选中,利用 CSS 能够快速的实现这一点:

{
    -webkit-user-select: none; /* Safari */
    -ms-user-select: none; /* IE 10 and IE 11 */
    user-select: none; /* Standard syntax */
}

这样,不管点击的频率多快,都不会出现尴尬的内容选中:

btn-click-unselect

跳转优化

现阶段,单页应用(Single Page Application)的应用很是普遍,Vue 、React 等框架大行其道。可是一些常见的写法,也容易衍生一些小问题。

譬如,点击按钮、文本进行路由跳转。譬如,常常会出现这种代码:

<template>
    ...
    <button @click="gotoDetail">
        Detail
    </button>
    ...
<template>
...
gotoDetail() {
    this.$router.push({
      name: 'xxxxx',
    });
}

大体逻辑就是给按钮添加一个事件,点击以后,跳转到另一个路由。固然,自己这个功能是没有任何问题的,可是没有考虑到用户实际使用的场景。

实际使用的时候,因为是一个页面跳转,不少时候,用户但愿可以保留当前页面的内容,同时打开一个新的窗口,这个时候,他会尝试下的鼠标右键,选择在新标签页中打开页面,遗憾的是,上述的写法是不支持鼠标右键打开新页面的。

缘由在于浏览器是经过读取 <a> 标签的 href 属性,来展现相似在新标签页中打开页面这种选项,对于上述的写法,浏览器是没法识别它是一个能够跳转的连接。简单的示意图以下:

image

因此,对于全部路由跳转按钮,建议都使用 <a> 标签,而且内置 href 属性,填写跳转的路由地址。实际渲染出来的 DOM 多是须要相似这样:

<a href="/xx/detail">Detail</a>

易用性

易用性也是交互设计中须要考虑的一个很是重要的环节,能作的有很是多。简单的罗列一下:

  • 注意界面元素的一致性,下降用户学习成本
  • 延续用户平常的使用习惯,而不是从新创造
  • 给下拉框增长一些预设值,下降用户填写成本
  • 同类的操做合并在一块儿,下降用户的认知成本
  • 任何操做以后都要给出反馈,让用户知道操做已经生效

先探索,后表态

这一点很是的有意思,什么叫先探索后表态呢?就是咱们不要一上来就强迫用户去作一些事情,譬如登陆。

想想一些经常使用网站的例子:

  • 相似虎牙、Bilibili 等视频网站,能够先蓝光体验,必定观看时间后才会要求登陆
  • 电商网站,只有到付款的时候,才须要登陆

上述易用性先探索,后表态的内容,部分来源于:Learn From What Leading Companies A/B Test,能够好好读一读。

字体优化

字体的选择与使用实际上是很是有讲究的。

若是网站没有强制必须使用某些字体。最新的规范建议咱们更多的去使用系统默认字体。也就是 CSS Fonts Module Level 4 -- Generic font families 中新增的 font-family: system-ui 关键字。

font-family: system-ui 可以自动选择本操做系统下的默认系统字体。

默认使用特定操做系统的系统字体能够提升性能,由于浏览器或者 webview 没必要去下载任何字体文件,而是使用已有的字体文件。 font-family: system-ui 字体设置的优点之处在于它与当前操做系统使用的字体相匹配,对于文本内容而言,它能够获得最恰当的展现。

举两个例子,天猫的字体定义与 Github 的字体定义:

  • 天猫font-family: "PingFang SC",miui,system-ui,-apple-system,BlinkMacSystemFont,Helvetica Neue,Helvetica,sans-serif;
  • Githubfont-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;

简单而言,它们整体遵循了这样一个基本原则:

一、尽可能使用系统默认字体

使用系统默认字体的主要缘由是性能,而且系统字体的优势在于它与当前操做系统使用的相匹配,所以它的文本展现必然也是一个让人温馨展现效果。

二、兼顾中西,西文在前,中文在后

中文或者西文(英文)都要考虑到。因为大部分中文字体也是带有英文部分的,可是英文部分又不怎么好看,可是英文字体中大多不包含中文。一般会先进行英文字体的声明,选择最优的英文字体,这样不会影响到中文字体的选择,中文字体声明则紧随其次。

三、兼顾多操做系统

选择字体的时候要考虑多操做系统。例如 MAC OS 下的不少中文字体在 Windows 都没有预装,为了保证 MAC 用户的体验,在定义中文字体的时候,先定义 MAC 用户的中文字体,再定义 Windows 用户的中文字体;

四、兼顾旧操做系统,以字体族系列 serif 和 sans-serif 结尾

当使用一些很是新的字体时,要考虑向下兼容,兼顾到一些极旧的操做系统,使用字体族系列 serif 和 sans-serif 结尾总归是不错的选择。

对于上述的一些字体可能会有些懵,譬如 -apple-system, BlinkMacSystemFont,这是由于不一样浏览器厂商对规范的实现有所不一样,对于字体定义更多的相关细节,能够再看看这篇文章 -- Web 字体 font-family 再探秘

可访问性(A11Y)

可访问性,在咱们的网站中,属于很是重要的一环,可是大部分前端(其实应该是设计、前端、产品)同窗都会忽视它。

我潜伏在一个叫 无障碍设计小组的群里,其中包含了不少无障碍设计师以及患有必定程度视觉、听力、行动障碍的用户,他们在群里常常会表达出一个观点,就是国内的大部分 Web 网站及 APP 基本没有考虑过残障人士的使用(或者可访问性作的很是差),很是的使人揪心。

尤为在咱们一些重交互、重逻辑的网站中,咱们须要考虑用户的使用习惯、使用场景,从高可访问性的角度考虑,譬如假设用户没有鼠标,仅仅使用键盘,可否顺畅的使用咱们的网站?

假设用户没有鼠标,这个真不必定是针对残障人士,不少状况下,用户拿鼠标的手可能在干其余事情,好比在吃东西,又或者在 TO B 类的业务,如超市收银、仓库收货,极可能用户拿鼠标的手操做着其余设备(扫码枪)等等。

本文不会专门阐述无障碍设计的方方面面,只是从一些我以为前端工程师须要关注的,而且仅须要花费少许代价就能作好的一些无障碍设计细节。记住,无障碍设计对全部人都更友善

色彩对比度

颜色,也是咱们每天须要打交道的属性。对于大部分视觉正常的用户,可能对页面的颜色敏感度还没那么高。可是对于一小部分色弱、色盲用户,他们对于网站的颜色会更加敏感,很差的设计会给他们访问网站带来极大的不便。

什么是色彩对比度

是否曾关心过页面内容的展现,使用的颜色是否恰当?色弱、色盲用户可否正常看清内容?良好的色彩使用,在任什么时候候都是有益的,并且不只仅局限于对于色弱、色盲用户。在户外用手机、阳光很强看不清,符合无障碍标准的高清晰度、高对比度文字就更容易阅读。

这里就有一个概念 -- 颜色对比度,简单地说,描述就是两种颜色在亮度(Brightness)上的差异。运用到咱们的页面上,大多数的状况就是背景色(background-color)与内容颜色(color)的对比差别。

最权威的互联网无障碍规范 —— WCAG AA规范规定,全部重要内容的色彩对比度须要达到 4.5:1 或以上(字号大于18号时达到 3:1 或以上),才算拥有较好的可读性。

借用一张图 -- 知乎 -- 助你轻松作好无障碍的15个UI设计工具推荐

很明显,上述最后一个例子,文字已经很是的不清晰了,正经常使用户都已经很难看得清了。

检查色彩对比度的工具

Chrome 浏览器从很早开始,就已经支持检查元素的色彩对比度了。以我当前正在写做的页面为例子,Github Issues 编辑页面的两个按钮:

image

审查元素,分别能够看到两个按钮的色彩对比度:

image

能够看到,绿底白字按钮的色彩对比度是没有达到标准的,也被用黄色的叹号标识了出来。

除此以外,在审查元素的 Style 界面的取色器,改变颜色,也能直观的看到当前的色彩对比度:

image

焦点响应

相似百度、谷歌的首页,进入页面后会默认让输入框得到焦点:

image

并不是全部的有输入框的页面,都须要进入页面后进行聚焦,可是焦点可以让用户很是明确的知道,当前本身在哪,须要作些什么。尤为是对于没法操做鼠标的用户。

页面上能够聚焦的元素,称为可聚焦元素,得到焦点的元素,则会触发该元素的 focus 事件,对应的,也就会触发该元素的 :focus 伪类。

浏览器一般会使用元素的 :focus 伪类,给元素添加一层边框,告诉用户,当前的获焦元素在哪里。

咱们能够经过键盘的 Tab 键,进行焦点的切换,而获焦元素则能够经过元素的 :focus 伪类的样式,告诉用户当前焦点位置。

固然,除了 Tab 键以外,对于一些多输入框、选择框的表单页面,咱们也应该想着如何简化用户的操做,譬如用户按回车键时自动前进到下一字段。通常而言,用户必须执行的触按越少,体验越佳。

下面的截图,彻底由键盘操做完成

a11y

经过元素的 :focus 伪类以及键盘 Tab 键切换焦点,用户能够很是顺畅的在脱离鼠标的状况下,对页面的焦点切换及操做。

然而,在许多 reset.css 中,常常能看到这样一句 CSS 样式代码,为了样式的统一,消除了可聚焦元素的 :focus 伪类:

:focus {
    outline: 0;
}

咱们给上述操做的代码。也加上这样一句代码,全程再用键盘操做一下

a11y2

除了在 input 框有光标提示,当使用 Tab 进行焦点切换到 select 或者到 button 时,因为没有了 :focus 样式,用户将彻底懵逼,不知道页面的焦点如今处于何处。

保证非鼠标用户体验,合理运用 :focus-visible

固然,形成上述结果很重要的一个缘由在于。:focus 伪类不论用户在使用鼠标仍是使用键盘,只要元素获焦,就会触发。

而其自己的默认样式又不太能被产品或者设计接受,致使了不少人会在焦点元素触发 :focus 伪类时,经过改变 border 的颜色或者其余一些方式替代或者直接禁用。而这样作,从可访问性的角度来看,对于非鼠标用户,无疑是灾难性的。

基于此,在W3 CSS selectors-4 规范 中,新增了一个很是有意思的 :focus-visible 伪类。

:focus-visible:这个选择器能够有效地根据用户的输入方式(鼠标 vs 键盘)展现不一样形式的焦点。

有了这个伪类,就能够作到,当用户使用鼠标操做可聚焦元素时,不展现 :focus 样式或者让其表现较弱,而当用户使用键盘操做焦点时,利用 :focus-visible,让可获焦元素得到一个较强的表现样式。

看个简单的 Demo:

<button>Test 1</button>
button:active {
  background: #eee;
}
button:focus {
  outline: 2px solid red;
}

使用鼠标点击:

a11y3

能够看到,使用鼠标点击的时候,触发了元素的 :active 伪类,也触发了 :focus伪类,不太美观。可是若是设置了 outline: none 又会使键盘用户的体验很是糟糕。尝试使用 :focus-visible 伪类改造一下:

button:active {
  background: #eee;
}
button:focus {
  outline: 2px solid red;
}
button:focus:not(:focus-visible) {
  outline: none;
}

看看效果,分别是在鼠标点击 Button 和使用键盘控制焦点点击 Button:

a11y4

CodePen Demo -- :focus-visible example

能够看到,使用鼠标点击,不会触发 :foucs,只有当键盘操做聚焦元素,使用 Tab 切换焦点时,outline: 2px solid red 这段代码才会生效。

这样,咱们就既保证了正经常使用户的点击体验,也保证了一批没法使用鼠标的用户的焦点管理体验。

值得注意的是,有同窗会疑惑,这里为何使用了 :not 这么绕的写法而不是直接这样写呢:

button:focus {
  outline: unset;
}
button:focus-visible {
  outline: 2px solid red;
}

为的是兼容不支持 :focus-visible 的浏览器,当 :focus-visible 不兼容时,仍是须要有 :focus 伪类的存在。

使用 WAI-ARIA 规范加强语义 -- div 等非可获焦元素模拟获焦元素

还有一个很是须要注意的点。

如今不少前端同窗在前端开发的过程当中,喜欢使用非可获焦元素模拟获焦元素,譬如:

  • 使用 div 模拟 button 元素
  • 使用 ul 模拟下拉列表 select 等等

当下不少组件库都是这样作的,譬如 element-ui 和 ant-design。

在使用非可获焦元素模拟获焦元素的时候,必定要注意,不只仅只是外观长得像就完事了,其行为表现也须要符合本来的 buttonselect 等可聚焦元素的性质,可以体现元素的语义,可以被聚焦,可以经过 Tab 切换等等。

基于大量相似的场景,有了 WAI-ARIA 标准,WAI-ARIA是一个为残疾人士等提供无障碍访问动态、可交互Web内容的技术规范。

简单来讲,它提供了一些属性,加强标签的语义及行为:

  • 可使用 tabindex 属性控制元素是否能够聚焦,以及它是否/在何处参与顺序键盘导航
  • 可使用 role 属性,来标识元素的语义及做用,譬如使用 <div id="saveChanges" tabindex="0" role="button">Save</div> 来模拟一个按钮
  • 还有大量的 aria-* 属性,表示元素的属性或状态,帮助咱们进一步地识别以及实现元素的语义化,优化无障碍体验

使用工具查看标签的语义

咱们来看看 Github 页面是如何定义一个按钮的,以 Github Issues 页面的 Edit 按钮为例子:

image

这一块,清晰的描述了这个按钮在可访问性相关的一些特性,譬如 Contrast 色彩对比度,按钮的描述,也就是 Name,是给屏幕阅读器看到的,Role 标识是这个元素的属性,它是一个按钮,Keyboard focusable 则代表他可否被键盘的 Tab 按钮给捕获。

分析使用非可聚焦元素模拟的按钮

这里,我随便选取了咱们业务中一个使用 span 模拟按钮的场景,是一个面包屑导航,点击可进行跳转,发现惨不忍睹:

image

HTML 代码:

<span class="ssc-breadcrumb-item-link"> Inbound </span>

image

基本上可访问性为 0,做为一个按钮,它不可被聚焦,没法被键盘用户选中,没有具体的语义,色彩对比度过低,可能视障用户没法看清。而且,做为一个能进行页面跳转的按钮,它没有不是 a 标签,没有 href 属性。

即使对于面包屑导航,咱们能够不将它改形成 <a> 标签,也须要作到最基本的一些可访问性改造:

<span role="button" aria-label="goto inbound page" tabindex="0" class="ssc-breadcrumb-item-link"> Inbound </span>

不要忘了再改一下颜色,达到最低色彩对比度以上,再看看:

image

OK,这样,一个最最最基本的,知足最低可访问性需求的按钮算是勉强达标,固然,这个按钮能够再更进一步进行改造,涉及了更深刻的可访问性知识,本文不深刻展开。

分析组件库的 A11Y

最后,在咱们比较经常使用的 Vue - element-ui、React - ant-design 中,咱们来看看 ant-design 在提高可访问性相关的一些功能。

以 Select 选择框组件为例,ant-design 利用了大量的 WAI-ARIA 属性,使得用 div 模拟的下拉框不只仅在表现上符合一个下拉框,在语义、行为上都符合一个下拉框,简单的一个例子:

image

看看使用 div 模拟下拉框的 DOM 部分:

image

再看看在交互体验上:

a11y5

上述操做全是在键盘下完成,看着平平无奇,实际上组件库在正常响应可获焦元素切换的同时,给用 div 模拟的 select 加了不少键盘事件的响应,能够利用回车,上下键等对可选项进行选择。实际上是下了不少功夫。

对于 A11Y 相关的内容,篇幅及内容很是之多,本文没法一一展开,感兴趣的能够通读下下列文章:

总结一下

本文从页面展现交互细节可访问性三个大方面入手,罗列一些在实际的开发过程当中,积攒的一些有益的经验。虽然不够全面,不过从一开始也就没想着大而全,主要是一些可能有用可是容易被忽视的点,也算是一个不错的查缺补漏小指南。

固然,不少都是我我的的观点想法,可能有一些理解存在一些问题,一些概念没有解读到位,也但愿你们帮忙指出。

最后

本文到此结束,但愿对你有帮助 :)

想 Get 到最有意思的 CSS 资讯,千万不要错过个人公众号 -- iCSS前端趣闻 😄

gzh_small.png

更多精彩 CSS 技术文章汇总在个人 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

若是还有什么疑问或者建议,能够多多交流,原创文章,文笔有限,才疏学浅,文中如有不正之处,万望告知。

相关文章
相关标签/搜索