本文首發於微信公眾號“Shopee技術團隊”。
前言
本文是基於 Shopee 供應鏈團隊內部 WMS(Warehouse Management System,倉庫管理系統) 專案的整體重構,總結而出的一份 Web 使用者體驗設計提升指南。
因為是對已經存在的專案進行完全的推翻重構,所以在整個過程中,我們一直在思考如何儘可能地站在使用者的角度,通過前端設計去提升改進使用者的體驗與感受,真正達到重構的目的及意義。
一個 Web 頁面或是一個 App,想讓別人用得爽,獲得良好的使用者體驗,可能需要包括但不限於:
- 急速的開啟速度
- 令人眼前一亮的 UI 設計
- 酷炫的動畫效果
- 豐富的個性化設定
- 易用、友好的便捷操作
- 貼心的細節
- 關注殘障人士,良好的可訪問性
- ……
所謂的使用者體驗設計,是秉承著以使用者為中心的思想的一種設計手段,以使用者需求為目標而進行的設計。設計過程注重以使用者為中心,使用者體驗的概念從開發的最早期就開始進入整個流程,並貫穿始終。
良好的使用者體驗設計,是團隊在產品開發中每一個環節共同努力的結果。
本文將主要從頁面呈現、互動細節、可訪問性三個方面入手,分享一些在實際開發過程中積攢的有益經驗。通過這篇文章,你將能:
- 瞭解到一些細節是如何影響使用者體驗的;
- 瞭解到如何在儘量小的開發改動下,提升頁面的使用者體驗;
- 瞭解到一些優秀的互動設計細節;
- 瞭解基本的無障礙功能及頁面可訪問性的含義;
- 瞭解基本的提升頁面可訪問性的方法。
1. 頁面呈現
就整個頁面的展示和頁面內容的呈現而言,不同的展示方式,所得到的效果截然不同。
這其中有非常多值得注意的細節。接下來分為幾個要點進行闡述:
- 自適應的佈局
- 重點內容的排佈設計
- 相容不同場景與異常回退
- 圖片的呈現及異常處理
- 適當的過渡與動畫
1.1 自適應的佈局
先來看一些佈局相關的問題。
佈局,是前端在重構頁面過程中需要提前進行規劃思考的,一般應該考慮清楚以下幾個問題:
- 對於 PC 端,專案是全屏佈局還是定寬佈局?使用者是否還在使用 IE?
- 對於全屏佈局,需要適配的最小寬度是多少?
- 對於移動端佈局,你知道使用者裝置的分佈嗎?最少相容到 Android 什麼版本?iOS 什麼版本?
- 內容應該以什麼樣的方式呈現?
到今天,各種裝置浩如煙海,移動端螢幕尺寸紛繁複雜(下圖僅僅是到 2019 年各種安卓裝置螢幕尺寸圖的分佈):
不過,我們的重構專案整體是以 PC 為主的 ToB 專案,所以這裡主要以 PC 端為例進行講解。
對於大部分 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 正常流排布(也就是需要滾動到底部才能看到 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.2 重點內容的排佈設計
下面這一塊關於重點內容的展示。
1.2.1 重要內容及功能的展示
讓吸引使用者注意力的元素前置。如果我們的頁面存在需要讓使用者瞭解、處理的核心資訊或者表單,儘可能將其位置放在上方,讓使用者更容易獲取這部分資訊。
將使用者需要的資訊、重要的功能展示出來而不是藏起來。
類似於導航、搜尋等高頻操作,一定不要讓使用者多次點選才能用到。
1.2.2 處理動態內容:文字超長
對於所有接收後端介面欄位的文字展示類的介面,都需要考慮全面。正常情況如下,是沒有問題的:
但是我們是否考慮到了文字會超長?超長了會折行還是換行?
對於單行文字,使用單行省略:
{
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;
}
1.2.3 處理動態內容:保護邊界
對於一些動態內容,我們經常使用 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 中一張非常好的圖,作為釋義:
1.3 相容不同場景與異常回退:空資料內容展示
這個模組是相容不同場景與異常回退,是一個常常被忽略的地方。
頁面經常會有列表搜尋、列表展示。那麼,既然存在資料的正常情況,當然也會存在搜尋不到結果或者列表無內容可展示的情形。
對於這種情況,一定要注意空資料結果頁面的設計;同時要知道,這也是引導使用者的好地方。對於空資料結果頁面,分清楚:
(1)資料為空
- 使用者無許可權——要告知使用者無許可權訪問的原因和解決方案
- 搜尋無結果——告知使用者搜尋無資料的結果,如有必要可推薦相關內容
- 篩選無結果——一般直接告知篩選無結果
頁面無資料——文案設計有幾個方向:
- 告訴使用者這裡將會存放什麼資料
- 給使用者一個主動創造資料的理由,比如通過話術引起使用者心理共鳴
- 若頁面無資料會給使用者造成困惑,則可以說明原因打消使用者的困惑
(2)異常狀態
- 網路異常——指出當前狀態為網路異常,並給出解決方案
- 伺服器異常——指出當前狀態為伺服器異常,並給出解決方案
- 載入失敗——載入失敗主要會由網路異常或伺服器異常造成
- 不同的情況可能對應不同的空資料結果頁面,附帶不同的操作引導
例如網路異常,可以引導使用者重新整理頁面:
或者確實是零結果,譬如沒有訂單資訊,可以引導使用者去進行訂單的建立(引導消費):
小小總結一下,上述篇幅一直都在闡述一個道理:開發時,不能僅僅關注正常現象,要多考慮各種異常情況,思考全面,做好各種可能情況的處理。
1.4 圖片的呈現及異常處理
圖片在我們的業務中非常常見。但是要完美處理圖片,並不輕鬆。
1.4.1 給圖片同時設定高寬
有的時候產品和設計會商定,只能使用固定尺寸大小的圖片,我們的佈局可能是這樣:
對應的佈局:
<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>
標籤同時寫上高寬,可以在圖片載入之前提前佔住位置,避免圖片從未載入狀態到渲染完成狀態高寬變化引起的重排問題。
1.4.2 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%
。如果你不希望圖片居中展示,可以使用它去改變圖片實際展示的位置。
ul li img {
width: 150px;
height: 100px;
object-fit: cover;
object-position: 50% 100%;
}
像是這樣,object-position: 100% 50%
指明從底部開始展示圖片。
這裡有一個很好的 Demo 可以幫助你理解
object-position
:
1.4.3 考慮螢幕 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 的螢幕提供最適合的圖片。
1.4.4 圖片丟失
好了,當圖片連結沒問題時,已經處理好了。接下來還需要考慮,當圖片連結掛了,應該如何處理。
處理的方式有很多種。最好的處理方式,是我在張鑫旭老師《圖片載入失敗後 CSS 樣式處理最佳實踐》這篇文章中看到的。這裡簡單講講:
- 利用圖片載入失敗,觸發
<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
資訊:
到此,完整的對圖片的處理就算完成了,完整的 Demo 你可以戳這裡看看:CodePen Demo - 圖片處理。
1.5 適當的過渡與動畫
好的頁面呈現需要適當的過渡與動畫,讓整體互動體驗更加流暢。適當增加過渡與動畫,能夠很好地讓使用者感知到頁面的變化,它們有如下作用:
- 減少認知負荷
- 防止變化視盲
- 空間上營造更好的印象
- 讓使用者介面鮮活起來
這一塊內容也可以放在互動設計優化,讀者朋友們瞭解就好。
1.5.1 loading 等待動畫
頁面上隨處可見的 loading 效果,其實就是這樣一種作用,讓使用者感知頁面正在載入,或者正在處理某些事務。
1.5.2 骨架屏動畫
骨架屏的佈局與頁面的視覺呈現保持一致,能引導使用者將關注點聚焦到感興趣的位置,並且能避免過長時間的等待。
1.5.3 滾動平滑:使用 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;
}
1.5.4 粘性滾動:使用 scroll-snap-type
優化滾動效果
sroll-snap-type
可能算得上是新的滾動規範裡面最核心的一個屬性樣式。
scroll-snap-type:屬性定義在滾動容器中的一個臨時點(snap point)如何被嚴格地執行。
光看定義有點難理解,簡單而言,這個屬性規定了一個容器是否對內部滾動動作進行捕捉,並且規定了如何去處理滾動結束狀態。讓滾動操作結束後,元素停止在適合的位置。
看個簡單示例:
當然,scroll-snap-type
用法非常多,可控制優化的點很多,限於篇幅無法一一展開。
1.5.5 控制滾動層級,避免頁面大量重排
這個優化可能稍微有一點難理解。需要了解 CSS 渲染優化的相關知識。
先說結論,控制滾動層級的意思是儘量讓需要進行 CSS 動畫(可以是元素的動畫,也可以是容器的滾動)的元素的 z-index 保持在頁面最上方,避免瀏覽器建立不必要的圖形層(GraphicsLayer),能夠很好地提升渲染效能。
這一點怎麼理解呢?一個元素觸發建立一個 Graphics Layer 層的其中一個因素是:
- 元素有一個 z-index 較低且包含一個複合層的兄弟元素。
根據上述這點,我們對滾動效能進行優化的時候,需要注意兩點:
- 通過生成獨立的 GraphicsLayer,利用 GPU 加速,提升滾動的效能;
- 如果本身滾動沒有效能問題,不需要獨立的 GraphicsLayer,也要注意滾動容器的層級,避免因為層級過高而被其他建立了 GraphicsLayer 的元素合併,被動地生成一個 GraphicsLayer ,影響頁面整體的渲染效能。
1.5.6 轉場動畫
從一個模組跳轉到另外一個模組的時候,轉場動畫就派上了用場。它的作用在於:在合適的時機,將視線引導到適當的位置。
看下面的例子:
在點選按鈕彈出彈窗的過程中,彈窗不是突兀地出現,而是從點選的地方放大至視窗中間,這個引導的過程讓體驗更加絲滑。
1.5.7 操作動畫
這個和 loading 有點類似,遇到一些耗時操作,比如下載時,我們可以通過定製一個特殊的動畫,減緩使用者等待的煩躁、焦慮感。
上述動畫的程式碼,你可以猛擊:
當然,除了下載等待,我們也可以在一些重要的操作互動上,例如點贊、關注等,定製特殊的動畫,讓過程更加生動有趣。下面這個是某網站的點贊動畫:
上述點贊動畫的程式碼,你可以猛擊:
1.5.8 使用過渡與動畫的誤區
合理使用動畫能讓頁面增色不少,但同時要避免踩入下面的一些坑:
- 動畫沒有關聯性
- 為了動畫而動畫,沒有目的性
- 過於緩慢,阻礙互動
- 不夠明確
簡單解釋一下。譬如動畫關聯性,關聯性背後的邏輯能幫助使用者在介面佈局中理解剛發生的變化,是什麼導致了變化。
下圖中,左邊是關聯性差的,右邊是關聯性好的:
還有一點,大部分動畫不宜過久,要足夠迅速。
緩慢的動畫產生了不必要的停頓。過渡動畫應該保持簡短,因為使用者會頻繁看到它們。讓動畫持續時間保持在 300ms 或更短。
看下圖演示,同一個轉場動畫會被頻繁觸發,所以儘可能地讓每次的動畫不要持續過久,能夠幫助使用者節省更多時間。
總而言之,動畫和過渡要用得恰當好處,避免為了動畫而動畫非常重要。
2. 互動設計優化
接下來一個大環節是一些關於互動的細節。
什麼是互動設計?互動設計(Interaction Design, IXD)是定義、設計人造系統的行為的設計領域,它定義了兩個或多個互動的個體之間交流的內容和結構,使之互相配合,共同達成某種目的。
2.1 Web 端互動方式
Web 端互動圍繞計算機為中心,主要涉及鍵盤、滑鼠兩類裝置的互動。
關於互動設計,一些比較通用的準則有:
- Don’t make me think
- 符合使用者的習慣與預期
- 操作便利
- 做適當的提醒
- 不強迫使用者
2.2 Don’t make me think
有一本書就叫 Don’t make me think,它所想表述的核心是,儘可能讓產品做到高可用性,讓使用者無須思考也能明確無誤地使用產品中的各項功能。
那麼,我們的頁面如何儘可能做到高可用性呢?
2.2.1 使用習慣用法
使用習慣用法。當我們設計一個新的頁面時,頁面位置、功能設定、視覺元素應當和慣常用法相差無幾,這樣才能讓使用者有舒適感。
這裡並不是要扼殺大家的想象力,讓所有頁面都一成不變。根據產品的形態及受眾,大部分頁面是不適用於各種天馬行空的想象的。
例如下面這樣一個 PC 端頁面結構,這種佈局已經非常常見。遇到這種頁面,使用者能夠非常快速地在指定區域找到想要的元素及資訊:
可以再和我們的 WMS 重構後的頁面作比較,整體是非常類似的:
採用習慣用法的設定能夠讓人快速上手新的陌生的頁面或者功能。
2.2.2 降低視覺噪聲
另外一種做法是降低視覺噪聲,讓使用者快速聚焦。
譬如彈窗背後的陰影、虛化,就是非常好的降低視覺噪聲的手段。
這一點還是非常好理解的,也屬於常見設計手段之一,在我們內部的相關元件、自研元件庫已經沉澱得很好了。
2.3 符合使用者的習慣與預期
接下來是符合使用者的習慣與預期,它的意義在於減少使用者的思考,符合使用者的習慣,讓使用者的體驗更加舒適。
下面這幾種彈窗,哪一個是更好的選擇?
三個彈窗可供操作的按鈕分別是:
- 右下角的取消和確認,同時右上角的 X 可以關閉彈窗;
- 只有右下角的取消和確認;
- 只有確認按鈕。
更好的選擇應該是第一個:同時有取消和確認按鈕,右上角的 X 可以關閉彈窗。因為這樣最符合使用者的習慣預期。
看看這個 Windows 下的彈窗:
大部分 Windows 的彈窗,都是有取消、確認加上右上角的 X 按鈕的。這種彈窗的好處在於:
- 視覺原因,元素平衡;
- 符合使用者習慣,大多數使用者都是 Windows 作業系統過來的;
- 互動一致性,降低使用者學習成本;
- 提升頁面的可訪問性和無障礙訪問性。
2.3.1 優化手勢:不同場景應用不同 cursor
對於不同的內容,最好給與不同的 cursor
樣式,CSS 原生提供了非常多種常用的手勢。
在不同的場景使用不同的滑鼠手勢,符合使用者的習慣與預期,可以很好地提升使用者的互動體驗。
首先對於按鈕,就至少會有三種不同的 cursor
,分別是可點選、不可點選、等待中:
{
cursor: pointer; // 可點選
cursor: not-allowed; // 不可點選
cursor: wait; // loading
}
除此之外,還有一些常見用法:對於一些可輸入的 Input 框,使用 cursor: text
;對於提示 Tips 類,使用 cursor: help
;放大縮小圖片 zoom-in
、zoom-out
等等:
一些常用的簡單列一列:
- 按鈕可點選:
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。
2.3.2 點選區域優化:偽元素擴大點選區域
按鈕是我們網頁設計中十分重要的一環,而按鈕的設計也與使用者體驗息息相關。
考慮這樣一個場景:在搖晃的車廂上或者是單手操作著螢幕,有的時候一個按鈕死活也點不到。
讓使用者更容易點選到按鈕無疑能很好地提升使用者體驗,並提升頁面的訪問性。尤其是在移動端,按鈕通常都很小,但是受限於設計稿或者整體 UI 風格,我們不能直接去改變按鈕元素的高寬。
那麼,有什麼辦法在不改變按鈕原本大小的情況下增加點選熱區呢?
藉助偽元素可以輕鬆實現。偽元素也是可以代表其宿主元素來響應滑鼠互動事件的。我們可以這樣寫:
.btn::before{
content:"";
position:absolute;
top:-10px;
right:-10px;
bottom:-10px;
left:-10px;
}
當然,在 PC 端下這樣子看起來有點奇怪,但是合理地用在點選區域較小的移動端則能取得十分好的效果:
2.4 操作便利
好的系統,操作起來應該是流暢的。同時,它能夠通過一些小細節打動使用者。
2.4.1 快速選擇優化:user-select: all
作業系統或者瀏覽器通常會提供一些快速選取文字的功能。看看下面的示意圖:
快速單擊兩次,可以選中單個單詞;快速單擊三次,可以選中一整行內容。但如果核心內容被分隔符分割,或者成為潛藏在一整行中的一部分,這個時候選取起來就比較麻煩。
利用 user-select: all
,可以將需要一次選中的內容進行包裹,使用者只需要點選一次,就可以選中該段資訊:
.g-select-all {
user-select: all
}
給需要一次選中的資訊加上這個樣式,該細節作用在一些需要複製貼上的場景時,非常好用。
在我們 WMS 的很多操作頁面,需要頻繁從表格中複製一些基礎資訊,例如下述的 Location ID
、Cell Name
,由於完整的欄位使用了分隔符 -
,所以一次點選是無法選中整段資訊的,而利用 user-select: all
可以很好地解決這個痛點:
別看只是減少一次點選滑鼠的次數,但正是這些細節的累積,才更能讓使用者感受到開發者的用心。
2.4.2 選中樣式優化:::selection
CSS 還提供了一個 ::selection
偽類,可以控制選中的文字樣式(只能控制 color
、background
、text-shadow
),進一步加深效果。
CodePen - user-select: all && ::selection 控制選中樣式
2.4.3 新增禁止選擇:user-select: none
有快速選擇,也就會有它的對立面——禁止選擇。
對於一些可能頻繁操作的按鈕,可能會出現如下尷尬場景:
- 文字按鈕的快速點選,觸發了瀏覽器的雙擊快速選擇,導致文字被選中:
- 翻頁按鈕的快速點選,觸發了瀏覽器的雙擊快速選擇:
對於這種場景,我們需要把不可被選中的元素設定為不可被選中,利用 CSS 可以快速實現這一點:
{
-webkit-user-select: none; /* Safari */
-ms-user-select: none; /* IE 10 and IE 11 */
user-select: none; /* Standard syntax */
}
這樣,無論點選頻率多快,都不會出現內容被選中的尷尬情況:
2.5 跳轉優化
現階段,單頁應用(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>
在實際的 WMS 重構過程中,我們對於所有有頁面跳轉功能的按鈕,包括但不限於路由選單、麵包屑導航、跳轉按鈕等,都進行了跳轉優化,以滿足使用者的不同訴求。
路由選單導航:
表格中的一些按鈕跳轉:
2.6 表單互動優化
輸入及選擇於使用者而言,是一項高互動成本的操作。下面提供了一些小的建議來減少使用者輸入出錯、提升使用者體驗。
2.6.1 儘可能地簡化表單
將表單做得簡單點,確保使用者在抓狂之前能進入下一步(表單越複雜,流失率越高):
對於沒法省去的輸入項,儘可能簡化使用者的輸入:
- 智慧預設預設項
- 輸入時提供智慧聯想
- 對於選擇框,儘可能精簡選項資訊
- 使用單選項來代替下拉選單
2.6.2 及時校驗
表單及時校驗,而不是使用者填完一堆資訊,統一提交後才告訴使用者填錯了:
2.6.3 貼心細節提示,校驗更寬容
還有一些比較有益的建議,可以有效的提升互動過程中使用者的體驗,根據實際情況可以考慮:
- 在表單中增加一些提示資訊,減少錯誤的機率
- 嘗試將表單輸入變得更加寬容,讓使用者的填寫更加簡單
2.7 先探索,後表態
這一點非常有意思,什麼叫先探索後表態呢?就是我們不要一上來就強迫使用者去做一些事情,例如登入。
想一想一些常用網站的例子:
- 類似虎牙、bilibili 等視訊網站,可以先藍光體驗,一定觀看時間後才會要求登入;
- 電商網站,只有到付款的時候,才需要登入。
上述易用性和先探索後表態的內容,部分來源於 “Learn From What Leading Companies A/B Test”,推薦閱讀。
2.8 結合產品的創意互動動畫
由於業務的型別限制,在這一塊,我們實際中運用的並不多,但是它也是增強使用者體驗非常有益且重要的一環,下文將簡單講一講。
這一類互動為結合產品的創意互動動畫。通過定製化的有儀式感的互動,提升品牌價值,能給予使用者深刻的印象。
結合產品及業務的創意動畫,是需要挖掘,不斷打磨、不斷迭代的。比如 bilibili 官網的頂部 banner,配合一些節日、活動,經常會出現一些有意思的創意互動動畫:
以及這個:
我非常多次在不同地方看到有人討論 bilibili 的頂部 banner 動畫,可見它這塊的動畫是成功的。很好地結合了一些節日、實事、熱點,作為一種比較固定的產品去不斷推陳出新,在不同時候帶給使用者不同的體驗。
2.9 字型優化
字型的選擇與使用其實是非常有講究的。
在 WMS 專案重構過程中,我們使用的全域性字型定義是:font-family: Roboto,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Oxygen,Ubuntu,Fira Sans,Droid Sans,Helvetica Neue,"sans-serif";
。
這裡,我們的設計師對英文字型有一些強限制,首選字型是 Roboto,並且在系統中提供了該字型包。
如果網站沒有強制必須使用某些字型。最新的規範建議我們使用系統預設字型。也就是 “CSS Fonts Module Level 4: Generic font families” 中新增的 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;
- Github:
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;
簡單而言,它們總體遵循了以下幾項基本原則:
2.9.1 儘量使用系統預設字型
使用系統預設字型的主要原因是效能,系統字型的優點在於它與當前作業系統相匹配,因此它的文字展示效果必然也是令人舒適的。
2.9.2 兼顧中西:西文在前,中文在後
中文或者英文(西文)都要考慮到。由於大部分中文字型也帶有英文部分,但是英文部分又不怎麼好看,並且英文字型中大多不包含中文。因此我們通常會先進行英文字型的宣告,選擇最優的英文字型,這樣不會影響到中文字型的選擇。
2.9.3 兼顧多作業系統
選擇字型的時候要考慮多作業系統。例如 macOS 下的很多中文字型在 Windows 都沒有預裝。為了保證 Mac 使用者的體驗,在定義中文字型的時候,先定義 Mac 使用者的中文字型,再定義 Windows 使用者的中文字型。
2.9.4 兼顧舊作業系統:以字型族系列 serif 和 sans-serif 結尾
當使用一些非常新的字型時,要考慮向下相容,兼顧到一些極舊的作業系統,使用字型族系列 serif 和 sans-serif 結尾總歸是不錯的選擇。
3. 可訪問性(A11Y)
可訪問性(accessibility,也被稱為 “A11Y”)在網站中屬於非常重要的一環,但是大部分前端(其實應該是設計、前端、產品)同學都忽視了它。
3.1 什麼是可訪問性
傳統上我們認為這隻與殘障人士有關,但提升網站的可訪問性也可以讓其他使用者群體(每個人)受益。
根據網頁內容可訪問性準則(即 “Web Content Accessibility Guidelines (WCAG) 2.0”),Web 可訪問性有以下四個基礎性原則。
(1)可感知
- 用文字替代非文字內容
- 多媒體的字幕及其他替代物
- 內容有多種呈現方式
- 內容的看和聽更容易
(2)可操作
- 可以通過鍵盤使用功能
- 使用者有充足的時間閱讀和使用內容
- 內容不要誘發癲癇和物理反應
- 使用者可以方便地導航、找到內容並確認自己在哪裡
- 使用者可以使用除鍵盤外的不同輸入方式
(3)可理解
- 文字容易閱讀和理解
- 內容以可預測的方式出現和操作
- 使用者可以得到幫忙,以避免和糾正錯誤
(4)健壯性
- 健壯的內容和可靠的解釋
- 內容與現在和未來的使用者工具相容
- 在各個平臺和環境中都能正確地展示
我潛伏在一個叫無障礙設計小組的群裡,其中包含了很多無障礙設計師以及患有一定程度視覺、聽力、行動障礙的使用者,他們在群裡經常會表達出一個觀點,就是國內的大部分 Web 網站及 App 基本沒有考慮過殘障人士的使用(或者可訪問性做得很差),非常令人揪心。
尤其在一些重互動、重邏輯的網站中,我們需要從高可訪問性的角度考慮使用者的使用習慣、使用場景。比如:假設使用者沒有滑鼠,僅僅使用鍵盤,能否順暢使用我們的網站?
假設使用者沒有滑鼠,這個真不一定是針對殘障人士。很多情況下,使用者拿滑鼠的手可能在幹其他事情,比如在吃東西;又或者在 To B 類的業務,如超市收銀、倉庫收貨,很可能使用者拿滑鼠的手操作著其他裝置(掃碼槍)等等。
本文不會專門闡述無障礙設計的方方面面,只是從一些我覺得前端工程師需要關注的,並且僅需要花費少量代價就能做好的一些無障礙設計細節。記住,無障礙設計對所有人都更友善。
3.2 色彩對比度
顏色,也是我們天天需要打交道的屬性。大部分視覺正常的使用者可能對頁面的顏色敏感度還沒那麼高。但是對於一小部分色弱、色盲使用者,他們對網站的顏色會更加敏感,不好的設計會給他們訪問網站帶來極大的不便。
3.2.1 什麼是色彩對比度
是否曾關心過頁面內容的展示,使用的顏色是否恰當?色弱、色盲使用者能否正常看清內容?良好的色彩使用,在任何時候都是有益的,而且不僅僅侷限於色弱、色盲使用者。在戶外使用手機,陽光很強看不清時,符合無障礙標準的高清晰度、高對比度文字就更容易閱讀。
這裡引入了一個概念——色彩對比度。簡單地說,就是兩種顏色在亮度(brightness)上的差別。運用到我們的頁面上,大多數的情況就是背景色(background-color)與內容顏色(color)的對比差異。
“最權威的網際網路無障礙規範——WCAG AA 規範規定,所有重要內容的色彩對比度需要達到 4.5:1 或以上(字號大於 18 號時達到 3:1 或以上),才算擁有較好的可讀性。”
看看下面這張圖:
很明顯,對比度由低到高。前兩個例子,別說視障使用者,正常使用者都已經很難看得清了。
當然,也會存在一些特例,譬如輸入框的 placeholder
、按鈕的禁用狀態等等。因此,在網頁重構的過程中,我們需要儘可能遵循這個規範。但又不是盲目遵循,導致毫無迴旋餘地。
3.2.2 檢查色彩對比度的工具
Chrome 瀏覽器從很早開始,就已經支援檢查元素的色彩對比度了。以 WMS 頁面中的一個 Table Header 為例,我們可以去檢查一些無法直觀界定是否達到標準的文字:
審查元素,分別可以看到當前文字與背景的對比度。下述結果表示,這個對比度是沒有問題的:
當然,我們的頁面上也會存在這樣的麵包屑導航:
可以看到,色彩對比度沒有達到標準的部分,被用黃色歎號標識了出來。
除此之外,在審查元素的 Style 介面的取色器,改變顏色,也能直觀地看到當前的色彩對比度:
3.2.3 不要單純依賴顏色
為了保證無障礙的準確性,應當確保你沒有完全依賴顏色來展示系統不同層級的關鍵資訊。
看看下面這個例子:
本來我們期待利用綠色和紅色來表達正確與錯誤,但是對於部分視覺障礙使用者,他可能根本感受不到這個提示。
正確的做法是,使用必要的文字和圖示進行說明:
因此在實際應用中,我們需要利用能傳達準確資訊的圖示配合文字描述去表達,譬如 WMS 登入錯誤頁面:
3.3 焦點響應
類似百度、谷歌的首頁,進入頁面後會預設讓輸入框獲得焦點:
並非所有的有輸入框的頁面都需要進入頁面後進行聚焦,但是焦點能夠讓使用者非常明確地知道當前自己在哪,需要做些什麼。尤其是對於無法操作滑鼠的使用者來說。
頁面上可以聚焦的元素,稱為可聚焦元素,獲得焦點的元素,則會觸發該元素的 focus
事件。對應地,也會觸發該元素的 :focus
偽類。
瀏覽器通常會使用元素的 :focus
偽類,給元素新增一層邊框,告訴使用者當前的獲焦元素在哪裡。
我們可以通過鍵盤的 Tab
鍵,進行焦點的切換。而獲焦元素則可以通過元素的 :focus
偽類的樣式,告訴使用者當前焦點位置。
當然,除了 Tab
鍵之外,對於一些多輸入框、選擇框的表單頁面,我們也應該想著如何簡化使用者的操作,例如使用者按Enter鍵時自動前進到下一欄位。一般而言,使用者必須執行的觸按越少,體驗越佳。??
下面的截圖,完全由鍵盤操作完成:
通過元素的 :focus
偽類以及鍵盤 Tab 鍵切換焦點,使用者可以非常順暢的在脫離滑鼠的情況下,對頁面的焦點切換及操作。
然而,在許多 reset.css
中,經常能看到這樣一句 CSS 樣式程式碼,為了樣式的統一,消除了可聚焦元素的 :focus
偽類:
:focus {
outline: 0;
}
我們給上述操作的程式碼。也加上這樣一句程式碼,全程再用鍵盤操作一下:
除了在 input
框有游標提示,當使用 Tab
進行焦點切換到 select
或者到 button
時,由於沒有了 :focus
樣式,使用者會感到迷茫,不知道頁面的焦點現在處於何處。
3.3.1 保證非滑鼠使用者體驗,合理運用 :focus-visible
造成上述結果很重要的一個原因在於,:focus
偽類不論使用者在使用滑鼠還是使用鍵盤,只要元素獲焦,就會觸發。
而其本身的預設樣式又不太能被產品或者設計接受,導致了很多人會在焦點元素觸發 :focus
偽類時,通過改變 border 的顏色或者其他一些方式替代或者直接禁用。而這樣做,從可訪問性的角度來看,對於非滑鼠使用者,無疑是災難性的。
基於此,在 W3 CSS selectors-4 規範中,新增了一個非常有意思的 :focus-visible
偽類。這個選擇器可以有效地根據使用者的輸入方式(滑鼠或是鍵盤)展示不同形式的焦點。
有了這個偽類,當使用者使用滑鼠操作可聚焦元素時,就可以做到不展示 :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
可以看到,使用滑鼠點選,不會觸發 :foucs
,只有當鍵盤操作聚焦元素,使用 Tab
切換焦點時,outline: 2px solid red
這段程式碼才會生效。
這樣,我們就既保證了正常使用者的點選體驗,也保證了一批無法使用滑鼠的使用者的焦點管理體驗。
值得注意的是,有同學會疑惑,這裡為什麼使用了 :not
這麼繞的寫法而不是直接這樣寫呢:
button:focus {
outline: unset;
}
button:focus-visible {
outline: 2px solid red;
}
為的是相容不支援 :focus-visible
的瀏覽器,當 :focus-visible
不相容時,還是需要有 :focus
偽類的存在。
我們在實際的 WMS 重構過程中,也會盡量保持這一點,讓使用者儘可能在非滑鼠操作下(僅僅使用鍵盤),也能使用我們的頁面,能做到基礎的焦點切換、回車響應事件。
下圖是一個簡單的演示(僅僅使用鍵盤進行頁面的操作,能夠知道當前焦點在哪,可以回車觸發點選):
3.3.2 使用 WAI-ARIA 規範增強語義:div
等非可獲焦元素模擬獲焦元素
還有一個非常需要注意的點。
現在很多前端同學在前端開發的過程中,喜歡使用非可獲焦元素模擬獲焦元素,例如:
- 使用
div
模擬button
元素 - 使用
ul
模擬下拉選單select
等等
當下很多元件庫都是這樣做的,像是 element-ui 和 ant-design。
在使用非可獲焦元素模擬獲焦元素的時候,一定要注意,不僅僅只是外觀長得像就完事了,其行為表現也需要符合原本的 button
、select
等可聚焦元素的性質,能夠體現元素的語義,能夠被聚焦,能夠通過 Tab 切換等等。
基於大量類似的場景,有了 WAI-ARIA 標準。它是一個為殘疾人士等提供無障礙訪問動態、可互動 Web 內容的技術規範。
簡單來說,WAI-ARIA 提供了一些屬性,用於增強標籤的語義及行為:
- 可以使用
tabindex
屬性控制元素是否可以聚焦,以及它是否/在何處參與順序鍵盤導航 - 可以使用
role
屬性,來標識元素的語義及作用,譬如使用<div id="saveChanges" tabindex="0" role="button">Save</div>
來模擬一個按鈕 - 還有大量的
aria-*
屬性,表示元素的屬性或狀態,幫助我們進一步地識別以及實現元素的語義化,優化無障礙體驗
3.4 使用工具檢視標籤的語義
我們來看看 Github 頁面是如何定義一個按鈕的。以 Github Issues 頁面的 Edit 按鈕為例:
這一塊清晰地描述了這個按鈕在可訪問性相關的一些特性。比如 Contrast
(色彩對比度)、Name
(按鈕的描述),是給螢幕閱讀器看到的;Role
標識是這個元素的屬性,它是一個按鈕,Keyboard focusable
則表明能否被鍵盤的 Tab 按鈕捕獲。
3.5 分析使用非可聚焦元素模擬的按鈕
這裡隨便選取了我們業務中一個使用 span 模擬按鈕的場景,是一個麵包屑導航,點選可進行跳轉:
HTML 程式碼:
<span class="ssc-breadcrumb-item-link"> Inbound </span>
<br/>
基本上可訪問性為零。作為一個按鈕,它不可被聚焦,無法被鍵盤使用者選中,沒有具體的語義,色彩對比度太低,可能視障使用者無法看清。並且,作為一個能進行頁面跳轉的按鈕,它沒有 <a>
標籤,沒有 href
屬性。
對於麵包屑導航,我們可以不將它改造成 <a>
標籤,但也需要做到最基本的一些可訪問性改造:
<span role="button" aria-label="goto inbound page" tabindex="0" class="ssc-breadcrumb-item-link"> Inbound </span>
不要忘了再改一下顏色,達到最低色彩對比度以上,再看看:
這樣,一個最最最基本的,滿足最低可訪問性需求的按鈕算是勉強達標。當然,這個按鈕可以再更進一步進行改造,涉及了更深入的可訪問性知識,本文不詳細展開。
3.6 分析元件庫的可訪問性
最後,我們來看看常用的 ant-design 在提升可訪問性上的一些相關功能。
以 Select 選擇框元件為例,ant-design 利用了大量的 WAI-ARIA 屬性,使得用 div 模擬的下拉框不僅僅在表現上符合一個下拉框,在語義、行為上都符合一個下拉框。
看看使用 div 模擬下拉框的 DOM 部分:
再看看在互動體驗上:
上述操作完全在鍵盤下完成,看著平平無奇,實際上元件庫在正常響應可獲焦元素切換的同時,給用 div 模擬的 select
加了很多鍵盤事件的響應,可以利用回車、上下鍵等對可選項進行選擇。其實下了很多功夫。
對於可訪問性相關的內容非常多,本文無法一一展開,這裡有一份簡單的指南:
- 通過 Web 內容無障礙指南(WCAG 2.0)瞭解可訪問性涉及的內容;
- 通過 WAI-ARIA 瞭解如何改造頁面;
- 不斷了解最新的規範,通過瀏覽器最新的功能持續增強可訪問性。
4. 總結
本文從頁面展示、互動細節、可訪問性三個大方面入手,列舉了一些在實際開發過程中積攢的有益經驗。雖然不夠全面,主要是一些可能有用但是容易被忽視的點,也算是一個不錯的查缺補漏小指南。
提升使用者體驗並非易事,但也不難:
- 頁面呈現 + 注重細節的互動設計 + 完善的可訪問性 + 效能(效能本文沒有過多提及) = 良好的使用者體驗;
- 使用者體驗是可以被提升的,而且並不難;
- 良好的使用者體驗設計,是產品開發每一個環節共同努力的結果;
- 提升使用者體驗也不是能夠一蹴而就的,在不同的細節發力,積少成多。
以上觀點和想法可能有一些理解存在問題,一些概念沒有解讀到位,也希望大家參與交流並指正。
參考資料
- WAI-ARIA basics
- WAI-ARIA 1.1
- Web 中的焦點管理
- 無障礙功能
- 功能性動畫設計:優秀的轉場效果
- 前端基礎知識概述
- 圖片載入失敗後 CSS 樣式處理最佳實踐
- 你所不知道的 CSS 動畫技巧與細節
- Web 動畫原則及技巧淺析
- 如何設計產品的空白頁面?
- 助你輕鬆做好無障礙的 15 個 UI 設計工具推薦
- Improve Your UI With Winning & Losing A/B Tests
本文作者
Coco,前端開發工程師,來自 Shopee 供應鏈倉儲管理(Warehouse management system, WMS)團隊。