整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

前端技术-由蒙层截图失败展开的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 协议