整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          前端技術-由蒙層截圖失敗展開的html2canvas

          前端技術-由蒙層截圖失敗展開的html2canvas實現原理探討

          導語

          html2canvas在前端通常用于合成海報、生成截圖等場景。本文由一次蒙層截圖失敗對html2canvas的實現原理進行探討。


          01

          問題背景


          在一個前端項目中,有對當前頁面進行截屏并上傳的需求。安裝了html2canvas的npm包后,實現頁面截圖時,發現html2canvas將原本有透明度的蒙層截圖為了沒有透明度的蒙層,如下面兩張圖所示:


          顯然這并不能滿足前端截屏的需求,于是進行google,終于查到了相關問題。原來html2canvas渲染opacity失敗的問題自2015年起就已存在,雖然niklasvh在2020年12月修復了該問題,但是并沒有合并入npm包中。所以當使用html2canvas的npm包實現截圖時,仍然存在opacity渲染失敗的問題。


          為了徹底搞明白html2canvas渲染opacity失敗的問題,我們先對html2canvas的實現原理進行剖析。

          02

          html2canvas原理剖析

          2.1

          流程圖

          如下圖所示,將html2canvas原理圖形化,主要分成出口供用戶使用的主要流程和兩部分核心邏輯:克隆并解析DOM節點、渲染DOM節點。

          2.2

          html2canvas方法

          html2canvas是出口方法,主要將用戶選擇的DOM節點和自定義配置項傳遞給renderElement方法。簡要邏輯代碼如下:

          const html2canvas=(element: HTMLElement, options: Partial<Options>={}): Promise<HTMLCanvasElement>=> {
          return renderElement(element, options);
          };

          向右滑動查看完整版


          renderElement方法,主要把用戶自定義配置與默認配置進行合并,生成CanvasRenderer實例,克隆、解析并渲染用戶選擇的DOM節點。簡要邏輯代碼如下:

          const renderElement=async (element: HTMLElement, opts: Partial<Options>): Promise<HTMLCanvasElement>=> {
          const renderOptions={...defaultOptions, ...opts}; // 合并默認配置與用戶自定義配置
          const renderer=new CanvasRenderer(renderOptions); // 根據渲染配置數據生成CanvasRenderer實例
          const documentCloner=new DocumentCloner(element, options); // 生成DocumentCloner實例
          const clonedElement=documentCloner.clonedReferenceElement; // createNewHtml層層遞歸查找用戶選擇的DOM元素,并克隆
          const root=parseTree(clonedElement); // 解析克隆的DOM元素,獲取節點信息
          const canvas=await renderer.render(root); // CanvasRenderer實例將克隆的DOM元素內容渲染到離屏canvas中
          return canvas;
          };

          向右滑動查看完整版

          2.3

          克隆并解析DOM節點

          CanvasRenderer是canvas渲染類,后續使用的渲染方法均是該類的方法。在克隆并解析DOM節點部分,主要是將renderOptions傳給canvasRenderer實例,調用render方法來繪制canvas。


          DocumentCloner是DOM克隆類,主要是生成documentCloner實例,克隆用戶所選擇的DOM節點。其核心方法cloneNode通過遞歸整個DOM結構樹,匹配查詢用戶選擇的DOM節點并進行克隆,簡要邏輯代碼如下:

          cloneNode(node: Node): Node {
          const window=node.ownerDocument.defaultView;
          if (window && isElementNode(node) && (isHTMLElementNode(node) || isSVGElementNode(node))) {
          const clone=this.createElementClone(node);
          if (this.referenceElement===node && isHTMLElementNode(clone)) {
          this.clonedReferenceElement=clone;
          }
          ...
          for (let child=node.firstChild; child; child=child.nextSibling) {
          if (!isElementNode(child) || (!isScriptElement(child) && !child.hasAttribute(IGNORE_ATTRIBUTE) && (typeof this.options.ignoreElements !=='function' || !this.options.ignoreElements(child)))) {
          if (!this.options.copyStyles || !isElementNode(child) || !isStyleElement(child)) {
          clone.appendChild(this.cloneNode(child));
          }
          }
          } // 層層遞歸DOM樹,查找匹配并克隆用戶所選擇的DOM節點
          ...
          return clone;
          }
          return node.cloneNode(false);
          } // 輸出格式為DOM節點格式



          parseTree方法是解析克隆DOM節點,獲取節點的相關信息。parseTree層層遞歸克隆DOM節點,獲取DOM節點的位置、寬高、樣式等信息,簡要邏輯代碼如下:

          export const parseTree=(element: HTMLElement): ElementContainer=> {
          const container=createContainer(element);
          container.flags |=FLAGS.CREATES_REAL_STACKING_CONTEXT;
          parseNodeTree(element, container, container);
          return container;
          };
          const parseNodeTree=(node: Node, parent: ElementContainer, root: ElementContainer)=> {
          for (let childNode=node.firstChild, nextNode; childNode; childNode=nextNode) {
          nextNode=childNode.nextSibling;
          if (isTextNode(childNode) && childNode.data.trim().length > 0) {
          parent.textNodes.push(new TextContainer(childNode, parent.styles));
          } else if (isElementNode(childNode)) {
          const container=createContainer(childNode);
          if (container.styles.isVisible()) {
          ...
          parent.elements.push(container);
          if (!isTextareaElement(childNode) && !isSVGElement(childNode) && !isSelectElement(childNode)) {
          parseNodeTree(childNode, container, root);
          }
          }
          }
          }// 層層遞歸克隆DOM節點,解析獲取節點信息
          };



          parseTree輸出的格式如下:
          const ElementContainer={
          bounds: Bounds {left: 8, top: 8, width: 389, height: 313.34375},
          elements: [
          {
          bounds: Bounds {left: 33, top: 33, width: 339, height: 263.34375}
          elements: [],
          flags: 0,
          style: CSSParsedDeclaration {backgroundClip: Array(1), backgroundColor: 4289003775, …},
          textNodes: [],
          },
          ...
          ],
          flags: 4,
          style: styles: CSSParsedDeclaration {backgroundClip: Array(1), backgroundColor: 4278190335, …},
          textNodes: [],
          }
          // bounds:位置、寬高
          // elements:子元素
          // flags:如何渲染的標志
          // style:樣式
          // textNodes:文本節點


          2.4

          層疊上下文

          在探討html2canvas渲染DOM節點的實現原理之前,先來闡明一下什么是層疊上下文。


          層疊上下文(stacking content),是HTML中的一種三維概念。如果一個節點含有層疊上下文,那么在下圖的Z軸中距離用戶更近。

          當一個節點滿足以下條件中的任意一個,則該節點含有層疊上下文。

          • 文檔根元素<html>
          • position為absolute或relative,且z-index不為auto
          • position為fixed或sticky
          • flex容器的子元素,且z-index不為auto
          • grid容器的子元素,且z-index不為auto
          • opacity小于1
          • mix-blend-mode不為normal
          • transform、filter、perspective、clip-path、mask/mask-imag/mask-border不為none
          • isolation為isolate
          • -webkit-overflow-scrolling為touch
          • will-change 為任意屬性值
          • contain為layout、paint、strict、content

          著名的7階層疊水平對DOM節點進行分層,如下圖所示:

          通過以下html結構對7階層疊水平進行驗證時,發現層疊水平為:z-index為負的節點在background/border的下面 ,與7階層疊水平有所出入。

          <div style="width: 300px; height: 120px;background: #ccc; border: 20px solid #F56C6C">
          <span style="color: #fff;margin-left: -20px;">內聯元素內聯元素內聯元素內聯元素內聯元素</span>
          <div style="width: 200px;height: 100px;background: #67C23A; margin-left: -20px; margin-top: -10px;"></div>
          <div style="float: left; width: 150px; height: 100px; background: #409EFF; margin-top: -110px;"></div>
          <div style="position: relative; background: #E6A23C; width: 100px; height: 100px; margin-top: -100px;"></div>
          <div style="position: absolute; z-index: 1; background: yellow; width: 50px; height: 50px; top: 110px;"></div>
          <div style="position: absolute; z-index: -1; background: #000; height: 200px; width: 100px; top: 90px"></div>
          </div>

          向右滑動查看完整版

          但是,當父元素具有定位和z-index屬性時,z-index為負的節點在background/border上面,與7階層疊水平相印證。

          <div style="width: 300px; height: 120px; background: #ccc; border: 20px solid #F56C6C; position: relative; z-index: 0; ">
          <span style="color: #fff; margin-left: -20px;">內聯元素內聯元素內聯元素內聯元素內聯元素</span>
          <div style="width: 200px; height: 100px; background: #67C23A; margin-left: -20px; margin-top: -10px;"></div>
          <div style="float: left; width: 150px; height: 100px; background: #409EFF; margin-top: -110px;"></div>
          <div style="position: relative; width: 100px; height: 100px; background: #E6A23C; margin-top: -100px;"></div>
          <div style="position: absolute; width: 50px; height: 50px; z-index: 1; background: yellow; top: -10px;"></div>
          <div style="position: absolute; height: 200px; width: 100px; z-index: -1; background: #000; top: -30px"></div>
          </div>



          2.5

          渲染DOM節點

          html2canvas是依據層疊上下文對DOM節點進行渲染。所以,在渲染DOM節點之前,需要先獲取DOM節點的層疊上下文。parseStackingContexts方法對克隆的DOM節點進行解析,獲取了克隆DOM節點的層疊上下文關系,其輸出的格式如下:

          const StackingContext={
          element: ElementPaint {container: ElementContainer, effects: Array(0), curves: BoundCurves},
          inlineLevel: [],
          negativeZIndex: [],
          nonInlineLevel: [ElementPaint],
          nonPositionedFloats: [],
          nonPositionedInlineLevel: [],
          positiveZIndex: [],
          zeroOrAutoZIndexOrTransformedOrOpacity: [],
          };
          // element: parseTree輸出的ElementContainer、DOM節點邊界信息、特殊渲染效果
          // inlineLevel:內聯元素
          // negativeZIndex:z-index為負的元素
          // nonInlineLevel:非內聯元素
          // nonPositionedFloats:未定位的浮動元素
          // nonPositionedInlineLevel:未定位的內聯元素
          // positiveZIndex:z-index為正的元素
          // zeroOrAutoZIndexOrTransformedOrOpacity:z-index: auto|0、opacity小于1,transform不為none的元素



          然后,renderStack方法調用renderStackContent方法遵循層疊上下文,自底層向上層層渲染DOM節點,簡要邏輯代碼如下:

          async renderStackContent(stack: StackingContext) {
          // 1. 第一層background/border.
          await this.renderNodeBackgroundAndBorders(stack.element);
          // 2. 第二層負z-index.
          for (const child of stack.negativeZIndex) {
          await this.renderStack(child);
          }
          // 3. 第三層block塊狀水平盒子
          await this.renderNodeContent(stack.element);
          
          for (const child of stack.nonInlineLevel) {
          await this.renderNode(child);
          }
          // 4. 第四層float浮動盒子.
          for (const child of stack.nonPositionedFloats) {
          await this.renderStack(child);
          }
          // 5. 第五層inline/inline-block水平盒子.
          for (const child of stack.nonPositionedInlineLevel) {
          await this.renderStack(child);
          }
          for (const child of stack.inlineLevel) {
          await this.renderNode(child);
          }
          // 6. 第六層z-index: auto 或 z-index: 0, transform: none, opacity < 1
          for (const child of stack.zeroOrAutoZIndexOrTransformedOrOpacity) {
          await this.renderStack(child);
          }
          // 7. 第七層正z-index.
          for (const child of stack.positiveZIndex) {
          await this.renderStack(child);
          }
          }



          最后,在方法renderNodeBackgroundAndBorders和方法renderNodeContent內部,調用了方法applyeffects方法地特殊效果進行渲染。而html2canvas的npm包中,缺少了透明度渲染效果的處理邏輯。這正是文章開頭出現的透明蒙層截圖失敗的根源所在。


          03

          問題定位與解決


          通過對比niklasvh提交的版本記錄fix: opacity with overflow hidden #2450,發現新增了一個透明度渲染效果的處理邏輯,簡要代碼邏輯如下:

          export class OpacityEffect implements IElementEffect {
          readonly type: EffectType=EffectType.OPACITY;
          readonly target: number=EffectTarget.BACKGROUND_BORDERS | EffectTarget.CONTENT;
          readonly opacity: number;
          
          constructor(opacity: number) {
          this.opacity=opacity;
          }
          }
          export const isOpacityEffect=(effect: IElementEffect): effect is OpacityEffect=> effect.type===EffectType.OPACITY;
          


          在parseStackingContexts解析DOM節點層疊上下文,輸出StackingContext時,在element的ElementContainer中新增了記錄節點透明度的邏輯,簡要代碼邏輯如下:

          if (element.styles.opacity < 1) {
          this.effects.push(new OpacityEffect(element.styles.opacity));
          }



          最后在applyEffects方法中,對DOM節點的透明度進行渲染,簡要代碼邏輯如下:

          if (isOpacityEffect(effect)) {
          this.ctx.globalAlpha=effect.opacity;
          }



          至此,將上述邏輯融合進html2canvas的npm包后,可解決透明蒙層截圖失敗的問題。


          Refe:

          1. https://www.zhangxinxu.com/wordpress/2016/01/understand-css-stacking-context-order-z-index/
          2. https://zhuanlan.zhihu.com/p/116775011
          3. https://blog.csdn.net/kagol/article/details/111452697
          4. https://github.com/niklasvh/html2canvas
          5. https://github.com/niklasvh/html2canvas/issues/717

          來源-微信公眾號:騰訊優聯技術團隊

          出處:https://mp.weixin.qq.com/s/1blzBT_yH-MjQSft90TUSg

          每一個特定或者特殊的日子里,幾乎所有的網站都變成了灰色,那么這種效果是怎么實現的呢?

          今天就來簡單的實現一下這樣的效果。



          添加以下全局CSS樣式,可以實現此效果:

          代碼一:

          html {
            -webkit-filter: grayscale(100%);filter:progid:DXImageTransform.Microsoft.BasicImage(graysale=1);
          } 
          <!-- 可以是整個網站變成灰色的  -->


          實現網頁顏色變灰這個效果,非常簡單:

          filter: grayscale(100%);
          

          這樣一段代碼即可實現,放在html和body的css屬性里即可實現。

          意思是修改所有的顏色為黑白 (100% 灰度):

          灰色網站會加入這段代碼,你可以按F12,把這段源碼刪除,即可變成彩色


          代碼二:

          html { 
             filter:progidXImageTransform.Microsoft.BasicImage(grayscale=1); 
          }

          使用方法:這段代碼可以變網頁為黑白,將代碼加到CSS最頂端就可以實現素裝。建議全國站長動起來。為在地震中遇難的同胞哀悼。

          如果網站沒有使用CSS,可以在網頁/模板的HTML代碼<head>和</head> 之間插入:

          <style>
             html{
               filter:progidXImageTransform.Microsoft.BasicImage(grayscale=1);
            }
          </style>

          有一些站長的網站可能使用這個css 不能生效,是因為網站沒有使用最新的網頁標準協議:

          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
          <html xmlns="http://www.w3.org/1999/xhtml">

          請將網頁最頭部的<html>替換為以上代碼。

          有一些網站FLASH動畫的顏色不能被CSS濾鏡控制,可以在FLASH代碼的<object …>和</object>之間插入:

          <param value="false" name="menu"/>
          <param value="opaque" name="wmode"/>

          最簡單的把頁面變成灰色的代碼是在head 之間加

          <style type="text/css"> 
          html {
             FILTER: gray
          }
          </style>


          代碼三:

          html{ 
          filter: grayscale(100%); 
          -webkit-filter: grayscale(100%); 
          -moz-filter: grayscale(100%);
          -ms-filter: grayscale(100%); 
          -o-filter: grayscale(100%); 
          filter: url("data:image/svg+xml;utf8,#grayscale"); 
          filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1); 
          -webkit-filter: grayscale(1);
          }


          總結:

          以上幾種代碼(方法),都是通過CSS的濾鏡來控制頁面的顯示而已,唯一不同的就CSS代碼及調用的方式。在css的修飾時還有權重問題,所以有時候css代碼不生效的時候可以考慮一下代碼的權重問題。

          歡迎關注第一山,今后將有更多前端開發技術與大家共同交流學習。

          輯導語:一些復雜的B端系統,在用戶用起來時會比較困難,總能聽到用戶說學不會,不會用,為了減低用戶的使用成本,搭建一個全局的幫助系統是很有必要,本文從三大幫助系統類型出發,進行詳細拆解。

          一些復雜的B端產品,因為其特殊的業務屬性和復雜度操作使用上門檻不低,總是會聽到用戶反饋不會用、學不會、記不住。為了降低用戶使用成本,保證用戶在一個大型業務系統的可用性,引入一個在全局系統層面用戶幫助體系對于提升用戶體驗是非常有必要的。

          Jakob Nielsen于1994年提出的十大可用性原則中,其最后一條原則Help and documentation(幫助性指導原則)是搭建B端用戶幫助體系的核心準則,在理想情況下,沒有幫助文檔就可以使用系統是最好的,但在某些情況下(尤其是B端系統),提供一些引導性的幫助其實是必要的。本文從三種 B 端幫助體系的三種類型主動式幫助、被動式幫助、自動式幫助進行詳細拆解說明。

          一、主動式幫助

          什么是主動式幫助呢?回歸到生活的場景中,進入地鐵站的方向指示牌,馬路上的路標,都是讓行人們可以根據指示找到想去的地方;剛剛參加工作,一般都會有前輩帶著你學習工作流程,進行教學指導;機場和車站的展示大屏,告訴我們目前車次的檢票口和車輛狀況,這些都是我們生活中主動幫助的例子。

          沿用到互聯網產品中也是一樣的,同樣也是主動幫助向用戶提供幫助,讓用戶盡快熟悉系統。

          1. 在系統中的使用場景

          對于第一次接觸系統或者第一次接觸系統中某個模塊的新用戶,剛開始使用產品的時候,需要快速熟悉并嘗試系統中的某一功能,這個時候系統提供一些主動的功能介紹或者操作引導可以讓用戶快速了解。

          下面是一款室內裝修設計師畫圖使用的系統,屬于操作復雜的工具類型,對于新用戶來說在第一次進入系統主動出現一個彈窗介紹完成渲染出圖的步驟,可以讓用戶快速學習到什么使用這款產品做一個設計效果圖,也讓用戶清楚了解每個步驟之間的先后順序。

          對于老用戶當系統新上線了功能需要告知哪里更新了,更新了什么內容。花瓣更新了點擊頭像下拉后展示更多信息的功能,在改版后第一次進入系統,出現了提示引導,引導用戶快速點擊進行體驗,當然也可以選擇關閉。

          使用主動幫助有 2 個核心場景,「對新用戶幫助教學」和「新功能上線后對老用戶的提示」; 總結 5 種交互形式:引導頁、模態彈窗、向導形式、工具提示、文字提示,需要設計師根據不同的場景,去適配不同的引導方式。

          2. 引導頁

          在用戶首次進入產品或者產品中某個獨立功能的時候,將產品最核心的功能加入一些品牌基調展示給用戶,可以加入一些插畫或者視頻吸引用戶,另外需要注意在文字部分不要長篇大論,提煉最核心的內容傳達給用戶。

          3. 模態彈窗

          讓用戶聚焦當前內容,在用戶第一次打開某個特定頁面時出現,缺點是用戶容易忽略或者無視,直接關掉,引導的效果差一點,所以彈窗教程建議保留二次進入的入口,當用戶需要的時候可以順利找到。應用場景有「版本更新提示」「新功能介紹」「常規通告」。

          設計形式上可以在文本的基礎上加入圖片、插畫、動畫、視頻講解和實例演示等視覺表現形式,不管用什么形式,其目的都是幫助用戶快速理解系統的功能特性。也可以使用一些視覺元素烘托氛圍,并在文案上注入情緒化的表達,從而提升用戶的關注度。

          承載內容上可以師簡單業務邏輯的功能說明或單頁面功能,采用讓用戶一次性進行學習。復雜業務邏輯的功能說明或多頁面功能聯動,通常會進行分步講解,通過循序漸進的形式將所有知識點逐漸披露出來,讓用戶有充裕時間進行信息的接收和理解。

          4. 向導引導

          在用戶首次進入相關頁面,且無操作時出現。有明確的指向性,提前告知用戶具體功能的使用場景,因此它會具體指向界面中的某些特定區域,同時會隨著具體操作的具體位置發生變化,讓用戶實際感知到功能的整個運轉邏輯和流程。針對局部功能升級的提示說明,一般與元素綁定關系較強,可讓用戶直觀了解關注點,提升功能觸達率。

          設計組成元素蒙層(可選)+ 文字 + 插圖/GIF(可選)。向導主要圍繞某個操作的引導說明,與元素綁定關系較強,核心功能和操作在視覺上突出顯示。

          為了讓用戶高效獲取信息,一次僅顯示一條。如果需要用戶聚焦了解功能或說明,不被頁面中其他元素干擾使用蒙層,注意蒙層的透明度要比彈窗蒙層淺,向導的蒙層需要用戶可以看到元素在頁面中的位置。具體使用過程中有三種交互方式隨著提示強度由強到弱依次是:「分布引導」「氣泡提示」「閃點提示」

          分步式引導(重):常用于頁面多個功能升級的引導組。當頁面有多個升級點,直接平鋪會讓頁面臃腫不聚焦。通過「下一步」操作,逐步喚出剩余引導。為避免步驟過多導致用戶疲勞,建議最多不超過5步。

          氣泡式(輕):相對輕量的引導,有足夠的提示性但不影響其他功能操作。

          閃點提示(弱):微輔助型提示,常與氣泡引導配合使用。在需要關注的地方閃爍,點擊閃點后喚出關聯氣泡提示。不對用戶造成視覺干擾,又能引起一定的關注。

          5. 文字提示

          文字提示作為最直觀的信息展示,一般會采用直接平鋪的展示方式,針對一些功能較多邏輯較為復雜的頁面,將對用戶有幫助的信息直接放在頁面上從而指導用戶的行為不失為一種簡單粗暴的設計方法。對重點或復雜功能提供直觀描述或建議。

          帶有引導性的文案處理,會促進用戶優化填寫方案,輸入更合適的內容。關于文案設計的詳細延展查看https://www.zcool.com.cn/work/ZNjA3NzU1ODA=.html這篇文章非常詳細的拆解了文案設計原則以及使用場景。具體的使用場景有:「頁面功能輔助說明」「占位提示」。

          6. 工具提示

          工具提示比文字直接展示要更簡潔降噪,沒有直接進行展示,在用戶需要的時候通過懸浮或者點擊元素以氣泡的形式呼出,Material Design在對工具提示(Tooltip)的官方定義是這樣的:“When activated, tooltips display a text label identifying an element, such as a description of its function.”工具提示僅僅起到提示的作用,它會出現在當用戶激活某一控件的時候,針對某一特定的元素通過簡要的文字來闡述其功能特性。

          在設計形式上有短暫性、匹配性、簡明性的特點:短暫性指工具提示出現和消失的時機需要恰當和短暫;匹配性指工具提示需要出現在與之關聯的元素附近;簡明性則是對工具提示承載的文本內容提出了要求,要盡可能具備簡短性和描述性。

          二、被動式幫助

          被動引導映射到我們生活中的場景下可以看作是手機地圖導航軟件,當你不知道該怎么走或者迷路的時候才會主動去打開地圖軟件進行導航。

          另一個生活中的場景是產品說明書,在使用前或者再遇到不會用的功能的時候才會去查閱說明書,無論是導航軟件還是說明書它不會自動把全部內容展示在你眼前,都需要你去進行查找。沿用到互聯網產品中是指用戶遇到問題的時候系統能夠提供一些幫助,去指導用戶接下來怎么做。

          1. 在系統中的使用場景

          被動式幫助一般會依托于主動式幫助,產品發展的初期階段,主動式幫助是必須的,當產品發展到一定規模具備一定成熟度后,被動式幫助的引入就可以極大的提高整體產品的使用體驗。常用的被動引導有:幫助中心/幫助文檔、客服支持、全局常駐性功能。

          2. 全局提示

          重點信息的匯總或提示。此類提示完美融合于頁面,醒目且對操作無干擾,用戶可根據披露內容判斷是否處理。常用的交互形式是全局提示、徽標,向用戶傳達信息的變化并提供快速觸達的能力,無形中提升用戶響應效率。

          全局提示:不同顏色的提示條。常作為前置提示存在于頁面或模塊頂部,為用戶順利操作提供指引性幫助。既不打斷用戶當前操作,又足夠明顯,一般需手動關閉或事件結束后自行消失。不同顏色屬性不同:一般藍色代表消息通知、綠色代表成功、橙色代表警示、紅色代表錯誤或異常等情況。

          徽標:形態各異的小紅點。常出現在圖標、按鈕右上角的紅色圓點、數字或文字,簡單且醒目。表示內容更新或有待處理的信息,此類提示符合用戶心智,無需教育就能向用戶精準傳達提示意圖。使用時注意無數字與有數字的應用場景。有數字的徽標給用戶帶來的心理壓力會更大,也會更吸引用戶注意力,同時需注意數字長度控制。

          3. 客服中心

          客服中心是B端產品的服務團隊和客戶建立聯系的平臺,目前大部分客服采用智能客服+人工客服的組合,通過智能客服先過濾已經在幫助中心的問題,可以解決 80%以上的共性簡單的問題,剩下沒有辦法通過智能客服解決的問題會轉接到人工客服。

          在設計上通常懸浮在右下角以入口或者懸浮窗口的形式,可以加入品牌形象IP、情感化來提升存在感,吸引用戶關注拉近平臺與用戶的距離。

          4. 幫助中心

          幫助中心是全平臺信息文檔的匯總,提供一個快捷入口,幫助用戶了解他想了解的問題,在幫助文檔中需要注意方便用戶直接進行搜索。文檔內容要針對用戶的核心任務,描述要盡量步驟化和流程化,另外由于大部分用戶實際上都不喜歡閱讀大篇幅文字,如何在文檔中直接傳達重要的信息也很重要。

          在設計上為保證用戶高效獲取信息,需突出內容本身,不要度裝飾。框架設計清晰將頁面氛圍導航區和內容展示區,讓用戶通過導航快速定位到想要查找的內容。一般幫助中心會由三部分組成:產品介紹,產品入門和使用,常見問題的匯總。

          三、自助式幫助

          自助式幫助就就像我們去吃自助餐,不用自己買菜、處理食材、烹飪,飯店直接把我們可能會喜歡的食物準備好了,直接來選擇自己喜歡的食物就可以了。在系統中也是一樣提前預判用戶的預期,直接為用戶提供建議和幫助,或者直接幫用戶自動執行一些任務,減少用戶的決策壓力,不過前提是需要產品設計師考慮非常周全并配合大量數據支撐。

          1. 在系統中的使用場景

          針對一些用戶操作風險較小且系統能力能夠支持的場景,可以直接交付系統來自動完成。一些用戶操作風險較大且系統能力也能夠勉強支持的場景,可以提供部分選項供用戶進行選擇,同時提供必要的容錯能力。常用的自助式幫助引導有智能推薦、錯誤校驗。

          2. 智能推薦

          系統自動提供內容供用戶進行選擇,幫助用戶做出決策,不過這種設計的前提是平臺有足夠的數據積累,系統通過字段自動為用戶預置內容。

          3. 模版設計

          用戶新建每一個內容都需要從頭到尾重新填寫一遍內容,成本極高,可以把高頻的類型變為模版進行選擇。

          4. 錯誤校驗

          當操作出現輸入錯誤時,為用戶展示明確的提示性消息,糾正和引導用戶的修改內容。設計的時候需要注意反饋的時機做到及時反饋,將發生了什么,接下來怎么調整告知用戶。常見的有以下類型:toast、表單錯誤校驗、模態彈窗、根據不同的場景適配不同的交互方式。

          最后

          任何的引導都要注意任何事情都是過尤不及,適當的給用戶提供幫助當然是好的,但是在用戶不需的時候過多的進行引導和幫助反而會適得其反,我們在使用引導和幫助的時候一定要合理的進行判斷,避免適得其反。

          本文由@郭大毛毛設計筆記 原創發布于人人都是產品經理,未經許可,禁止轉載。

          題圖來自 Unsplash,基于 CC0 協議


          主站蜘蛛池模板: 日本一区二区视频| 激情亚洲一区国产精品| 三上悠亚日韩精品一区在线| 无码一区18禁3D| 亚洲另类无码一区二区三区| 日韩一区二区三区视频久久| 国产一区二区中文字幕| 秋霞无码一区二区| 一区二区三区四区精品| 日韩精品福利视频一区二区三区| 果冻传媒董小宛一区二区| 国产微拍精品一区二区| 伊人久久大香线蕉av一区| 色一乱一伦一图一区二区精品| 亚洲日韩一区二区三区| 中文字幕日本精品一区二区三区| 日韩精品一区二区三区在线观看l| 人妻少妇AV无码一区二区| 久久精品免费一区二区喷潮| 精品视频一区二区三区在线观看 | 日韩一区二区在线观看| 精品国产aⅴ无码一区二区| 国产一区二区三区在线视頻| 日本一区二区高清不卡| 成人欧美一区二区三区在线视频 | 国产成人高清视频一区二区| 亚洲AV成人精品一区二区三区| 国产麻豆精品一区二区三区v视界| 成人毛片一区二区| 3d动漫精品啪啪一区二区中文 | 国产精品无码一区二区三区在| 国产精品视频一区| 国产成人一区二区三中文| 日韩精品无码一区二区中文字幕| 国产suv精品一区二区6| 亚洲AⅤ视频一区二区三区| 国模极品一区二区三区| 无码丰满熟妇一区二区| 亚洲av色香蕉一区二区三区蜜桃| 成人日韩熟女高清视频一区| 精品3d动漫视频一区在线观看|