前端不止:Web性能优化 – 关键渲染路径以及优化策略

我问你:“当你从搜索引擎的结果页面选择打开一条搜索结果时,你觉得多长时间之后,如果页面还处于白屏或者没有加载到关键信息,你会选择关掉这个窗口?”

《Designing for Performance》的作者 Lara Swanson 在2014年写过一篇文章《Web性能即用户体验》,她在文中提到“网站页面的快速加载,能够建立用户对网站的信任,增加回访率,大部分的用户其实都期待页面能够在2秒内加载完成,而当超过3秒以后,就会有接近40%的用户离开你的网站”。

Google和亚马逊的研究表明,Google页面加载的时间从0.4秒提升到0.9秒导致丢失了20%流量和广告收入,对于亚马逊,页面加载时间每增加100毫秒就意味着1%的销售额损失。可见,页面的加载速度对于用户可能的下一步操作是多么的举足轻重。

想一想,如果你希望你的网站在一秒钟之内呈现用户想看的关键信息,有哪些可行的手段?Minify,压缩,雪碧图等等。

Google的Web性能工程师 Ilya Grigorik 会告诉你,你只需要理解浏览器的关键渲染路径。

页面性能可能是一个感性的东西

页面的性能,看似是一个理性和量化的概念,实则也来自于用户的感知,主观的评价,是一个偏感性的东西。

(参考自Google关键渲染路径)

如果页面可以做到优先显示与用户操作有关的内容,就可以让用户更快速的感知到操作得到响应,这个过程叫做“优化关键渲染路径”。

什么是关键渲染路径

我记得,有一个非常经典的面试题叫做:《当浏览器地址栏输入URL并回车后,发生了什么?》。

关键渲染路径就是描述浏览器从收到 HTML、CSS 和 JavaScript 字节开始,到如何使用HTML、CSS 和 JavaScript 在屏幕上渲染像素的中间过程。

如果我们能够优化这条路径,就能让页面更快速的展示内容,给用户更好的体验。

全景图

我们先尝试站在高处,看一眼关键渲染路径的全景图,这样能够快速的领略一个大致轮廓和一些关键概念。

文档对象模型 (DOM)

DOM概念之于Web开发人员再熟悉不过了,当浏览器发出请求并接收到HTML文档后,它会有这样一个流程来构建DOM:字节 → 字符 → 令牌 → 节点 → 对象模型。

以下面这段代码为例:

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
    <title>Critical Path</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
  </body>
</html>

浏览器接收到HTML请求的返回结果,根据预定的流程解析HTML,文档中的“开标签”,比如<html><head>等会转换成一个令牌(Token),然后令牌转换成节点对象(Node)。

这个令牌解析并转换为节点对象的过程,也是每个节点建立关系(树形结构)的过程。例如:head的令牌出现在html令牌之后,但其闭标签出现在html闭标签之前,这就意味着headhtml的子节点,以此类推,建立节点的父子关系。

这个过程在浏览器中,叫做“Parse HTML”。

CSS 对象模型 (CSSOM)

当DOM捕获了页面的内容,我们还需要知道页面如何展示这些内容,所以需要构建CSS 对象模型(CSSOM)。

浏览器解析DOM,遇到了link标签,发现它引用了一个外部样式资源:style.css,于是浏览器会向外部请求样式资源,然后进行后续的DOM构建工作。

CSS 被视为阻塞渲染的资源,这意味着浏览器将不会渲染任何已处理的内容,直至 CSSOM 构建完毕。

CSSOM有着一个和DOM构建相似的流程:字节 → 字符 → 令牌 → 节点 → CSS对象模型。

以下面的CSS样式为例,它会根据具体解析规则,将CSS文档转换成下面的树形结构:

body { font-size: 16px }
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }

这种树形结构让CSS有层级继承关系,子节点会继承父节点的样式。

前面谈到CSS会阻塞浏览器的渲染过程,因为渲染树的构建同时需要DOM和CSSOM,所以当浏览器请求的style.css返回之后,浏览器会开始解析样式表,并重新计算样式(Recalculate Style),将CSS转换成CSSOM,然后进行后续的操作。

值得注意的是,CSSOM运算是一个非常复杂的过程,性能消耗会比较大,所以你会常常听到“老人们”说写样式“尽量使用classid,保证层级扁平,减少过度层叠”,而且越是通用的CSS样式,执行速度越快,越是具体(选择器)的CSS样式,则执行速度越慢。

DOM + CSSOM = 渲染树

渲染树和DOM树不同,它只会捕获一些页面上可见的元素,比如,Headerdisplay:none的元素不会放在渲染树中。

渲染树的构建会从DOM的根节点开始遍历,对于不可见节点会忽略,然后在CSSOM中找到每个对应节点的样式规则并应用,最后输出的渲染树会包含所有的可见内容和样式信息,如下图:

布局和绘制

有了渲染树,浏览器会进入布局和绘制阶段。

布局就是弄清每个对象在页面视窗(Viewport)上的确切大小和位置,它的输出是一个“盒模型”,里面准确的捕获每一个元素在页面视窗中的位置和尺寸。

在布局工作完成之后,浏览器会开始绘制,将渲染树转换成屏幕上的像素,这样,我们就能在浏览器中看到页面的内容。

短暂回顾一下“关键渲染路径”的步骤

  1. 处理 HTML 标记并构建 DOM 树。
  2. 处理 CSS 标记并构建 CSSOM 树。
  3. 将 DOM 与 CSSOM 合并成一个渲染树。
  4. 根据渲染树来布局。
  5. 将各个节点绘制到屏幕上。

当DOM或者CSSOM发生变化的时候,浏览器就需要再次执行一次上面的步骤。

JavaScript

到目前为止,我们还没涉及到JavaScript,但它在整个关键渲染路径中扮演着非常重要的角色,就如全景图中画的那样,我们从一段简单的代码开始:

<body>
   <p>Hello <span>web performance</span> students!</p>
   <script>
     var span = document.getElementsByTagName('span')[0];
     span.textContent = 'javascript';
   </script>
</body>

一个大家都知道的重要事实是:脚本在文档的何处插入,就在何处执行。

当HTML解析过程中遇到一个script标记时,它会暂停DOM构建,将控制权移交给JavaScript引擎,等JavaScript引擎运行完毕,浏览器再从中断的地方恢复DOM构建。也就是说,执行内联的JavaScript会阻塞页面的首次渲染。

现在我们假设,这段JavaScript是外部资源。

<body>
   <p>Hello <span>web performance</span> students!</p>
   <script src="write.js"></script>
</body>

则浏览器的渲染会阻塞直到write.js的请求返回后,并执行JavaScript后,继续。

需要注意的是,在网页中引入JavaScript脚本有一个微妙事实,就是JavaScript不仅可以读取和修改DOM属性,还可以读取和修改CSSOM属性。

前面我们提到CSS是阻塞渲染的资源,当它和JavaScript一起出现在页面上时,会发生这样的事情:

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
    <title>Critical Path: Script</title>
  </head>
  <body>
    <p>Hello <script>document.write('web performance')</script> students!</p>
  </body>
</html>

在浏览器解析HTML构建DOM过程中,发现了link标签,于是发出请求获取style.css,然后继续构建DOM,此时,它发现script标签,由于JavaScript可能会访问样式属性,所以它会阻止JavaScript的执行直到styles.css返回并完成CSSOM构建,然后执行这一段JavaScript代码,再继续后面DOM的构建和相关渲染操作。

于是styles.css的请求不仅阻塞后面的渲染,还阻塞了DOM的构建。

如果将这段JavaScript作为外部资源,就是一个比较典型的页面结构:

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
    <title>Critical Path Render</title>
  </head>
  <body>
    <p>Hello <span>web performance</span></p>
    <script src="app.js"></script>
  </body>
</html>

JavaScript和CSS资源请求是并行的,但仍然需要等到CSSOM构建完成之后,JavaScript才可以执行,然后在进行后面的渲染工作。于是,当 DOM、CSSOM 和 JavaScript 执行之间有大量的依赖关系时,就很可能导致浏览器在处理及渲染网页时出现延迟。

优化策略

我们花了大量的篇幅来理解浏览器的渲染过程,理解DOM,CSSOM,渲染树,浏览器绘制,分析HTML,CSS和JS在渲染过程中的关系,我相信你已然受益匪浅,现在,我们来运用这些知识加速你的网站。

第一步,分析你的网站渲染状况

我们以Google为例,通过Chrome的Performance工具查看页面渲染情况,如下图,你应该可以清晰的看到图中有四条竖线,他们分别是什么含义呢?

(Google主页的性能分析情况)

  1. 绿色竖线,代表First Paint,即浏览器开始进行像素的绘制
  2. 黄色竖线,代表First Meaningful Paint(首次有效绘制)用户可以开始看到部分内容,但绘制仍在继续
  3. 蓝色竖线,代表大家比较熟悉的DOMContentLoaded
  4. 红色竖线,代表load,页面加载完成

优秀的网站都能够把“首次有效渲染”做到1秒之内完成,这样能够让用户更快的看到所请求的页面得到响应。如果你的网站“首次有效渲染”超过1秒,那么就非常有必要重新分析一下网站的关键渲染路径是否合理。

第二步,分析关键渲染路径

在关键渲染路径中,我们通常要关注三个点:

  1. 页面首次渲染需要的关键资源数量
  2. 关键资源的大小
  3. 关键渲染路径的往返次数(Roundtrip)

我们的策略也非常简单,就是减少关键资源数量,降低资源大小,减少关键路径的往返次数。

关键渲染的资源一般是阻止屏幕首次渲染HTML,CSS和JavaScript,所以最重要也是最难的部分的是你需要根据自己网站的实际情况分析,哪些是页面绘制的所必须的,哪些是无关的。

第三步,根据分析采取优化手段

1、减少关键资源的大小

我们首先从最简单也是最直接的减少关键资源的大小开始:

对于所有的资源(HTML,JavaScript,CSS,Image等),你都应该用上三大绝招:Minify,Compression和Cache,这里不过多的赘述里面的细节。

这一点对于HTML来说,非常关键,HTML作为渲染的关键资源,消除或者延迟加载肯定不太可能(这里指的是非局部渲染的关键HTML),能够做到是消除无用代码(比如:注释)和最小化代码(Minify)以及动态局部渲染等。

(Google对页面的HTML进行了压缩)

2、延迟JavaScript非阻塞资源加载

JavaScript和CSS都是阻塞渲染的资源,对于已经鉴别出的对于首次渲染没有起到关键作用的代码,我们首先想到的是要延迟它的加载,让它脱离关键渲染路径。

首先,对于阻塞渲染的JavaScript,应该将它放置在页面body的底部,为什么呢?

JavaScript可以查询和操作DOM和CSSOM,正如前面介绍的,HTML解析过程中构建DOM,当遇到JavaScript就停止DOM构建执行JavaScript,如果被执行的JavaScript是放置在head附近,那么很可能要被操作或者查询的DOM还没有构建到DOM当中。

而对于,非阻塞渲染的JavaScript,我们应该采用异步的方式加载,如下:

  <script src="script.js"></script>
  <script async src="script.js"></script>
  <script defer src="myscript.js"></script>
</body>
</html>

方式一:即阻塞的JavaScript,HTML解析过程中遇到script标签,发出网络请求获取script.js,在网络请求返回后,解析并执行script.js,然后浏览器继续HTML解析。

方式二:async,完全的异步操作,HTML解析遇到该标签后,发出网络请求,但不阻止HTML解析和其后面的渲染操作,当JavaScript请求返回后立刻执行,且不等待HTML解析或其他操作的完成。所以,如果脚本中有DOM操作,就并不适合。比较适合的场景是Google Analytics。

方式三:defer,HTML的解析和对JavaScript资源的网络请求是并行的,但它会等待HTML解析完成之后,才执行脚本。

(图片参考自:Asynchronous and deferred JavaScript execution explained « Peter Beverloo)

不过,async和defer,他们对浏览器的兼容性有一定的要求,但仍然应该使用它们,同时可以采用退而求其次的延迟代码执行的方法(比如:on DOMContentLoad后),特别是与首次渲染无关的计算逻辑和功能。

3、尽早和按需的加载CSS

你可能在思考,有没有异步加载CSS的需求?我认为不应该有,页面应该只引用与该页面相关的样式文件。(只不过很多时候,我们将所有的CSS都打包在了一个压缩的CSS文件中了。)目前,已经有许多帮助你分析关键渲染路径上的所需要的CSS的工具:grunt-criticalcsscriticalcriticalCSS,在线CRPCSS工具。

前面已经提到,CSS是阻塞渲染的资源,在CSSOM完全解析完成之前,浏览器不可能开始屏幕的绘画。

所以,我们应该尽早的开始对样式资源的请求,将它尽早、尽快地下载到客户端,这样解释了为什么我们看到样式资源的link标签一般都放在head表中:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Sample Site</title>
  <link href="style.css" rel="stylesheet">
</head>

CSSOM的运算是一个非常复杂和相对耗时的过程,但它也有一个特点,就是可能只有在特定的情况下才会起作用,比如:响应式设计的页面。

对于响应式页面,我们可以考虑将不同媒体上的样式分离,在<link>中使用媒体查询,浏览器仍然会下载对应的资源,但是可以避免不必要的CSSOM解析导致对渲染的阻塞。

<link href="style.css" rel="stylesheet" media="all">
<link href="portrait.css" rel="stylesheet" media="orientation:portrait">
<link href="print.css" rel="stylesheet" media="print">

同时,我们还应该避免在首次渲染的CSS样式中使用@import指令,因为它只有在收到并解析完带有@import规则的CSS资源之后,才会发现导入的 CSS 资源,这个时候就会重新请求,从而增加了关键渲染路径的往返次数。

4、内联CSS来提高渲染性能

到目前为止,我们已经做到了识别关键渲染资源,将非关键资源延迟加载或者不加载。那么,减少关键路径的往返次数是什么意思?其实就是减少关键渲染资源从服务器端到客户端的往返次数。比如,外链的JS和CSS文件以前CSS的@import,在页面渲染的过程中,都会重新去服务器端请求。这其实,和我们常说的减少http请求量(合并http请求)类似,但是我么从渲染路径的角度来理解这样一种性能的消耗。

根据这样的逻辑,我们很容易就想到可以将渲染必备CSS内联到HTML中,来减少渲染路径的往返次数。

实际上不少的优秀网站都采用了在head内联样式的做法:Google,百度,淘宝,京东。

(百度和Google将样式inline在head中)

关于内联样式还有更进一步的做法,在文章的一开始就提到,优化关键渲染路径就是要优先显示和用户先关内容。

所以,我们可以考虑仅仅将当前屏幕展示的内容(above-the-fold,一屏)所需的CSS内联到HTML的head中,然后采用异步的方式加载整个页面所需要的完整CSS,以便用户能够更快的看到首屏出现的内容。(inlining-critical-css-for-better-web-performance

5、一个神奇的数字14kb

在最开始我们提到,要减小关键资源的大小,那么多小比较合适呢?(废话,当然是越小越好)。

其实,有一个神奇的数字14kb,它是怎么来?

HTTP的传输层协议是TCP,TCP协议有一个慢启动的过程,即它在第一次传递数据时,只能同时传递14kb的数据块,所以当数据超多14kb时,TCP协议传递数据实际是多次的往返(roundtrip)。如果能够将渲染所需要的资源控制在14kb之内,那么就能TCP协议启动时,一次完成数据的传递。

其他Web资源和关键渲染路径的关系

你一定会思考,除了HTML,JavaScript和CSS,Web页面还包含许多其他的资源,比如:图片,网络字体(Icon Font),他们和关键渲染路径的关系是什么?

大家对图片加载感受都应该大致一样,它会在页面加载过程中或完成后,逐步显示,也就是说它不是阻塞渲染的资源,它的痛点主要在于质量和资源大小的权衡,以及请求数量带来的性能消耗(雪碧图)。

网络字体,在网络加载比较慢的情况下,用户可能会感受到字体或者图形的变化(Icon Font)。其实,浏览器在渲染树构建完成之后,会指示需要哪些字体在网页上渲染指定文本,然后分派字体请求,浏览器执行布局并将内容绘制到屏幕上,如果字体尚不可用,浏览器可能不会渲染任何文本像素,待字体可用之后,再绘制文本像素,当然,不同浏览器之间实际行为有所差异,这里不在赘述,请参考文章尾部的资料链接。

总结

优化关键渲染路径的最终目的是优先显示和用户操作相关的内容,减少低优先级资源对浏览器渲染的阻塞,从而尽早显示用户真正关心的关键内容。页面性能就是用户体验的一个重要维度,尝试用感性的思维去思考理性的代码,也许真的能受益不少。


参考资料:

  1. Google关键渲染路径
  2. 《Web性能即用户体验》
  3. https://peter.sh/experiments/asynchronous-and-deferred-javascript-execution-explained/

更多精彩洞见,请关注微信公众号:思特沃克

Share

前端不止:Web内容的无障碍性

网民统计报告

根据2017年7月份发布的第40次中国互联网络发展状况统计报告:

截至 2017 年 6 月,中国网民规模达 7.51 亿,中国手机网民规模达 7.24 亿, 中国网民中农村网民占比 26.7%,规模为 2.01 亿。

截至 2017 年 6 月,中国网民通过台式电脑和笔记本电脑接入互联网的比例分别为 55.0% 和 36.5%;手机上网使用率为 96.3%,平板电脑上网使用率为 28.7%;电视上网使用率为 26.7%。

截至 2017 年 6 月,我国非网民规模为 6.32 亿。上网技能缺失以及文化水平限制仍是阻碍非网民上网的重要原因。调查显示,因不懂电脑 / 网络,不懂拼音等知识水平限制而不上网的比例分别为 52.6% 和 26.9%;由于不需要 / 不感兴趣而不上网的比例为 11.2%;受没有电脑,当地无法连接互联网等上网设施限制而无法上网的比例分别为 9.3% 和 6.2%。

提升非网民上网技能,降低上网成本以及提升非网民对互联网需求是带动非网民上网的主要因素。

信息无障碍

今天,我想讨论一个关键的词语——信息无障碍。

信息无障碍,英文词语来自“Accessibility”,是指任何人(注意是任何人,无论是健全人还是残疾人,无论是年轻人还是老年人等等)在任何情况下都能平等地、方便地、无障碍地获取信息、利用信息。

首先,我们要对Accessibility(无障碍)的一些错误认识进行一些纠正:这样一个词,很多人自然地跟残障人士联系起来,因为经常可以看到无障碍坡道、无障碍洗手间这样的词语。

信息无障碍更多强调的是对所有人都平等,方便的获取信息。比如:键盘上的F和J的凸起基准键。它的作用就是方便任何人可以精准的找到键盘字母的位置,从而可以在不看键盘的情况下,快速的打字,俗称“盲打”,大家都知道它的含义,没有人会把这个词理解为“盲人打字”吧。

(键盘基准键)

我国非网民规模为 6.32 亿,由于个人主观意愿,比如:不需要 / 不感兴趣而不上网的比例仅仅占11.2%。

那么,剩下的88.8%,也就是大约5.612亿人,是有上网需求的,但因为其他各种原因而不能上网。信息的公平使用和访问,是所有人的基本权利,如果你不能像身边其它人一样公平的获取信息,那意味着你不能公平接受教育、就业、独立生活等等。

我为什么会注意

我是谁?我为什么关心这些?这不是个哲学问题。每个人身上都有很多的标签,但在这里,我的标签是一个普通的Web开发工程师,一个新科技产物的使用者,一个信息的生产者和使用者,一个能“无障碍”获取信息的个体。而我的生活和我的工作让我开始关注“无障碍”这样一个词。

在互联网的大环境下,所有人的生活都方便了不少,我们可以远程办公,远程接受教育,网上购物,现在甚至连买菜、买水果都不需要出门,就这段时间,我妈有时都会直接在网上买菜和水果。

在我们享受这种生活便利的同时,我们也常常听到一些声音,比如:“这些都是年轻人的东西”,“我家小孩手机app玩的可溜了”。

前几天,我去办理港澳通行证,其实已经比我五年前办护照时方便很多,然而,在市政府政务中心的自动办理出境机器旁边,我会听到有几位年长的人说“这个机器不会用,怎么办?”,另一个人说,“没事,有个警察在旁边帮你操作”。这就意味着,如果旁边没有那个警察帮着操作,那么就不方便使用了,至少不是对所有人都方便。

科技的便利性看来还不是对所有人都便利,其实它还是需要一定的学习成本。

因为在外企的缘故,我有幸参加过一些海外的项目,在需求的实现过程中,客户对应用的无障碍性都会有一定的要求,于是我从中学习到了不少的相关知识。当然我也去过一些其他国家,跟不同国家的同事讨论过这方面的问题,也听他们介绍了一些做的不错的项目。所以我来举个例子:

比如,澳大利亚政府的“网络可访问性国内过渡战略”(NTS)规定,所有政府网站及其内容必须在 2012 年 12 月 31 日以前达到 WCAG 2.0 的 A 级合规要求,并在 2014 年 12 月 31 日之前达到 AA 级合规要求。

WCAG是万维网联盟(W3C)发布的一套名为“Web Content Accessibility Guidelines (WCAG) ”的网络内容可访问性指引。该指引目前是网络可访问性的国际标准。合规等级分为三级(A、AA 和 AAA)。

相关达到 WCAG 2.0 的 A 级合规要求的网站,例如:澳大利亚官方政府网站澳大利亚政府留学网站等,体验一下他们在Web内容无障碍性的一些实践,比如:只通过tab和enter来导航到不同的网站区域。

如果反观一下国内的一些相关网站,无障碍访问的体验感一下就降低了不少。

是能力问题还是被忽略了?

有时候,我在想这样一个问题,到底是我们的能力问题,还是问题被忽略了,当然大部分人的答案会是后者。

但我有时候会认为是前者,因为我们忽视了这个问题,所以导致其实我们也缺乏这方面的能力,无论是开发还是设计。

“目前我国99%的网站,由于没有实现无障碍,盲人难以正常浏览访问网站。”省盲协主席、中山大学工学院教授富明慧于2013年说的。富明慧本身就是一名盲人,他失明后发明了电脑盲文输入法。他说,加快网站无障碍改造,政府部门网站应该先行一步。

如果你在一个互联网公司工作,你大可在周边一问,比如:你听说过Web Accessibility?或者你知道怎么做才是最佳的方式吗?我们的产品里面有做这个?会作为代码和质量审核的一部分吗?

从哪里开始

连续追问这几个问题,的确会让不少人哑口无言,包括我自己在内。首先,我要承认这个不是一件容易的事情,否则不会有今天这样的一个讨论和思考。

我认为无障碍性的实现,应该是一个端到端的过程,不是设计师(UX/XD),不是开发(Dev),不是质量分析师(QA)某个人的责任,而是整个产品研发过程中所有人的责任,也许从产品构思的那天的就要开始考虑(比如:用户群体)。

其实这是个如何去做的话题会比较大,但是我想在这里举几个简单例子,让大家产生一些共鸣,也许从明天开始,在写代码和设计的过程中,你就会注意这些小的细节。

例子:通过Tab切换聚焦的的顺序

由于行动障碍而无法使用鼠标的人,会使用键盘进行页面的浏览。而页面上DOM的顺序会决定Tab切换时聚焦(focus)的顺序,我们知道CSS可以改变DOM在页面上的显示位置逻辑,但是DOM本身的顺序没有改变,这就容易导致Tab切换时给键盘使用者带来困惑。比如:

<div style="width:200px">
  <button style="float: right">右边菜单按钮</button>
  <button>左边</button>
  <button>中间</button>
</div>

当使用tab进行切换时,并不是最先聚焦到“左边”这个按钮,而是右边菜单,这就和页面上看到的逻辑产生了冲突。

例子:通过tabindex聚焦弹出框

你有没有注意到Bootstrap的模态框是这么写的:

<button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
  弹出
</button>
<div class="modal fade" id="myModal" tabindex="-1" ...其他属性省略>...</div>

当tabindex=-1时,表示当前元素必须要被聚焦,如果是元素弹出框,就需要使用tabindex,这样才能保证使用键盘的用户可以理解通过tab切换到模态框中的各个元素。如果你没有使用像Bootstrap这样的框架,那么当用其他前端框架实现自定义的模态框时,请务必考虑这个细节。

例子:请自定义元素的outline样式

你知道CSS中{ outline:none }对于网站的无障碍访问性是一个致命的做法吗?为什么我们还会这么做呢?因为元素在被聚焦时,会有一个蓝色的轮廓,而出于视觉效果的考虑,被认为是“不好看的”,所以被去掉了。

于是,当通过tab进行页面浏览时,很难立刻知道光标当前聚焦在哪一个元素(链接或者输入框)。这种情况,我们需要为它的聚焦效果提供一个另外的设计,以便同时保证它的功能性和视觉效果。更多关于{ outline:none }的内容,大家可以参考:http://www.outlinenone.com/

例子:设计页面时,请满足文字上的前后景颜色的对比度

(文字和背景的颜色对比)

WCAG 2.0 的1.4.3条对页面上文字的对比度有一个最低的要求4.5 : 1,目的很明显是为了保证色盲/色弱人群可以无障碍的访问网站的内容。假如说你是产品经理,有一天设计师告诉你,这个设计可能导致10个用户里面有1个用户存在访问障碍,阅读困难,你能接受吗?我想谁都接受不了。

有什么工具可以帮助检测网站的无障碍性吗?

对于普通使用者,可以使用Chrome的审计功能和Accessibility Developer Tools(Chrome插件),它能帮助你自动的检测网页的的可访问性问题,以及帮助你提供相关的修正信息。

(Chrome的审计功能)

Accessibility Developer Tools(Chrome插件)

对于开发人员,可以做一些自动化的检测,比如:使用pa11y这样一个工具,它是基于HTML codeSinffer以及PhantomJS制作而成的网站内容A11y(Accessibility,无障碍性)自动化检查工具。pa11y出现在ThoughtWorks 2017年3月的技术雷达中,我的同事写过一篇详细的文章来介绍这个工具:《无障碍性测试工具 Pa11y》

当然,最重要和最有效的检验方式是用户测试,比如:假设你自己是一个纯键盘的网站浏览者,尝试一下用键盘浏览自己开发的网站,是否能够方便的导航到网页的各个部分,并进行无障碍的阅读和交互。

还有其他一些重要的关注点吗?

有的,比如:基本HTML的语义化,alternative text的使用,ARIA标签属性的使用,都可以帮助屏幕阅读器有效的告诉使用者当前的元素类型和作用。

不要小看这些细节

​不要小看这些细节或者说基础功能,它涵盖的人群非常大,根据国家统计局最新数据,在中国,单是65岁的老年人已经超过1.5亿人口。加上其它障碍人群,以及第二语言学习者,等环境障碍人群,粗粗一算,这么简单的特性就能方便好几亿的用户,为什么要省略呢?

我在写这篇文章的时候,也去查了不少的资料,我觉得知乎上有一个人说很好:对无障碍性一个最大的误区是,将信息无障碍,当做产品的情怀功能,而非基础功能或Bug去对待。


更多精彩洞见,请关注微信公众号:思特沃克

Share

前端不止:请告诉我,你要什么样的图标

有一个英语成语叫做一画胜千言(A picture is worth a thousand words),不知道大家有没有听过?它是指的是一张静态的图片就可表达一个复杂的概念或者与一个主题相关的图片有时比起详细的解释,能够更有效的描述有关主题。- “一画胜千言”维基百科

如果我们要用一句话来说明图标的作用,没有比这个成语更适合的词了。本篇文章,我们就来聊聊关于图标的一些事情。

一个图标的生命周期(工作流程)

关于图标的生命周期,在我个人所经历的开发项目中,有以下两种:

第一种方式:图标库(选择阶段) -> 图标使用(开发阶段)

第二种方式:图标设计(设计阶段) -> 图标导出(沟通阶段) -> 图标使用(开发阶段)

一般来说,小公司或者独立开发者会采用第一种工作流程。而大型组织或公司因为拥有更完善的团队和资源,一般会采取第二种方式,能够获得更多自主权和建立企业VI(Visual Identity,企业视觉识别)的能力。

但无论哪种方式,都包括两个角色:设计师和Web开发。只是在第一种工作方式中,设计师是不可见的。

图标的设计和使用

设计阶段通常是由不了解Web开发的设计师们来完成的,他们会根据产品的需要,绘出满足需求的图标,然后交给Web开发人员使用。

(ThoughtWorks官网“Contact with us”图标)

为什么要先介绍图标的使用,而一笔跳过导出过程呢?原因很简单,因为我们需要先知道服务的对象是谁,才知道如何正确的为它服务。

常见的三种图标的使用方式

1.使用图片

直接将设计师画好的图标,以PNG格式的图片一个个分离导出,这是最直观的图标打包方式。

(FlatIcon图标)

它的优点是:

  • 能够使用彩色的图标
  • 能够支持大部分浏览器

缺点是:

  • 图标大小是固定的(不能根据场景自由缩放)
  • Retina屏幕需要两倍图

开发人员拿到这样的图标,通常需要先将其合成为一张图片,以方便制作雪碧图,这个过程可以由开发人员自己完成,也可以由设计师来做(设计师可以根据源文件中心导出一张包含所有图标的PNG文件制作)。

制作雪碧图的工具有很多,我比较常用的在线雪碧图工具是:Sprite Cow,或者是NodeJS平台下的构建工具插件,如:webpack-spritesmith

2.直接使用svg

使用SVG(可缩放矢量图形),W3C标准是最被看好的Web端图形解决方案。它能提供如裁剪路径、Alpha通道、滤镜效果等复杂渲染能力,具备传统图片没有的矢量功能,还可以被记事本等阅读器、搜索引擎访问。

设计师可以轻松的在设计绘图软件(AI,PS)的帮助下导出SVG格式的图标/图片。

但目前,国内svg还没有被非常广泛的使用,原因在于兼容性不足,不能够很好的兼容旧的IE版本和一些Android原生浏览器。

(Can I use svg?)

上图为百度对2017年前三个月的浏览器使用进行的统计,目前国内还有超过20%的用户仍在使用IE8,9甚至是IE7。

3.IconFont

IconFont是目前最为流行的图标解决方案,顾名思义,它就是字体文件,你可以用任何一个字体编辑工具打开它,如果你打开某一个查看,就会发现它就是一些路径,这些路径可以用AI,PS,Sketch等软件来绘制。

IconFont的优点在于能够用CSS控制样式,无限缩放而不失真,支持IE7+,兼顾屏幕阅读器,不过缺点是不能支持彩色图标(拥有多种颜色的图标)。获得IconFont的方式也很简单,设计师将图标通过AI/PS转成SVG文件,然后由开发人员通过工具(在线或者本地)转换为IconFont,比如:国外的icomoon.io,国内的iconfont.cn,开源构建工具插件有gulp-iconfont等等。

产生适合Web开发的图标

“产生适合Web开发的图标”是我们本篇文章要关注的重点。

1.使用图片的方式

如果开发人员直接使用图片,则相对简单,设计师只需要针对普通屏幕和Retina屏幕准备两套图(单倍图和两倍图)。

以国内某著名的中文小说阅读网站为例,会针对不同的设备使用不同倍数的logo图片,以保证在如Retina屏幕下的清晰度。

.logo-wrap .logo a {
    display: block;
    width: 219px;
    height: 52px;
    background: url(/qd/images/logo.dbed5.png) no-repeat;
}

@media not all, not all, (-webkit-min-device-pixel-ratio: 1.3), not all, (min-resolution: 1.3dppx) {  
    .logo-wrap .logo a {
        background: url(/qd/images/logo3x.fd980.png) no-repeat;
        background-repeat: no-repeat;background-size: 217px;
    }
}
)

2.使用SVG

关于转换成SVG,这里就要引荐一下Sara Soueidan在Generate London 2015 Conference上的演讲《Sara Soueidan: SVG for Web Designers (and Developers)》(YouTube视频需要翻墙),如果不方便,Sara Soueidan有一篇博客《Tips for Creating and Exporting Better SVGs for the Web》更详细的讲解了关于SVG导出的内容,当然,还有一篇国内的翻译文章《创建和导出SVG的技巧》,最后再推荐一篇Adobe工程师michael chaize写的关于AI导出SVG的文章《Export SVG for the web with Illustrator CC》

在上述资料中,我觉得看视频更直观,顺便领略一下这位优秀的阿拉伯女性前端开发工程师(兼自由作家和演讲人)的风采。

博客和视频中谈到了多个点导出SVG需要注意的地方,由于篇幅限制,这里简单描述三个tips:

1. 选择适合绘画的画板

你有在网页上嵌入过SVG吗,给它指定一个高度和宽度,然后发现它其实比你指定的尺寸要小?开发人员常常会遇到这样的问题。

一般来说,这是因为SVG视窗中有一定大小的白色空白空间。视窗是按照样式表的指定尺寸显示的,但是它里面有额外的空白——在图形周围——使得你的图片看起来好像“缩水”了,因为这块空白在视窗里面是占空间的。为了避免这种情况,你需要确保你的画板是刚刚好能容纳里面的图像的,不要大太多。

画板的尺寸就是导出的SVG视窗的尺寸,所有画板上的空白最终都会变成视窗中的白色空白。

对于没有AI工具的开发,可以在下面的SVGO优化选项中选择“Prefer viewBox to width/height”。

2. 选择合适的导出选项

上图展示的选项是推荐的生成适合Web使用的SVG。如果你不想使用Web字体,可以选择把文本转换成轮廓。

如果SVG中包含大量的文字,这个选项output fewer tspan elements可以在很大程度上降低svg的大小。

3. 优化SVG

通常是建议在把SVG从图形编辑器中导出后,再用单独的优化工具来进行优化。比如:删除无用Comments和Metadata,简化代码,简化单个路径等。推荐的第三方工具:NodeJS工具svgomg,AI插件SVG-NOW,Sketch插件Svgo-compressor等,请参考Sara Soueidan的文章《Useful SVGO[ptimization] Tools》

3. IconFont

前面提到IconFont一般是由SVG通过工具转换而来,而如果开发最终需要使用IconFont来展示图标,那么对于导出的SVG有一些特殊要求。我在本文的前面一小节,已经介绍了几款IconFont的转换工具,每一款工具都有详细的文档来说明SVG绘制的规则,尽管不尽相同,但有一些基本原则是一致的:

  1. 将文字转换为路径
  2. 不可以使用图片(字体只是路径)
  3. 修剪画板(trimming to art boundaries)(前面已经介绍过)
  4. 将描边转化为闭合图形
  5. 简化无用的节点
  6. ……

更多关于IconFont的绘画规则,请参考:Iconfont.cn文档Icomoon文档gulp-iconfont文档fontello文档。

及时和频繁的沟通

Sara Soueidan说过一句话:“设计师和开发者应该成为好朋友”。

我们今天的话题正好涉及到这两个角色,也许你会觉得它们俩似乎有点“八竿子打不着”,但其实不是。请看下面这张图,敏捷的开发过程中不同角色共享职责,那么设计师和开发也不例外。

(敏捷开发中不同角色共享职责)

在ThoughtWorks工作,你会发现不少设计师懂HTML,CSS,甚至如何用Chrome查看元素,同时有不少开发对设计也颇有研究和兴趣。而我们的设计师和开发人员会坐在同一张桌子上一起完成工作,以保证及时和频繁的需求沟通和合作。

至于“设计师和开发者应该成为好朋友”,作为一名Dev,我就跟好多设计师都是朋友(至少我是这么认为的)。

而为了更好的做到沟通顺畅和职责共享,还出现了一种新(相对较新)的角色UI Dev,如下图。不过,关于这个角色的定义众说纷纭,我们就不在这里细聊了。

(UI Developer(参考自Stack Overflow答案))

结尾

在本篇文章中,我们谈了图标的三种使用方式:图片、SVG、IconFont,而它们也只是图标这个话题的冰山一角。虽然篇幅很短,但尤其重要的是,保证团队中设计师和开发人员便捷的协作工作,一起找到满足团队需求的解决方案,才是保证图标质量的关键。


更多精彩洞见,请关注微信公众号:思特沃克

Share

前端不止:Retina屏幕下两倍图

所见不一定即所得

眼睛是心灵的窗户,也是蒙蔽你的一种途径。

假设,我给你一张图片,你觉得肉眼可以观察到全部的细节吗?

屏幕上一张清晰的图片

肉眼在屏幕上看到图片的清晰度由三个因素决定,一是图片像素本身是否精细,二是屏幕分辨率,三是屏幕大小。

我们来逐步分析它们之间的关系:

屏幕分辨率

屏幕分辨率也就是设备分辨率,设备像素,它是物理的像素,比如,新的iPhone7,屏幕分辨率是1334 x 750像素分辨率,326 ppi。

图像大小

如果你学过《数字图像处理》这门课,那你对下面的解释就是非常熟悉了。

位图是由像素(Pixel)组成的,像素是位图最小的信息单元,存储在图像栅格中。每个像素都具有特定的位置和颜色值。按从左到右、从上到下的顺序来记录图像中每一个像素的信息,如:像素在屏幕上的位置、像素的颜色等。位图图像质量是由单位长度内像素的多少来决定的。单位长度内像素越多,分辨率越高,图像的效果越好。

假设,以上这个logo的图像大小是1334 x 750像素和iPhone7屏幕分辨率一样,那么,一位图像素对应的就是一个设备像素,这就是会是一个完全保真的显示。因为一个位置像素不能进一步分裂,我想这一点应该大家非常容易理解,也就是一个萝卜一个坑。

屏幕分辨率和屏幕尺寸

相信大部分人对上面这个设置肯定特别熟悉,有些人可能对XP,甚至98系统的样式更熟悉(一不小心暴露了年龄),在Windows系统下,提高屏幕分辨率一般都需要提高屏幕尺寸。

因为在固定屏幕的情况下,提高屏幕分辨率(如上图),图像和文字显示目标会相应缩小,原因是系统并不会自动根据屏幕尺寸和分辨率关系相应的调整文字和图标的大小,这是Windows系统自身的行为。

我相信,如果家里有年长的人使用电脑,肯定屏幕分辨率调的很低,因为这样文字和图标才会比较大,我家06年买的台式机就是这样。

也因此,我们很容易有一个错觉,那就是屏幕越大,分辨率就能越大(在单位面积内像素数量固定的情况下,尺寸越大,单个屏幕拥有的像素就越多,分辨率自然就越大)。

直到,苹果Retina屏幕的出现,原来小屏幕也可以拥有大分辨率。

PPI的概念

PPI,像素密度,即每英寸所拥有的像素数目(比如:上面iPhone 7的PPI是326),PPI数值越高,代表显示屏能够以越高的密度显示图像,画面的细节就会越丰富。

以Retina屏幕为例,它并不是像普通显示器那样通过增大尺寸来增加分辨率,而是靠提升屏幕单位面积内的像素数量,即像素密度来提升分辨率,这样就有了高像素密度屏幕。

根据上面的分析,分辨率提升了,那么图标和文字尺寸就会变小,但是Mac的操作系统不同,它自动采取相应的模式(如Mac下的HiDPI)进行适配,将缩小后的字体(苹果一直采用矢量字体)和图标重新放大,这样苹果用了更多的像素数来显示同样的内容,所以显示尺寸仍然不变。

苹果将“高像素密度屏幕”的概念营销出一个专业的术语“Retina”,将其称为双密度显示,声称人类的肉眼将无法区分单个像素。

当一个显示屏像素密度超过300ppi时,人眼就无法区分出单独的像素。这也是讲:显示设备清晰度已达到人视网膜可分辨像素的极限。因此,行动电话显示器的像素密度达到或高于300ppi就不会再出现颗粒感,而手持平板类电器显示器的像素密度达到或高于260ppi就不会再出现颗粒感,苹果电脑Mac的Retina显示器像素密度只要超过200ppi就无法区分出单独的像素。

好,说了这么多,都是谈屏幕的问题,貌似和前端开发没有什么关系,我又不是要买新手机(呵呵),那么现在,我们现在来谈谈前端的问题。

Web中的像素(CSS像素)

CSS像素是一个抽象概念,设备无关像素,简称-“DIPS”,device-independent像素,主要使用在浏览器上,用来精确的度量(确定)Web页面上的内容。

在标准情况下一个CSS像素对应一个设备像素。

.box {
  width: 200px;
  height: 300px;
  font-size: 12px;
}

上面的代码,将会在显示屏设备上绘制一个200×300像素的盒子,在标准屏幕下,它占据的就是200×300设备像素。但是在Retina屏幕下,相同的div却使用了400×600设备像素,保持相同的物理尺寸显示,导致每个像素点实际上有4倍的普通像素点。

对于图片来说也是如此:

这个时候,屏幕会怎么处理呢?其实,有点类似图像软件的放大图片功能,采用自有的算法(图像处理算法)计算放大方式。只不过,这里是苹果Retina屏幕的计算方法,一个CSS像素点实际分成了四个,造成颜色肯定会存在偏差(非全保真的显示),于是,我们看上去就变得模糊了(特别是图片,非常的明显)。

开发当中遇到这样的事情,我们应该怎么处理呢?这时,我们需要引出devicePixelRatio的概念。

devicePixelRatio设备像素比

window.devicePixelRatio是设备上物理像素和设备独立像素(device-independent pixels (dips))的比例。

公式表示就是:window.devicePixelRatio = 物理像素 / dips

  • 普通密度桌面显示屏的devicePixelRatio=1
  • 高密度桌面显示屏(Mac Retina)的devicePixelRatio=2
  • 主流手机显示屏的devicePixelRatio=2或3

举例说明,一张100×100的图片,通过CSS设置它{ width:100px; height:100px }。在普通密度桌面显示屏的电脑上打开,没有什么问题,但假设在手机/或者Retina屏幕的Mac,按照逻辑分辨率来渲染,他们的devicePixelRatio=2,那么就相当于拿4个物理像素来描绘1个电子像素。这等于拿一个2倍的放大镜去看图片,图片可能因此变得模糊。

代码如何解决呢?

原理我们明白了,那么从代码层面,我们应该如何实现呢?

一个常见的做法是把图片换成200×200的,CSS宽高不变,仍然是{ width:100px; height:100px },这样,CSS宽高换算成物理像素是200×200,图片也是200×200,就不会变糊了。可以采用媒体查询和JS操作的方式

CSS Media Queries

#element { background-image: url('hires.png'); }

@media only screen and (min-device-pixel-ratio: 2) {
    #element { background-image: url('hires@2x.png'); }
}

@media only screen and (min-device-pixel-ratio: 3) {
    #element { background-image: url('hires@3x.png'); }
}

JS查询

retinajs库

是不是适配Retina屏幕所有的图片都需要切换呢?

不是,一般情况下,不需要针对网站上的所有图片都提供两个版本(非Retina屏幕和Retina屏幕),大部分图片缩放并不会太多的影响用户的体验。

常常需要被处理的图片有:网站的logo、彩色图片图标,因为他们的图像大小都偏小,在Retina上物理像素放两倍显示就会出现模糊情况,这个时候,你就需要通过媒体查询或者JS操作来替换图片。

最后

眼睛是心灵的窗户,也是蒙蔽你的一种途径,带上知识的眼镜,将世界看个清楚。


参考资料:

  1. http://www.w3cplus.com/css/towards-retina-web.html
  2. http://www.jianshu.com/p/bb76c606f0b4
  3. https://developer.mozilla.org/zh-CN/docs/Mobile/Viewport_meta_tag
  4. http://caniuse.com/#search=devicePixelRatio
  5. https://www.web-tinker.com/article/20590.html

更多精彩洞见,请关注微信公众号:思特沃克

Share

你听说过“风格指南驱动开发”吗?

从“敏捷”下手

“今天,客户的UX又给我邮件了一版新的设计(PDF文件),改动不大,无非就是这个高度再调高点、那个宽度再调小些、这里用粗体、那边用18px的字体,可以参考以前做的手风琴组件的body部分,还有就是,顺便把手机版的样式截个图发过来?”

我:“能告诉我宽度和高度的具体值吗?那个手风琴组件可以在哪个页面找到?”

另一个开发告诉我:”先凭感觉做,然后再找UX面对面的按照要求一个个过。“

我:”好,面对面谈,总比邮件来回要快些。“

UX答复我:”面对面谈可能没有时间,你能先做一个粗略的版本吗?我先看看,然后给你反馈。等你做完所有的部分,我们再约个时间一起过”

即便心里在暗骂(等我做完了,你又跟我说这个不对,那个不对?)嘴上还是说了,“可以。”

然后,我问QA:“有测试环境可以部署我的新代码吗?没有完全做完,但是要给UX看效果。”

QA说:“有,但是部署完估计要1个多小时。”

我看了下时间,再过一个小时,客户UX就下班了,要得到他/她的反馈,估计得明天了!

当我把这个故事讲给别人听的时候,一般会得到两个回复:

  1. 哎呀,跟我们一样,痛苦的很
  2. 你们怎么这么不敏捷?

我无法否认这两个说法,很痛苦,也确实不够敏捷。但为我们提供了一点点线索——敏捷。

1-agile

敏捷宣言中强调:个体和互动高于流程和工具,工作的软件高于详尽的文档。

上面的故事很明显并不满足敏捷的价值观,邮件和截图绝对不可能代表“个体和互动”,一个需要部署一个小时才能看到页面效果的应用也谈不上“可工作的软件”。

怎么破?引入“在线风格指南”

针对当前的痛点,想要破,需要做到至少下面三点:

  • 独立前端开发工作,让它与后端逻辑解耦(俗称“前后端分离”)
  • 建立“可工作的软件”来展示前端开发结果
  • 组件化的设计和开发流程

看到这三点,明白人可能会立刻联想到一个大家耳熟能详的前端开发框架:Bootstrap。没错,它作为一个优秀的前端开发框架,确实满足上面的要求,有许多不错的网站都将Bootstrap作为网站的前端骨架。

Bootstrap有两个特质非常吸引人,优秀的特性和组件和漂亮的开发文档

不过,今天我们不谈Bootstrap框架,我想来聊聊这个漂亮的开发文档,俗称“在线风格指南”。

相信大家对“风格指南”都不陌生,主要分两类:静态风格指南和动态风格指南。

静态风格指南也就是我们常见的静态设计文档,比如,由设计师提供的PSD/PDF等文件,文档中包含:调色板,字体,按钮,链接等等。

2-style-guide

(medialoot上的一个样例)

动态风格指南,也称为Living Style Guide(“活的”风格指南或者在线风格指南),它是一个包含风格指南的Web站点,就像Bootstrap开发文档一样。

3-living-style-guide

在这里,我们需要引入的是“在线风格指南”,而不是Bootstrap,这里的不同点在于:

  • 角色变化,我们从“风格指南”的使用者,变成了是它的拥有者、开发者和使用者。
  • 用户变化,它不再是开发文档,现在用户是UX、前端开发和BA(业务分析),在UX和BA的眼中看到的文档即最新实现结果,在前端开发眼中看到的代码即设计。
  • 侧重不同,不仅仅是基础组件,也具有更加偏业务的大型组件。

为什么还要组件化的设计和开发?

组件化的做法在当前的场景下,似乎有点顺其自然,特别是有Bootstrap作为前车之鉴。

我想大家都知道,前端开发其实有一个通病,即大量的JS、CSS和其他资源文件(字体文件、图标、图片),在没有很好的管理控制下,很容易导致资源的冗余,依赖关系复杂度增加、维护性降低、导致之后的开发难度变大。

和后端语言开发不同,比如,Java有包管理和类的支持,有一些常见(或者约定俗成)的实现层次,如:Controller、Service、Repository等;有框架和语言特性带来的优势,比如IOC、AOP、注解、继承、接口等,合理利用能够让代码职责单一,模块高内聚低耦合,接口化,可重用,易于测试等等。

而Web前端开发,由于涉及到的内容较广,又不太可能完全具备后端语言的优秀特性。所以,更加需要开发人员具有优秀的设计和管理思想,比如:CSS的合理命名和管理、有效利用CSS预处理器、JavaScript的模块化、框架的特性(比如AngularJS的依赖注入,指令)、以及组件化等等。

组件化其实是大型软件开发中的一个共识,特别是前端,在没有统一标准的前提下,大家都在不断的造轮子,有无数的人倒了下去,又有无数勇士踩着前者的尸体冲上来。也许是因为它确实能够具有一些非常优秀的特性:单一的职责、资源的高内聚、独立的作用域、可独立的测试、接口的规范化、可重用、可组合等。

4-folder-structure

我们项目的代码组织结构

从“风格指南”到“驱动开发”

总结一下前面的内容,“前后端分离”,“在线风格指南”,“组件化开发”,似乎我们只说到一些与开发相关的事情,其实不然。

“在线风格指南”被开发,UX、BA共享,合理的组件划分可以合理控制开发闭环,UX可以更快的看到设计实现的原型,提升团队成员沟通频率,BA可以方便的根据组件合理的编写Story(故事卡)。

当这三个角色都参与到这个过程当中时,我们就真正回到今天的正题“风格指南驱动开发”。

这是一个相当新的术语,但不是我发明的,如果要追溯的话,最早在公开场合中谈到这个概念的人应该是Nicole Sullivan,她在2014年9月的一次演讲《Components & SGDD》中提出(Nicole Sullivan目前在NPM这家公司,没错,就是那个NPM,做Product Manager & Design Manager)。

“风格指南驱动开发”尝试着:

  1. 让UX和前端开发更紧密的工作在一起,将设计与前端开发的工作闭环缩小,更快速的迭代产品原型。
  2. 将UI开发和业务系统分离开,业务系统不仅仅是指后端系统(不仅仅是前后端分离),也包括业务的Web系统。
  3. 让设计文档更加“灵活”,更加及时(up to date),更加一致(single source of truth)。
  4. 让前端资源管理更加规范,开发模式更加清晰。
  5. 让整个Web开发周期更加敏捷(Agile)。

它是一种前端开发和团队工作方式的实践。

工作流程 – 如何“驱动开发”?

5-sgdd-process

开发流程

怎么样的工作方式,才算“风格指南驱动开发”?其实,当团队拥有了“组件化的思想”和“在线风格指南”,“风格指南驱动开发”的整个过程其实是行云流水的,我简单描述一下:

1.挖掘到新的需求/特性

当新的需求出现时,UX开始进行页面设计,Living Style Guide会作为设计的参考文档。通常情况,设计师会查看已有的调色板、字体和其他基本元素或组件来组成新的页面布局。在组件化的思想和Living Style Guide的帮助下,BA和设计师都会尝试使用或者扩展现有的组件。

2.抽象成组件

一旦设计完成,BA、UX和开发会开始讨论如何把新的设计细分为独立的组件,哪些是已经存在可以重用的,哪些是新的需用新建或者扩展实现的。Living Style Guide作为桥梁帮助设计与开发进行沟通,促进双方的理解,确保实现的准确性。而抽象出来的组件,帮助BA划分任务和故事(Story),以便更加准确的估算“故事点”。

3.实现和文档化

此时,Living Style Guide是作为一个开发框架和设计试验场(playground)。

作为一个试验场(playground),允许你随时看到每一个开发出来的组件,作为开发框架,允许你快速开发,它和真正的产品实现完全隔离,这种隔离会鼓励你以更加抽象的方式创建组件,以便于让他们更容易被重用。

Living Style Guide的开发注重组件化的隔离和规范化的开发流程(套路清晰明了),我们常常会开发一些自动化的构建任务来帮助快速初始化一个组件需要的基本内容,只要开发人员对开发所需的前端技术栈有掌握,就能较快速的开发完成相应的组件。

而开发完成的组件在Living Style Guide中立刻变成“活的文档”,可以快速展示各种不同的组件应用场景,提供给UX和BA做审查(review)。

4.组件在产品应用中的热插拔

最后一步,就是将组件应用到真正的产品实现中(该产品代码应该是与Living Style Guide毫无关系的业务代码)。而对于Living Style Guide输出的结果,应该可以任意选择刚好满足需求所需要的组件,拥有足够的灵活性,才能实现它在产品应用代码中的热插拔。

如果还有第5步的话,那就是重复上面的4步,这就是“风格指南驱动开发”的完整流程。

留在最后的思考 – 它到底驱动了什么?

作为好奇宝宝的你们和我,当读完这篇文章,应该仍然在思考,它到底驱动了什么?

6-haoqi

也许你比较熟悉TDD和BDD,他们通过测试,驱动我们编写刚好满足测试和满足需求的实现,而测试反过来成为保护伞,在我们通过重构提升代码质量的同时,保证功能的安全性。

那么,“风格指南驱动开发”到底驱动了什么?也许,它驱动着我们尽最大可能去重新使用已有的组件(代码)和设计更通用的组件,也驱动着我们(开发、UX、BA)进行更加频繁的沟通,它驱动着BA(业务分析)书写更加合理的Story,也驱动开发进行更加合理的代码和资源的管理。

Share