译者:伊一
感谢 勾三股四 的推荐,FamilySearch 的工程师 Steven Lambert 在这篇文章 Creating A Living Style Guide: A Case Study 中现身说法分享了他的团队建立样式指南的开发过程,从需求到实施到发布详细地讲述了他们的经验和教训,相信很多公司和团队都有视觉统一规范的问题,希望翻译这篇文章,对你们有所帮助。文章中有些词汇是我自己的理解,如果有不恰当的地方欢迎各位指正。
以下是正文:
在线样式指南是当今web发展的一个重要工具,尤其在大型的、复杂的web应用中。它有助于样式和模式形成文档,保证设计师和开发人员的同步,极大地有助于组织和提取复杂的界面。事实上, 在线样式指南仍然是一个团队沟通设计标准的最佳途径之一。
最近,我们的公司完成了一个在线样式指南的创建。这篇文章讲述了我们如何开发在线样式指南,这个过程中我们犯的错误,以及为什么目前的样式指南生成器不能满足我们的需求。
我们为何需要在线样式指南 Link
FamilySearch 是一个全球家谱网站,被多个团队建立和维护,每个团队负责网站的一个部分。四年前,我们对网站进行了重新设计,想要达成一个更加统一的品牌风格。然而,三年之后每个团队创建了他们自己独特的样式,我们意识到这个网站不再统一。
-
整个网站有200多种不同的颜色。而大部分颜色的十六进制值非常接近。我们发现,原因在于开发人员使用吸管工具提取设计模型中的颜色。
-
通用的样式,例如按钮,在很多样式表中进行了代码复制,或者更糟糕的是,即使在同一个样式表中也可能会有不同。
-
同一网页中的样式不一致。
-
用户体验模式(UX patterns)在整个网站中会有所不同,导致用户混淆。
我们决定是时候改变了。我们现在的做法是不可持续也是不可扩展的。我们需要一个样式指南。
众多颜色中仅有一小部分会应用到这个网站。注意这里的灰色有多少相似的色调 (View large version)
制作样式指南并不是一个新的想法。它之前被尝试过、做过 – 但是失败了。最后的成果是一个PDF格式的样式指南,已经过时多年并且很少被提及。很多设计师和开发人员甚至都不知道它存在。我们知道想要让这个新的样式指南成功,必须不断更新,否则就会像之前一样以失败告终。
我们开始了 Link
在2014年初,我作为一个web开发人员加入了FamilySearch。一个月之后,我开始发现,由我的团队负责的这部分网站有很多CSS代码膨胀。我们没有一个通用的样式表,所以每个网页不得不对这些通用的样式进行复制粘贴。很多时候这些样式可能会发生变化,导致通用的样式会有不一致的外观。
我开始和团队里的一名设计师讨论如何解决这些不一致的问题,提议将通用的样式整合到一个单独的样式表里,供所有网页共用。在业余时间里,我们依据所负责的网站部分的清单,查找可以加入到通用样式表中的样式和模式。在一个月里,我们把最通用的样式汇总到了一个样式表里,并且针对我们的网站部分发布了一个小型的样式指南。
我们的样式指南,受当时的 Github 样式指南的启发(View large version)
从建立到发布,我们都确保通知了团队里其他的开发人员,设计师和管理员我们在干什么。这有助于讨论为什么样式指南是有用的,并且允许所有人来支援这个项目。因此,当这个样式指南发布的时候,团队里的所有人都开始使用它,我们清理了很多代码库中的CSS膨胀代码。
我们做的事情被传开了,很快其他团队也开始对拥有一个样式指南产生了兴趣。我们与网站的首席设计师取得了联系,讨论了将这个样式指南延伸到整个网站的想法。而事实上,他们在一个月之前就忙于为市场团队建立一个样式指南。我们很快结合了成果,并开始了为整个网站构建样式指南的工作。
创建样式指南 Link
开始,我们将网站每个网页的大屏幕截图打印出来并挂在了一间屋子里。这不仅是看到不一致之处的绝佳方式,也可以作为讨论样式指南重要性的谈资。通过并排观察所有的网页,可以很容易发现没有样式指南的影响,引发关于如何使用样式指南解决这些问题的讨论。我们鼓励尽可能多的人来参观这个房间,发现问题供我们解决。
网站所有的网页被打印出来后,我们便检查每个页面,识别出在样式和模式上不一致的地方。我们在便签上记录下了查找的结果,并粘贴到了对应的页面,这样我们就可以很容易的发现哪里以及什么不一致。利用便签上的信息,我们可以收集出一个所有网站通用的样式和模式的列表。
墙上挂的就是网站所有的屏幕截图,我们为这个房间命名“不一致的房间(the room of inconsistencies)”(View large version)
在这六个月里,我们试图把一切都整合到一个统一的集合中。因为我们仍然在利用业余时间创建样式指南,所以可能会有几个星期毫无进展。
在那段时间里,我们组织了对开发人员和设计师的问卷调查,以便更好地理解这两个群体想要从在线样式指南中获取什么信息。在这些结果中,我们了解到了样式指南里需要包含什么和不需要包含什么。
我们也会有一些激烈的讨论,尤其是在颜色问题上。我没有在开玩笑 – 我认为我们花费了4个月的时间去决定是否需要一个调色板,它需要包含什么颜色,当不能使用一个单一的基色编程实现按钮和警告框来得到正确的视觉效果时该怎么办。
起初,设计师认为我们不应该强制一个调色板,这会限制他们的创造力。然而,我们越多的讨论统一颜色的重要性,我们就越觉得需要一个。我们决定定义一组设计师可用的基础颜色和主题颜色。为了帮助设计师不会觉得颜色选择太受限制,我们规定所有的颜色都可以用任意的百分比调亮,给设计师足够的创造空间。
讨论之后,我尝试去说服设计师,这个方式可以在为 alerts 和 buttons 编写颜色时节省大量的时间。如果我们可以使用一个基色,然后通过一定的百分比调亮或加深,来创建边框、背景和高亮的颜色,那么可以很容易地在需要时创建新的样式。然而,在大量的讨论之后,他们却说服了我,这种方法并不总能凑效。基于提供的基色,得到的颜色也许并不能保证对比度或者产生视觉上令人满意的效果。
项目进展到一半的时候,我们发布了一个样式指南的标准版。这给了那些感兴趣的团队尝试的机会,看看它怎么起作用。而且向那些团队展示了样式指南是如何节省他们的时间和精力的。
六个月以后,我们发布了正式的 FamilySearch Style Guide。我们非常激动,但是我们知道这个工作还未结束。我们需要让设计师和开发人员使用它。
为此,我们利用样式指南里最新的样式创建了一个 Sketch 模板,设计师可以用它很容易地创建新的模型。之后,这些模型可以交给开发人员,依据样式指南和模型里的信息来开发最终的产品。
我们的 Sketch 模板包含预定义的符号和样式文本,结合了样式指南里的样式和模式 (View large version)
这个 Sketch 模板使用了预定义的符号和样式文本,设计师可以在他们的设计中使用。这些符号按模式pattern(警告、按钮等)分类,样式文本按类型style(标题、段落,列表等)分类,并提供了各自所有的变型。这个模板由一名设计师维护,每当样式指南变化时都会更新。
使用这个 Sketch 模板和样式指南,设计师可以更专注于布局和工作流,而不是颜色、字体和按钮样式。我们和设计师密切合作,保证他们的创造力不会因为遵循样式指南被扼杀。我们不会死板的规定如何使用模块和组件,而是让设计师自己判断。在保证所有设计有一个统一的界面外观的前提下,允许设计师自由创作。
样式指南总体结构 Link
在六个月的开发过程中,我们也考虑了如何组织和呈现这个样式指南给开发人员和设计师使用。我们研究了很多种组织大型CSS项目的方法,最终无意间发现了 Brad Frost 文章中提到的原子设计atomic design。我们立即学习并尝试使用这个理论来组织我们的样式指南。
我们喜欢这个原子设计的一点就是,它鼓励创建类似于乐高的模块(LEGO-like pieces),并在此基础上创造更多复杂的组件。为了便于团队理解,我们决定为Brad Frost的阶段(stages)重命名。原子即是元素,分子即是模块,有机体即是组件。Brad Frost 在他的书中写道,对阶段的重命名是完全可以接受的,因为这里的理论思想才是最重要的。
“That being said, naming things is hard and imperfect. The names I’ve chosen for the stages of atomic design have worked really well for me and the teams I’ve worked with. But maybe they don’t work for you […] By taking the time to establish an agreed-upon vocabulary, [a] team [is] able to get on board with the concept of atomic design and work together effectively by speaking the same language.” – Brad Frost
“话说,取名字是很难并且不完善的。我为原子设计的阶段选取的名字对我和我的团队很适用。但是也许并不适合你们 […] 协定统一的词汇,可以让团队更好地理解原子设计的概念,有效的协同工作。”– Brad Frost
在对阶段的命名达成一致之后,我们使用这些名字组织我们的目录结构。我们为每一个阶段(stage)创建一个目录,并且为每个阶段下的每个模式(pattern)创建一个文件。这种方法虽然能很有效的组织我们的模式,但是没有给预处理使用的变量和函数提供存储空间。作为弥补,我们创建了一个_helpers_目录,所有人都可以导入它获取所有的变量和函数。
结构建立好之后,剩下的就是如何对这些模式进行分类和命名。我们建立了一组简单的规则便于迅速解决这个问题:
-
既然我们可以使用标签选择器和类名选择器选取一个元素,那么我们可以将类似 inputs 和 buttons 这样的元素和单一的类名选择器组合在一起,来创建简单的控件,例如 badges 或者 icons。
-
模块是那些需要不止一个 HTML 元素来创建的模式。我们可以很容易将 modules 和 elements 进行区分,因为后者只需要一个单一的 HTML 元素。像警告信息(alert messages)和卡片(cards)这样的模式就可以归为此类。
组建的划分需要一些技巧。我们最初尝试将使用了模块的模式归为组件,但是很快发现,由于原子设计的构造模块特性(building block nature),我们很可能会在有表单的卡片中获取到警告信息。我们觉得很不对劲,认为像卡片这么简单的东西不应该被视为组件。然后,我们想起了在原子设计中,有机体会被看作是一个界面中相对复杂的不同区域。但是怎么干净简单地定义一个界面的一个不同区域呢?
我们决定组件应该是那些可以被表示成 HTML5 区域元素(sectioning elements)的模式: <main>,<header>, <footer>, <aside>, <nav>, <article>, <section>。这样区分它们就简单多了,我们可以通过参考那些元素在一个 HTML 网页中的使用方式,理解何时一个模式足够大到可以被归为组件。
css
├─ elements
│ ├─ buttons
│ ├─ forms
│ └─ typography
├─ modules
│ ├─ alerts
│ ├─ cards
│ └─ modals
├─ components
│ ├─ header
│ └─ footer
└─ helpers
├─ functions
├─ mixins
└─ variables
目录结构一个例子
知道如何将模式分类之后,我们开始创建并为它们命名。大多数情况下,命名一个模式是相对简单的,尤其是在元素这个阶段,我们只需要根据它们是什么来命名即可(比如 buttons,forms,alerts)。其他没有名字的模式,我们会参考web上是怎么称呼的(比如 cards)。
然而,有些模式很难命名,因为它们在web上并没有一个统一的身份。举例来说,我们不得不花费一个月的时间为移动抽屉导航(mobile drawer navigation)这个模式命名。它有很多名字,比如 off-screen navigation, off-canvas navigation, tray, drawer 或者 slide-in。最后,我们不得不给出一个硬性规定。
有一个样式指南的好处就是,一旦一个模式被写入文档,所有人都会使用样式指南里的名字引用它。即使有人不认同我们选择的名字,考虑到和其他人的沟通,他们也不得不使用。
组织样式指南的最后一步就是搞清楚怎样书写CSS选择器。我们想要创建可以被轻松覆写的组件样式。如果你曾经使用过 Bootstrap 并尝试覆写它的基础样式,你就会明白像.nav > li > a这样去覆写是一件多么烦人的事。我们发现BEM CSS可以帮助我们为所有的控件写一个单独的类名选择器。开发者仅仅通过在此基础上追加自己的类名就可以覆写基础的样式。
比如,一个卡片模块创建了一个带有 box shadow 的矩形,并为子元素添加了 padding。如果一个开发人员想要移除子元素的 padding,那么他只需要同时使用对应的单一类名选择器和自己的类名就可以做到。因为样式指南只用了单一的类名选择器,所以开发者的选择器总会实现覆盖。
<div class=""fs-card"">
<h4 class=""fs-card__title"">Card Title</h4>
<div class=""fs-card__body no-padding"">
This is a card. It has a slight border radius and box shadow to make it
stand out from the content.
</div>
</div>
<style>
.no-padding {
padding: 0;
}
</style>
BEM CSS 使覆写变得简单
我们犯的错误 Link
在样式指南的创建过程中和发布之后,我们犯了一些错误,阻碍了开发人员和设计师使用它。有些错误很容易修复,但有些不是。俗话说,“不犯错的人什么都没做”。
1. 发布过早 Link
我们最早犯的错误就是过早地发布了样式指南标准版。虽然它激起了使用样式指南的兴趣,帮助我们获得了许多支持,但是当正式版本发布的时候问题出现了,团队不得不切换掉标准版。
开发人员和管理人员已经投入了大量的时间使用最初的样式转换他们的网页。当他们发现需要花费更多的时间转换到新的样式时,可想而知,他们并不高兴。我们对标准版的样式和类名做了很大的改动,这基本上是要他们从头做起。不仅如此,整个网页转换需要设计师和开发者人工逐页检查 才能确保万无一失。
为了补救,我开发了一个 审计工具 auditing tool,从书签工具中运行后可以鉴别和高亮网页上被样式指南进行了样式改动的地方。这个工具缩短了转换网页的时间,并且确保了所有的元素使用了样式指南中的样式。因为它可以从书签工具中执行,所以即使是设计师也可以使用它帮助完成转换的工作。
我建议,如果你正在创建一个样式指南,不要发布标准版或者一个早期版本,这必然会有重大的变化。同样的转换工作实施两次是件很痛苦的事情,而且最终可能会影响采用。
2. 误解了对于CSS来说什么是一个破坏性的改变 Link
样式指南发布之后,我们犯的另一个错误显现了。当我们观察开发者和设计师如何使用样式指南的时候,发现我们采用的按钮的名字不容易被理解。我们使用了名字“primary button”, “secondary button” 和 “tertiary button”,但是没有说明分别在什么情况下使用。
我们重新命名和描述,以便更好地表达它们的意思,最后改成了“recommended action button,” “button,” 和 “minor action button”。这些名字描述了按钮的用途而不是规定了使用次序,清楚地说明了每个按钮应该在什么情况下怎样使用。然而,因为我们改变了按钮的名字,所以也不得不修改对应类名的BEM修饰符。
变化前和变化后的按钮样式
每个按钮使用一个类名修饰符改变外观。开发者可以使用类名fs-button获取基本的按钮样式,然后按需求添加合适的类名修饰符,比如fs-button--tertiary获取的是第三种按钮样式。随着按钮名字的改变,修饰符也发生了变化,取而代之的是fs-button--minor。
等到了发布改动的时候,我们标记这次发布不具有破坏性(non-breaking),因为它没有破坏基础的按钮样式,而仅仅改变了修饰样式,但是我们错了。
发布后不久,我们开始接到了一些投诉,说我们破坏了样式。原来大多数开发人员认为的没有破坏性的改变是能安全升级到新版本,不需要改动代码。升级之后,他们发现按钮外观发生了变化,而且需要为每个按钮修改类名修饰符,他们很不满意。
那个小插曲之后,我们明白了,每个会造成模式外观变化或者需要类名改动的发布都是具有破坏性的。
3. 原子设计的组织 Link
我们采用了原子设计技术,使用元素(elements)、模块(modules)、组件(components)、模板(templates)和网页(pages)来组织样式指南。我们将样式指南设计成了多个页面,每个页面包含一个分类。
过了一段时间,我们总是会被问及一些样式被记录在了哪里,并为他们指向了样式指南的其他页面。我们很快就发现,设计师和开发人员甚至都不知道样式指南不止一页。他们期望所有的样式在一个页面上。
我们决定满足所有人的期望,把所有的样式都搬到了一个页面上。我们保持了内部文件的组织结构不变,只是改变了样式指南呈现信息的方式。
我们不要严格遵守原子设计的决定看起来像是放弃了要努力建立的东西。然而,我们的决定得到了验证,今年的早些时候,Trent Walton 在使用原子设计时写了an article about ensuring that conventions work for your team。我们意识到,与其照搬理论,不如按照人们期望的方式组织样式更为重要。
4. 手工制作样式指南 Link
最初的样式指南是一个纯手写的、有很多重复代码的网页。任何外观上的变化都需要人工添加到样式指南的每个部分。虽然一开始这种变化并不难实现,但是随着样式指南的逐渐充实,需要的工作量也越来越大。我们很快意识到,改动样式指南甚至要比增加新的样式还要复杂。
我们首次尝试将样式指南自动化,使用一个人工操纵的 JSON 文件创建了一个 Handlebars 模板( Handlebars 是JavaScript一个语义模板库,通过对view和data的分离来快速构建Web模板)。组合HTML和嵌入的对象、字符串,结合拥有样例输出的HTML文档,可以生成样式指南的各个部分。在一段时间内,虽然这种做法显得比维护一个单一的大型页面更加容易,但是却没有可扩展性,最后我们明白需要更进一步自动化。
官方版样式指南的设计模型(View large version)
我们开始研究样式指南生成器来解决这个问题。它应该更容易并且更加自动化的被操纵。我们创建了一个满足我们使用要求的需求列表。
-
允许我们为样式指南定制结构、模板。我们想要自定义整个输出,而不仅是一小部分。
-
如果不允许自定义结构,也需要能输出一个 JSON 对象,让我们能使用到自己的模板中。
-
输出的代码应该与示例分开。一些示例需要额外的、甚至完全不同的构建结构。例如,一个通常情况下在整个屏幕显示的modal想要显示在样式指南的一个小区域里,就需要额外的结构和样式。但是我们并不想让这部分代码输出,因为它与开发人员如何标记一个modal无关。
-
为 sections 创建层次,并按我们的需求排序
-
使用 Markdown 解析注释。在使用 JSON 字符串维护 HTML 之后,我们觉得使用 Markdown 会更简单些。
-
如果需要的话,可以把例子写在注释中,而不是一个单独的文件里。有时候,在相应的代码行下查看和编辑示例会更容易。
-
如果样式指南生成器可以在注释中使用标签,我们需要能够为 colors 和 icons 自定义标签
-
如果我们不能自定义标签,生成器需要能够解析任意的 key/value 形式的标签。
-
最后,这个生成器必须是仍然被维护的,这样当我们有问题需要解决的时候,可以寻求帮助。
-
此外,使用Javascript编写的生成器优先,必要时我们可以尝试修改它来满足我们的需求。
(原文里有个表格)
Note: 表格显示了各个样式指南生成器和需求的匹配情况。所有高亮的样式指南生成器使用的是基于标签的注释(都是基于KSS),需要满足最后两个需求。x表示满足了需求,**!**表示满足了部分需求。
对于自定义模板,大部分样式指南生成器仅允许修改 header/footer,或者代码渲染的方式,只有一个允许我们使用自己的模板。
创建我们自己的样式指南生成器 Link
看了目前市面上的样式指南生成器,我们发现绝大多数甚至还不能满足我们一半的需求。只有一个非常接近,但是也不允许我们自己创建模板,也不会输出一个 JSON 对象让我们使用。经过了好几周去研究和尝试不同的样式指南生成器,我们决定要想满足所有的需求,只能自己创建一个。
创建自己的样式指南生成器并不是一件新鲜事。实际上,在这个网站之前,SC5 Styleguide和SourceJS的作者就讨论过这么做的原因。这两个人与我们的经历类似,并且得出了相同的结论:目前的样式指南生成器不能满足我们的需求。
我们想要为生成的样式指南自定义所有的东西。我们想要设计一个自定义主题来匹配我们的品牌。我们的示例代码需要压缩,这样界面里就不会堆满一些设计师和开发者不关心的代码。有些时候我们的代码可能不同于示例代码,或者有些时候我们不会显示代码。
所以我们花费了两个月的时间建立一个可以满足这些条件的样式指南生成器。
LivingCSS 样式指南生成器 Link
我们用node.js创建了一个 样式指南生成器,可以解析JSDoc样式的注释,利用这些信息产生一个在线样式指南。我们决定使用基于标签的系统,因为Markdown不能像 key/value 标签一样简单的触发每个section的不同状态。
/**
* A short description or lengthy explanation about the style. Will
* be parsed using `markdown`.
*
* @section Section Name
* @example
* <div class=""my-awesome-class"">Example</div>
*/
例:LivingCSS 需要解析的注释代码
LivingCSS区别于其他 tag-like 注释解释器的一点是,它不会给你强加一个严格的标签规则。而是定义了一些基本的tags供你使用,并且,只要是遵循@tag {type} name - description 格式的标签都可以被解析(type, name 和 description 都是可选的)。此外,如果你需要特殊功能的标签,也可以自定义。
注释的描述使用 Markdown 结合标签解析,意味着你可以完全控制任意给定区域内容的渲染方式。被解析之后的注释传入一个 Handlebars 模板,产生样式指南。如果你不想使用默认的模板也可以自定义,这样你便可以按照需求自定义样式指南。如果你不想使用 Handlebars,你也可以选择输出一个适合的 JSON 对象。
要使用 LivingCSS,你只需要输入你想要解析的文件列表(有恰当的注释标记)和生成文件的输出目录即可。其他可选项可以作为最后一个参数输入。最后输出结果是一个静态的 HTML 文件,也就是样式指南。
使用LivingCSS生成的样式指南的输出示例 (View large version)
最终,我们建立了我们所需要的:一个灵活的样式指南生成器。如果你正在研究使用生成器创建样式指南,我建议你收集自己的需求,和目前可用的生成器进行比较。每个样式指南生成器有它自己的优势和不足,找到适合你的那个是自动化样式指南的最好方法。
维护 Link
样式指南发布之后,我们继续每周召开会议,讨论新的模式,现在的模式是否足够满足我们的需求,以及用户的需求。我们也允许任何人对现有的模式提出新增和修改的建议,并在会议中讨论是否实施。这有助于大家感受成为样式指南的一份子,而不是没有实权的被强迫做事。
当一个样式需要被改变或增加时,我们通常会先在 Sketch 里设计出来,尤其是如果我们需要讨论不同状态下的样式的时候。然而,当我们合并的样式与网站上发生冲突时,我们会选择其中一个作为官方模式,忽略 Sketch 的设计。
然后,我们把这个模式加入到样式指南里,试图重用许多先前定义的样式和图案。我们使用 LivingCSS 对这个新的模式自动更新样式指南。接下来,我们会把新的样式指南发布到测试环境,这样开发人员和设计师就可以在新版本上线之前对新样式进行测试。为了给所有的团队留出足够的测试时间,我们一般在一个月左右之后才上线。最后,我们会更新 Sketch 模板,保证所有的设计使用最新的样式。
最近,我们被告知,用户感觉我们网站上的字体很难阅读。我们做了一些尝试:使用一种更加清晰的字体,增大字号和行高,实现一个基线网格和模块化字型。我们认为这些改变真是太棒了,在一些用户测试之后,我们计划在接下来的几个月里实现它。
因为我们有了一个在线样式指南,和让团队在有限时间里手工升级排版相比,这样一个全网站的排版变化显得微不足道。我们只需要在样式指南里增加样式,所有人就可以自动获取到更新后的样式。
能够轻松在全网站升级样式,改善用户体验,或许是使用在线样式指南的最大优势。
总结 Link
创建在线样式指南的过程虽然漫长但是值得。过程中我们犯了一些错误,阻止了开发人员和设计师的快速采用和有效使用。然而,我们排除了万难,并最终成功。
尽管它已经发布,我们还有很长的路要走。还有更多样式和模式可以补充,更多的网页需要被转换,在不久的将来,我们计划在样式指南中拓展动画animations和无障碍指南。我们希望您学到了一些宝贵的经验,并且我们的经历可以对您的样式指南有所帮助。