1. <dd id="mhwbf"><track id="mhwbf"></track></dd>

  2. <em id="mhwbf"></em><dd id="mhwbf"></dd>
  3. <rp id="mhwbf"><object id="mhwbf"></object></rp>

    1. <em id="mhwbf"><ruby id="mhwbf"></ruby></em>
      <button id="mhwbf"><acronym id="mhwbf"></acronym></button>

          <dd id="mhwbf"></dd>

          前端優秀實踐不完全指南

          來源:掘金
          2021-02-27
          854
          導語:本文從頁面展示、交互細節、可訪問性三個大方面入手,羅列一些在實際的開發過程中,積攢的一些有益的經驗。雖然不夠全面,不過從一開始也就沒想著大而全,主要是一些可能有用但是容易被忽視的點,也算是一個不錯的查缺補漏小指南。
          閱讀本文大概需要12分鐘

          本文其實應該叫,Web 用戶體驗設計提升指南。

          一個 Web 頁面,一個 APP,想讓別人用的爽,也就是所謂的良好的用戶體驗,我覺得他可能包括但不限于:

          • 急速的打開速度
          • 眼前一亮的 UI 設計
          • 酷炫的動畫效果
          • 豐富的個性化設置
          • 便捷的操作
          • 貼心的細節
          • 關注殘障人士,良好的可訪問性
          • ...

          所謂的用戶體驗設計,其實是一個比較虛的概念,是秉承著以用戶為中心的思想的一種設計手段,以用戶需求為目標而進行的設計。設計過程注重以用戶為中心,用戶體驗的概念從開發的最早期就開始進入整個流程,并貫穿始終。

          良好的用戶體驗設計,是產品每一個環節共同努力的結果。

          除去一些很難一蹴而就的,本文將就頁面展示、交互細節、可訪問性三個方面入手,羅列一些在實際的開發過程中,積攢的一些有益的經驗。通過本文,你將能收獲到:

          1. 了解到一些小細節是如何影響用戶體驗的
          2. 了解到如何在盡量小的開發改動下,提升頁面的用戶體驗
          3. 了解到一些優秀的交互設計細節
          4. 了解基本的無障礙功能及頁面可訪問性的含義
          5. 了解基本的提升頁面可訪問性的方法

          頁面展示

          就整個頁面的展示,頁面內容的呈現而言,有一些小細節是需要我們注意的。

          整體布局

          先來看看一些布局相關的問題。

          對于大部分 PC 端的項目,我們首先需要考慮的肯定是最外層的一層包裹。假設就是 .g-app-wrapper。

          <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 時,則出現滾動條,保證內部內容不亂。

          ">

          對于現代布局,更多的是全屏布局。其實現在也更提倡這種布局,即使用可隨用戶設備的尺寸和能力而變化的自適應布局。

          通常而言是左右兩欄,左側定寬,右側自適應剩余寬度,當然,會有一個最小的寬度。那么,它的布局應該是這樣:

          <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

          當然,實現它的方法有很多,這里僅給出一種推薦的解法。

          處理動態內容 - 文本超長

          對于所有接收后端接口字段的文本展示類的界面。都需要考慮全面(防御性編程:所有的外部數據都是不可信的),正常情況如下,是沒有問題的。

          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 結果頁面設計,可以詳細看看這篇文章:如何設計產品的空白頁面?

          小小總結一下,上述比較長的篇幅一直都在闡述一個道理,開發時,不能僅僅關注正?,F象,要多考慮各種異常情況,思考全面。做好各種可能情況的處理。

          圖片相關

          圖片在我們的業務中應該是非常的常見了。有一些小細節是需要注意的。

          給圖片同時設置高寬

          有的時候和產品、設計會商定,只能使用固定尺寸大小的圖片,我們的布局可能是這樣:

          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;
          }
          復制代碼

          同時,給 標簽同時寫上高寬,可以在圖片未加載之前提前占住位置,避免圖片從未加載狀態到渲染完成狀態高寬變化引起的重排問題。

          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 的屏幕。

          正好, 標簽是有提供相應的屬性 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. 利用圖片加載失敗,觸發 元素的 onerror 事件,給加載失敗的 元素新增一個樣式類
          2. 利用新增的樣式類,配合 元素的偽元素,展示默認兜底圖的同時,還能一起展示 元素的 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 效果,其實就是這樣一種作用,讓用戶感知頁面正在加載,或者正在處理某些事務。

          ">

          滾動優化

          滾動也是操作網頁中非常重要的一環??纯从心男┛梢詢灮狞c:

          滾動平滑:使用 scroll-behavior: smooth 讓滾動絲滑

          使用 scroll-behavior: smooth,可以讓滾動框實現平穩的滾動,而不是突兀的跳動??纯葱Ч?,假設如下結構:

          <div class="g-container">
            <nav>
              <a href="#1">1a>
              <a href="#2">2a>
              <a href="#3">3a>
            nav>
            <div class="scrolling-box">
              <section id="1">First sectionsection>
              <section id="2">Second sectionsection>
              <section id="3">Third sectionsection>
            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-in、zoom-out 等等:

          image">

          一些常用的簡單列一列:

          • 按鈕可點擊: cursor: pointer
          • 按鈕禁止點擊:cursor: not-allowed
          • 等待 Loading 狀態:cursor: wait
          • 輸入框:cursor: text;
          • 圖片查看器可放大可縮?。?code>cursor: zoom-in/ zoom-out
          • 提示:cursor: help;

          當然,實際 cursor 還支持非常多種,可以在 MDN 或者下面這個 CodePen Demo 中查看這里看完整的列表:

          CodePen Demo -- Cursor Demo

          點擊區域優化 -- 偽元素擴大點擊區域

          按鈕是我們網頁設計中十分重要的一環,而按鈕的設計也與用戶體驗息息相關。

          考慮這樣一個場景,在搖晃的車廂上或者是單手操作著屏幕,有的時候一個按鈕,死活也點不到。

          讓用戶更容易的點擊到按鈕無疑能很好的增加用戶體驗及可提升頁面的訪問性,尤其是在移動端,按鈕通常都很小,但是受限于設計稿或者整體 UI 風格,我們不能直接去改變按鈕元素的高寬。

          那么這個時候有什么辦法在不改變按鈕原本大小的情況下去增加他的點擊熱區呢?

          這里,偽元素也是可以代表其宿主元素來響應的鼠標交互事件的。借助偽元素可以輕松幫我們實現,我們可以這樣寫:

          .btn::befoer{
            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">

          • 翻頁按鈕的快速點擊,觸發了瀏覽器的雙擊快速選擇:

          對于這種場景,我們需要把不可被選中元素設置為不可被選中,利用 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 等框架大行其道。但是一些常見的寫法,也容易衍生一些小問題。

          譬如,點擊按鈕、文本進行路由跳轉。譬如,經常會出現這種代碼: