如下文章來源於iCSS前端趣聞 ,做者SbCococss
iCSS前端趣聞 不止於 CSShtml
本文略長,耐下心好好讀讀,應該會有所收穫~前端
其實標題應該叫,Web 用戶體驗設計提高指南。vue
一個 Web 頁面,一個 APP,想讓別人用的爽,也就是所謂的良好的用戶體驗,我以爲他可能包括但不限於:git
所謂的用戶體驗設計,實際上是一個比較虛的概念,是秉承着以用戶爲中心的思想的一種設計手段,以用戶需求爲目標而進行的設計。設計過程注重以用戶爲中心,用戶體驗的概念從開發的最先期就開始進入整個流程,並貫穿始終。github
良好的用戶體驗設計,是產品每個環節共同努力的結果。web
除去一些很難一蹴而就的,本文將就頁面展現、交互細節、可訪問性三個方面入手,羅列一些在實際的開發過程當中,積攢的一些有益的經驗。經過本文,你將能收穫到:編程
就整個頁面的展現,頁面內容的呈現而言,有一些小細節是須要咱們注意的。element-ui
先來看看一些佈局相關的問題。後端
對於大部分 PC 端的項目,咱們首先須要考慮的確定是最外層的一層包裹。假設就是 .g-app-wrapper
。
<div class="g-app-wrapper"> <!-- 內部內容 --> </div>
首先,對於 .g-app-wrapper
,有幾點,是咱們在項目開發前必須弄清楚的:
對於定寬佈局,就比較方便了,假設定寬爲 1200px
,那麼:
.g-app-wrapper { width: 1200px; margin: 0 auto; }
利用 margin: 0 auto
實現佈局的水平居中。在屏幕寬度大於 1200px
時,兩側留白,固然屏幕寬度小於 1200px
時,則出現滾動條,保證內部內容不亂。
對於現代佈局,更多的是全屏佈局。其實如今也更提倡這種佈局,即便用可隨用戶設備的尺寸和能力而變化的自適應佈局。
一般而言是左右兩欄,左側定寬,右側自適應剩餘寬度,固然,會有一個最小的寬度。那麼,它的佈局應該是這樣:
<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; }
利用了 flex 佈局下的 flex-grow: 1
,讓 .main
進行伸縮,佔滿剩餘空間,利用 min-width
保證了整個容器的最小寬度。
固然,這是最基本的自適應佈局。對於現代佈局,咱們應該儘量的考慮更多的場景。作到:
下面一種情形也是很是常見的一個情景。
頁面存在一個 footer 頁腳部分,若是整個頁面的內容高度小於視窗的高度,則 footer 固定在視窗底部,若是整個頁面的內容高度大於視窗的高度,則 footer 正常流排布(也就是須要滾動到底部才能看到 footer)。
看看效果:
嗯,這個需求若是可以使用 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[1]
固然,實現它的方法有不少,這裏僅給出一種推薦的解法。
對於全部接收後端接口字段的文本展現類的界面。都須要考慮全面(防護性編程:全部的外部數據都是不可信的),正常狀況以下,是沒有問題的。
可是咱們是否考慮到了文本會超長?超長了會折行仍是換行?
對於單行文本,使用單行省略:
{ width: 200px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
固然,目前對於多行文本的超長省略,兼容性也已經很是好了:
{ width: 200px; overflow : hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
對於一些動態內容,咱們常用 min/max-width
或 min/max-height
對容器的高寬限度進行合理的控制。
在使用它們的時候,也有一些細節須要考慮到。
譬如常常會使用 min-width
控制按鈕的最小寬度:
.btn { ... min-width: 120px; }
當內容比較少的時候是沒問題的,可是當內容比較長,就容易出現問題。使用了 min-width
卻沒考慮到按鈕的過長的狀況:
這裏就須要配合 padding 一塊兒:
.btn { ... min-width: 88px; padding: 0 16px }
借用Min and Max Width/Height in CSS[2]中一張很是好的圖,做爲釋義:
這個也是一個經常被忽略的地方。
頁面常常會有列表搜索,列表展現。那麼,既然存在有數據的正常狀況,固然也會存在搜索不到結果或者列表無內容可展現的情形。
對於這種狀況,必定要注意 0 結果頁面的設計,同時也要知道,這也是引導用戶的好地方。對於 0 結果頁面,分清楚:
不一樣的狀況可能對應不一樣的 0 結果頁面,附帶不一樣的操做引導。
譬如網絡異常:
或者確實是 0 結果:
關於 0 結果頁面設計,能夠詳細看看這篇文章:如何設計產品的空白頁面?[3]
小小總結一下,上述比較長的篇幅一直都在闡述一個道理,開發時,不能僅僅關注正常現象,要多考慮各類異常狀況,思考全面。作好各類可能狀況的處理。
圖片在咱們的業務中應該是很是的常見了。有一些小細節是須要注意的。
有的時候和產品、設計會商定,只能使用固定尺寸大小的圖片,咱們的佈局多是這樣:
對應的佈局:
<ul class="g-container"> <li> <img src="http://placehold.it/150x100"> <p>圖片描述</p> </li> </ul> ul li img { width: 150px; }
固然,萬一假設後端接口出現一張非正常大小的圖片,上述不加保護的佈局就會出問題:
因此對於圖片,咱們老是建議同時寫上高和寬,避免由於圖片尺寸錯誤帶來的佈局問題:
ul li img { width: 150px; height: 100px; }
同時,給 <img>
標籤同時寫上高寬,能夠在圖片未加載以前提早佔住位置,避免圖片從未加載狀態到渲染完成狀態高寬變化引發的重排問題。
object-fit
固然,限制高寬也會出現問題,譬如圖片被拉伸了,很是的難看:
這個時候,咱們能夠藉助 object-fit
,它可以指定可替換元素的內容(也就是圖片)該如何適應它的父容器的高寬。
ul li img { width: 150px; height: 100px; object-fit: cover; }
利用 object-fit: cover
,使圖片內容在保持其寬高比的同時填充元素的整個內容框。
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%; }
像是這樣,object-position: 100% 50%
指明從底部開始展現圖片。這裏有一個很好的 Demo 能夠幫助你理解 object-position
。
CodePen Demo -- Object position[4]
正常狀況下,圖片的展現應該沒有什麼問題了。可是對於有圖片可展現的狀況下,咱們還能夠作的更好。
在移動端或者一些高清的 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 屬性,不太瞭解的能夠移步 前端基礎知識概述[5]
好了,當圖片連接沒問題時,已經處理好了。接下來還須要考慮,當圖片連接掛了,應該如何處理。
處理的方式有不少種。最好的處理方式,是我最近在張鑫旭老師的這篇文章中 -- 圖片加載失敗後CSS樣式處理最佳實踐[6] 看到的。這裏簡單講下:
<img>
元素的 onerror
事件,給加載失敗的 <img>
元素新增一個樣式類<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
信息:
OK,到此,完整的對圖片的處理就算完成了,完整的 Demo 你能夠戳這裏看看:
CodePen Demo -- 圖片處理[7]
接下來一個大環節是關於一些交互的細節。對於交互設計,一些比較通用的準則:
在咱們的交互過程當中,適當的增長過渡與動畫,可以很好的讓用戶感知到頁面的變化。
譬如咱們頁面上隨處可見 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
,是突兀的跳動切換:
給可滾動容器添加 scroll-behavior: smooth
,實現平滑滾動:
{ scroll-behavior: smooth; }
scroll-snap-type
優化滾動效果sroll-snap-type
可能算得上是新的滾動規範裏面最核心的一個屬性樣式。
scroll-snap-type[8]:屬性定義在滾動容器中的一個臨時點(snap point)如何被嚴格的執行。
光看定義有點難理解,簡單而言,這個屬性規定了一個容器是否對內部滾動動做進行捕捉,而且規定了如何去處理滾動結束狀態。讓滾動操做結束後,元素中止在適合的位置。
看個簡單示例:
固然,scroll-snap-type
用法很是多,可控制優化的點不少,限於篇幅沒法一一展開,具體更詳細的用法能夠看看個人另一篇文章 -- 使用 sroll-snap-type 優化滾動[9]
這個優化可能稍微有一點難理解。須要瞭解 CSS 渲染優化的相關知識。
先說結論,控制滾動層級的意思是儘可能讓須要進行 CSS 動畫(能夠是元素的動畫,也能夠是容器的滾動)的元素的 z-index 保持在頁面最上方,避免瀏覽器建立沒必要要的圖形層(GraphicsLayer),可以很好的提高渲染性能。
這一點怎麼理解呢,一個元素觸發建立一個 Graphics Layer 層的其中一個因素是:
根據上述這點,咱們對滾動性能進行優化的時候,須要注意兩點:
若是你對這點還有點懵,能夠看看這篇文章 -- 你所不知道的 CSS 動畫技巧與細節[10]
在用戶點擊交互方面,也有一些有意思的小細節。
cursor
對於不一樣的內容,最好給與不一樣的 cursor
樣式,CSS 原生提供很是多種經常使用的手勢。
在不一樣的場景使用不一樣的鼠標手勢,符合用戶的習慣與預期,能夠很好的提高用戶的交互體驗。
首先對於按鈕,就至少會有 3 種不一樣的 cursor,分別是可點擊,不可點擊,等待中:
{ cursor: pointer; // 可點擊 cursor: not-allowed; // 不可點擊 cursor: wait; // loading }
除此以外,還有一些常見的,對於一些可輸入的 Input 框,使用 cursor: text
,對於提示 Tips 類使用 cursor: help
,放大縮小圖片 zoom-in
、zoom-out
等等:
一些經常使用的簡單列一列:
cursor: pointer
cursor: not-allowed
cursor: wait
cursor: zoom-in/ zoom-out
固然,實際 cursor
還支持很是多種,能夠在 MDN[11] 或者下面這個 CodePen Demo 中查看這裏看完整的列表:
CodePen Demo -- Cursor Demo[12]
按鈕是咱們網頁設計中十分重要的一環,而按鈕的設計也與用戶體驗息息相關。
考慮這樣一個場景,在搖晃的車箱上或者是單手操做着屏幕,有的時候一個按鈕,死活也點不到。
讓用戶更容易的點擊到按鈕無疑能很好的增長用戶體驗及可提高頁面的訪問性,尤爲是在移動端,按鈕一般都很小,可是受限於設計稿或者總體 UI 風格,咱們不能直接去改變按鈕元素的高寬。
那麼這個時候有什麼辦法在不改變按鈕本來大小的狀況下去增長他的點擊熱區呢?
這裏,僞元素也是能夠表明其宿主元素來響應的鼠標交互事件的。藉助僞元素能夠輕鬆幫咱們實現,咱們能夠這樣寫:
.btn::befoer{ content:""; position:absolute; top:-10px; right:-10px; bottom:-10px; left:-10px; }
固然,在 PC 端下這樣子看起來有點奇怪,可是合理的用在點擊區域較小的移動端則能取到十分好的效果,效果以下:
608782-20160527112625428-906375003
在按鈕的僞元素沒有其它用途的時候,這個方法確實是個很好的提高用戶體驗的點。
user-select: all
操做系統或者瀏覽器一般會提供一些快速選取文本的功能,看看下面的示意圖:
快速單擊兩次,能夠選中單個單詞,快速單擊三次,能夠選中一整行內容。可是若是有的時候咱們的核心內容,被分隔符分割,或者潛藏在一整行中的一部分,這個時候選取起來就比較麻煩。
利用 user-select: all
,能夠將須要一次選中的內容進行包裹,用戶只須要點擊一次,就能夠選中該段信息:
.g-select-all { user-select: all }
給須要一次選中的信息,加上這個樣式後的效果,這個細節做用在一些須要複製粘貼的場景,很是好用:
CodePen -- user-select: all 示例[13]
::selection
固然,若是你想更進一步,CSS 還有提供一個 ::selection
僞類,能夠控制選中的文本的樣式(只能控制color
, background
, text-shadow
),進一步加深效果。
CodePen -- user-select: all && ::selection 控制選中樣式[14]
user-select: none
有快速選擇,也就會有它的對立面 -- 禁止選擇。
對於一些可能頻繁操做的按鈕,可能出現以下尷尬的場景:
對於這種場景,咱們須要把不可被選中元素設置爲不可被選中,利用 CSS 能夠快速的實現這一點:
{ -webkit-user-select: none; /* Safari */ -ms-user-select: none; /* IE 10 and IE 11 */ user-select: none; /* Standard syntax */ }
這樣,不管點擊的頻率多快,都不會出現尷尬的內容選中:
現階段,單頁應用(Single Page Application)的應用很是普遍,Vue 、React 等框架大行其道。可是一些常見的寫法,也容易衍生一些小問題。
譬如,點擊按鈕、文本進行路由跳轉。譬如,常常會出現這種代碼:
<template> ... <button @click="gotoDetail"> Detail </button> ... <template> ... gotoDetail() { this.$router.push({ name: 'xxxxx', }); }
大體邏輯就是給按鈕添加一個事件,點擊以後,跳轉到另一個路由。固然,自己這個功能是沒有任何問題的,可是沒有考慮到用戶實際使用的場景。
實際使用的時候,因爲是一個頁面跳轉,不少時候,用戶但願可以保留當前頁面的內容,同時打開一個新的窗口,這個時候,他會嘗試下的鼠標右鍵,選擇在新標籤頁中打開頁面,遺憾的是,上述的寫法是不支持鼠標右鍵打開新頁面的。
緣由在於瀏覽器是經過讀取 <a>
標籤的 href
屬性,來展現相似在新標籤頁中打開頁面這種選項,對於上述的寫法,瀏覽器是沒法識別它是一個能夠跳轉的連接。簡單的示意圖以下:
因此,對於全部路由跳轉按鈕,建議都使用 <a>
標籤,而且內置 href
屬性,填寫跳轉的路由地址。實際渲染出來的 DOM 多是須要相似這樣:
<a href="/xx/detail">Detail</a>
易用性也是交互設計中須要考慮的一個很是重要的環節,能作的有很是多。簡單的羅列一下:
這一點很是的有意思,什麼叫先探索後表態呢?就是咱們不要一上來就強迫用戶去作一些事情,譬如登陸。
想想一些經常使用網站的例子:
上述易用性和先探索,後表態的內容,部分來源於:Learn From What Leading Companies A/B Test[15],能夠好好讀一讀。
字體的選擇與使用實際上是很是有講究的。
若是網站沒有強制必須使用某些字體。最新的規範建議咱們更多的去使用系統默認字體。也就是 CSS Fonts Module Level 4 -- Generic font families[16] 中新增的 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;
font-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 結尾總歸是不錯的選擇。
對於上述的一些字體可能會有些懵,譬如 -apple-system
, BlinkMacSystemFont
,這是由於不一樣瀏覽器廠商對規範的實現有所不一樣,對於字體定義更多的相關細節,能夠再看看這篇文章 -- Web 字體 font-family 再探祕[19]
可訪問性,在咱們的網站中,屬於很是重要的一環,可是大部分前端(其實應該是設計、前端、產品)同窗都會忽視它。
我潛伏在一個叫 無障礙設計小組的羣裏,其中包含了不少無障礙設計師以及患有必定程度視覺、聽力、行動障礙的用戶,他們在羣裏常常會表達出一個觀點,就是國內的大部分 Web 網站及 APP 基本沒有考慮過殘障人士的使用(或者可訪問性作的很是差),很是的使人揪心。
尤爲在咱們一些重交互、重邏輯的網站中,咱們須要考慮用戶的使用習慣、使用場景,從高可訪問性的角度考慮,譬如假設用戶沒有鼠標,僅僅使用鍵盤,可否順暢的使用咱們的網站?
假設用戶沒有鼠標,這個真不必定是針對殘障人士,不少狀況下,用戶拿鼠標的手可能在幹其餘事情,好比在吃東西,又或者在 TO B 類的業務,如超市收銀、倉庫收貨,極可能用戶拿鼠標的手操做着其餘設備(掃碼槍)等等。
本文不會專門闡述無障礙設計的方方面面,只是從一些我以爲前端工程師須要關注的,而且僅須要花費少許代價就能作好的一些無障礙設計細節。記住,無障礙設計對全部人都更友善。
顏色,也是咱們每天須要打交道的屬性。對於大部分視覺正常的用戶,可能對頁面的顏色敏感度還沒那麼高。可是對於一小部分色弱、色盲用戶,他們對於網站的顏色會更加敏感,很差的設計會給他們訪問網站帶來極大的不便。
是否曾關心過頁面內容的展現,使用的顏色是否恰當?色弱、色盲用戶可否正常看清內容?良好的色彩使用,在任什麼時候候都是有益的,並且不只僅侷限於對於色弱、色盲用戶。在戶外用手機、陽光很強看不清,符合無障礙標準的高清晰度、高對比度文字就更容易閱讀。
這裏就有一個概念 -- 顏色對比度,簡單地說,描述就是兩種顏色在亮度(Brightness)上的差異。運用到咱們的頁面上,大多數的狀況就是背景色(background-color)與內容顏色(color)的對比差別。
最權威的互聯網無障礙規範 —— WCAG AA[20]規範規定,全部重要內容的色彩對比度須要達到 4.5:1 或以上(字號大於18號時達到 3:1 或以上),纔算擁有較好的可讀性。
借用一張圖 -- 知乎 -- 助你輕鬆作好無障礙的15個UI設計工具推薦[21]:
很明顯,上述最後一個例子,文字已經很是的不清晰了,正經常使用戶都已經很難看得清了。
Chrome 瀏覽器從很早開始,就已經支持檢查元素的色彩對比度了。以我當前正在寫做的頁面爲例子,Github Issues
編輯頁面的兩個按鈕:
審查元素,分別能夠看到兩個按鈕的色彩對比度:
能夠看到,綠底白字按鈕的色彩對比度是沒有達到標準的,也被用黃色的歎號標識了出來。
除此以外,在審查元素的 Style 界面的取色器,改變顏色,也能直觀的看到當前的色彩對比度:
相似百度、谷歌的首頁,進入頁面後會默認讓輸入框得到焦點:
並不是全部的有輸入框的頁面,都須要進入頁面後進行聚焦,可是焦點可以讓用戶很是明確的知道,當前本身在哪,須要作些什麼。尤爲是對於沒法操做鼠標的用戶。
頁面上能夠聚焦的元素,稱爲可聚焦元素,得到焦點的元素,則會觸發該元素的 focus
事件,對應的,也就會觸發該元素的 :focus
僞類。
瀏覽器一般會使用元素的 :focus
僞類,給元素添加一層邊框,告訴用戶,當前的獲焦元素在哪裏。
咱們能夠經過鍵盤的 Tab
鍵,進行焦點的切換,而獲焦元素則能夠經過元素的 :focus
僞類的樣式,告訴用戶當前焦點位置。
固然,除了
Tab
鍵以外,對於一些多輸入框、選擇框的表單頁面,咱們也應該想着如何簡化用戶的操做,譬如用戶按回車鍵時自動前進到下一字段。通常而言,用戶必須執行的觸按越少,體驗越佳。
下面的截圖,徹底由鍵盤操做完成:
經過元素的 :focus
僞類以及鍵盤 Tab 鍵切換焦點,用戶能夠很是順暢的在脫離鼠標的狀況下,對頁面的焦點切換及操做。
然而,在許多 reset.css
中,常常能看到這樣一句 CSS 樣式代碼,爲了樣式的統一,消除了可聚焦元素的 :focus
僞類:
:focus { outline: 0; }
咱們給上述操做的代碼。也加上這樣一句代碼,全程再用鍵盤操做一下:
除了在 input
框有光標提示,當使用 Tab 進行焦點切換到 select
或者到 button
時,因爲沒有了 :focus
樣式,用戶將徹底懵逼,不知道頁面的焦點如今處於何處。
:focus-visible
固然,形成上述結果很重要的一個緣由在於。:focus
僞類不論用戶在使用鼠標仍是使用鍵盤,只要元素獲焦,就會觸發。
而其自己的默認樣式又不太能被產品或者設計接受,致使了不少人會在焦點元素觸發 :focus
僞類時,經過改變 border 的顏色或者其餘一些方式替代或者直接禁用。而這樣作,從可訪問性的角度來看,對於非鼠標用戶,無疑是災難性的。
基於此,在W3 CSS selectors-4 規範[22] 中,新增了一個很是有意思的 :focus-visible
僞類。
:focus-visible
:這個選擇器能夠有效地根據用戶的輸入方式(鼠標 vs 鍵盤)展現不一樣形式的焦點。
有了這個僞類,就能夠作到,當用戶使用鼠標操做可聚焦元素時,不展現 :focus
樣式或者讓其表現較弱,而當用戶使用鍵盤操做焦點時,利用 :focus-visible
,讓可獲焦元素得到一個較強的表現樣式。
看個簡單的 Demo:
<button>Test 1</button> button:active { background: #eee; } button:focus { outline: 2px solid red; }
使用鼠標點擊:
能夠看到,使用鼠標點擊的時候,觸發了元素的 :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:
CodePen Demo -- :focus-visible example[23]
能夠看到,使用鼠標點擊,不會觸發 :foucs
,只有當鍵盤操做聚焦元素,使用 Tab 切換焦點時,outline: 2px solid red
這段代碼纔會生效。
這樣,咱們就既保證了正經常使用戶的點擊體驗,也保證了一批沒法使用鼠標的用戶的焦點管理體驗。
值得注意的是,有同窗會疑惑,這裏爲何使用了 :not
這麼繞的寫法而不是直接這樣寫呢:
button:focus { outline: unset; } button:focus-visible { outline: 2px solid red; }
爲的是兼容不支持 :focus-visible
的瀏覽器,當 :focus-visible
不兼容時,仍是須要有 :focus
僞類的存在。
還有一個很是須要注意的點。
如今不少前端同窗在前端開發的過程當中,喜歡使用非可獲焦元素模擬獲焦元素,譬如:
div
模擬 button
元素ul
模擬下拉列表 select
等等當下不少組件庫都是這樣作的,譬如 element-ui 和 ant-design。
在使用非可獲焦元素模擬獲焦元素的時候,必定要注意,不只僅只是外觀長得像就完事了,其行爲表現也須要符合本來的 button
、select
等可聚焦元素的性質,可以體現元素的語義,可以被聚焦,可以經過 Tab 切換等等。
基於大量相似的場景,有了 WAI-ARIA 標準[24],WAI-ARIA是一個爲殘疾人士等提供無障礙訪問動態、可交互Web內容的技術規範。
簡單來講,它提供了一些屬性,加強標籤的語義及行爲:
tabindex
屬性控制元素是否能夠聚焦,以及它是否/在何處參與順序鍵盤導航role
屬性,來標識元素的語義及做用,譬如使用 <div id="saveChanges" tabindex="0" role="button">Save</div>
來模擬一個按鈕aria-*
屬性,表示元素的屬性或狀態,幫助咱們進一步地識別以及實現元素的語義化,優化無障礙體驗咱們來看看 Github 頁面是如何定義一個按鈕的,以 Github Issues 頁面的 Edit 按鈕爲例子:
這一塊,清晰的描述了這個按鈕在可訪問性相關的一些特性,譬如 Contrast 色彩對比度,按鈕的描述,也就是 Name
,是給屏幕閱讀器看到的,Role
標識是這個元素的屬性,它是一個按鈕,Keyboard focusable
則代表他可否被鍵盤的 Tab 按鈕給捕獲。
這裏,我隨便選取了咱們業務中一個使用 span 模擬按鈕的場景,是一個麪包屑導航,點擊可進行跳轉,發現慘不忍睹:
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>
不要忘了再改一下顏色,達到最低色彩對比度以上,再看看:
OK,這樣,一個最最最基本的,知足最低可訪問性需求的按鈕算是勉強達標,固然,這個按鈕能夠再更進一步進行改造,涉及了更深刻的可訪問性知識,本文不深刻展開。
最後,在咱們比較經常使用的 Vue - element-ui[25]、React - ant-design[26] 中,咱們來看看 ant-design 在提高可訪問性相關的一些功能。
以 Select 選擇框組件爲例,ant-design 利用了大量的 WAI-ARIA 屬性,使得用 div 模擬的下拉框不只僅在表現上符合一個下拉框,在語義、行爲上都符合一個下拉框,簡單的一個例子:
看看使用 div 模擬下拉框的 DOM 部分:
再看看在交互體驗上:
上述操做全是在鍵盤下完成,看着平平無奇,實際上組件庫在正常響應可獲焦元素切換的同時,給用 div 模擬的 select 加了不少鍵盤事件的響應,能夠利用回車,上下鍵等對可選項進行選擇。實際上是下了不少功夫。
對於 A11Y 相關的內容,篇幅及內容很是之多,本文沒法一一展開,感興趣的能夠通讀下下列文章:
本文從頁面展現、交互細節、可訪問性三個大方面入手,羅列一些在實際的開發過程當中,積攢的一些有益的經驗。雖然不夠全面,不過從一開始也就沒想着大而全,主要是一些可能有用可是容易被忽視的點,也算是一個不錯的查缺補漏小指南。
固然,不少都是我我的的觀點想法,可能有一些理解存在一些問題,一些概念沒有解讀到位,也但願你們幫忙指出。
本文到此結束,但願對你有幫助 :)
若是還有什麼疑問或者建議,能夠多多交流,原創文章,文筆有限,才疏學淺,文中如有不正之處,萬望告知。