一、Alice 设计模式
是否记得这样的试题?用一套同样的HTML结构,生成不同 的视觉效果。CSS 的最大好处就是,灵活。比如同样的HTML结构,可以实现不同的外观;又比如,同样的外观,可以用不同的方式不实现。但灵活的同时也给我们带来麻烦。团队 协作时,大家的编码风格各异,其他人要看懂/debug的成本也因此提高。这时,我们需要一个规范,一个像红灯亮起我们就不能擅闯的规范。
在 Alipay 前端,Alice 框架有这样一套规范,让大家的协作更方便。这套规范基于 Alice,属于 Alice 的一部分。其最基本的原则是,同样的结构,产出不同的视觉效果。
注:所有样式的创建,都必须基于 CSS 规范 进行
Alice 的设计起源于支付宝的 pa.css 文件。由于这个文件被多系统引用,没有人敢随便改动里面的内容,所以只能不断往里面添加内容,导致了这个文件体积变得非常大。所以,亟待重构。在尝试重构后,发现了重构不是我们真正想要的,因些主要从两个方面来构建 Alice:
- 减少依赖,避免耦合
- 统一风格,让代码有规可循,保证团队协作效率
更我的设计思想,请参考:支付宝CSS架构
二、关于 Alice v3
检出 Alice 前端解决方案的所有代码:
- 到 Github 上 fork 我们:https://github.com/sofish/Alice
直接 clone 下来:
git clone git@github.com:sofish/Alice.git
1. 文件结构:
--- |---- plugins/ 浏览器兼容解决方案对应的编辑器插件 |---- solutions/ 浏览器兼容解决方案 |---- tpl/ 参考的模板文件 |---- w3c/ HTML5/CSS3 标准文档 |---- base.css Alice 的基础,所有样式均基于它 |---- readme.md
2. base.css 的作用
- CSS reset
- 小功能:
- .fn-clear 清除浮动
- .fn-hide/.fn-show 相当于display:block;/display:none;
- .fn-left/.fn-right 相当于 float:left;/float:right;
3. 命名规范:
注意:非组件/解决方案,请不要使用.ui-/.sl-作为前缀
- .ui- 组件前缀
- .sl- 兼容解决方案前缀
4. 注释:以一个组件结构为例
/* * @name: ui-组件名 * @overview: 组件描述 * @required: 与其他组件的依赖关系,一般为null */
/* 一般模块注释 一般单行或块状注释 注明 overwrite 的是可以覆的,没注明的是必须的 */ .ui-someuiorsl{ display:block; overflow:hidden; 999px;/* overwrite */ }
三、如何使用
1. 如何使用 alice 构建系统样式
A. 分析视觉稿
虽然视觉稿是多变的,但 Alice 模块的结构是不变的。因此,我们拿到视觉稿的第一时间(交互白板的时候,其实已经可以开始寻找),就是分析视觉稿。确认哪些资源是我们相要的。而 Alice 方面,我们要分析的是,全局设置的有那些,可以使用 Alice 模块的有哪些。通常,需要确定的全局设置包括:
- 颜色:文字、边框、背景
- 字体:种类、大小
- 布局:模块、分栏
- 图标:.ui-icon .ui-icon-NAME
一般,我们为全局设置创建一个单独的 global.css
而那些应该做为组件?一般情况下 TPL(下详)中的 14 个通用组件是必要的。另外需要根据页面使用的实际情况抽象。越多的组件,我们的编码就越统一、能创建越多的代码片段,这无论是对我们的协作,还是效率的提 升,都是非常有益的。下面这个 CheckList 可以作为你规范样式库的参考:
至于如何规划一个 CSS 文件,请参考《CSS 规范》
B. 使用tpl.css / tpl.html (命名规范在下面)
tpl.css 是一套 CSS 模板。如果你要构建新的组件。那么,你可以直接使用它。而不是引入+覆盖她。TPL 中包括了,全局设置/ 布局 / 列表 / 标题 / 切换 / 表单 / 表格 / 按钮 / 对话框。从 checklist 中可以看出已有组件列表。如果你的组件是已经有的,那么,参照已有的结构去构建。如果你新建一个新的组件,那么,使用下图所示的方法来构建:
记住:
不同外观的相同组件,HTML不要相互嵌套,CSS 推荐嵌套。
推荐的:
<ul class="ui-nav"> <li class="ui-nav-item"> some text <ul class="ui-nav-item-child"> <li> some text <ul class="ui-list"> <li class="ui-list-item"> some text</li> </ul... </ul> </li> <li... </ul>
不推荐的:
<ul class="ui-nav"> <li class="ui-nav-item"> some text <ul class="ui-nav-item-child"> <li> some text <ul class="ui-nav"> <li class="ui-nav-item"> some text </li> </ul... </ul> </li> <li... </ul>
推荐的:
/* global scrope */ .ui-icon-rarr{background:...} .ui-icon-larr{background:...} .ui-title{font-size:...} /* component only */ .ui-nav .ui-list{...} .ui-table .ui-list{...}
不推荐的:(除非需要重用)
/* set everything into a global scrope */ .ui-icon-rarr{background:...} .ui-icon-larr{background:...} .ui-title{font-size:...} .ui-list{} .ui-nav{}
在模块化和命名上,以一个Tab组件为例,分解如下:
值得注意的是:
- 组件名是必选的
- 状态请参照下文中“状态的规范”
- 在组件窗口最外一层添加状态,而非给每一个内容添加状态。除非内容有独立的状态
比如,我们可以这样写:
<div class="ui-new ui-new-hover"> <h3>TITLE</h3> <p class="ui-new-cnt"> .... </p> </div>
但不要这样写:
<div class="ui-new"> <h3 class="ui-new-title-hover">TITLE</h3> <p class="ui-new-cnt ui-new-cnt-hover"> .... </p> </div>
- 直接使用 TPL,而不是覆盖 TPL
- 充分考虑组件标签的语义化和层级的灵活性
语义化是什么?什么样的写法才是正确的。这里给一个建议,把你将要构建的页面当成一本书。是段落的,你就用P(aragraph);是标题的,就用 H(eader);是引用的,就用Blockquote。而不是简单的,块状的东西由块状元素包含,行内的元素用行内的标签包含。这里有点要求就是, 去深入了解每个 HTML 标签的用法。关于灵活。像 “在组件窗口最外一层添加状态,而非给每一个内容添加状态。除非内容有独立的状态” 就是一种灵活的表现。让你更灵活去地改变状态。
关于 HTML 的语义化,可以参考:这样去写你的 HTML
2. 如何使用 style lib (系统样式)
- 已有组件:直接使用
- 组件有更改:与和系统 owner 确认,并经过全面测试,才能修改组件
- 新样式:基于 Alice TPL,创建新样式
3. Alice 组件命名规范 (参照图示)
- 组件名
尽量让人看到名字就能知道是什么组件,比较 ui-tab,比如 ui-nav 这样的命名。所有小图标都使用 .ui-icon .ui-icon- 前缀,建议同一系统(域)人的常用小图标全部合成 sprite。用 HTML ENTRY 来引用,不要写空标签,应使用 HTML ENTRY 来替代,以达到语义化的要求。HTML ENTRY 请参考这个文档:https://docs.google.com/Doc?docid=0AWiI12yCmwaoZGNiemJqOGpfMTVmaHZtOWNkeg
- 组件整体状态 = 组件名 + 状态
常用的状态有:hover, current, selected, disabled, focus, blur, checked, success, error 等。通常你的命名应该看起来像 .ui-name-hover, .ui-name-error 这样。
- 组件模块 = 组件名 + 模块名
常用模块名有:cnt(content), hd(header), text(txt), img(images/pic),item, cell 等,只要词义表达了组件要实现的功能或者要表现出来的的外观就可以了。
- 组件模块状态 = 组件模块 + 状态
参照常用状态
命名注意:
- 组件嵌套:大组件可有子组件命名。
拿支付宝某项目中的的 .ui-nav 为例,如果有多级,可以这样命名:
ui-nav > ui-subnav(ui-nav的子类) > ui-list(嵌套进去的其他组件) <ul class="ui-nav"> <li class="ui-nav-item"> <a href="#">nav Triggle Link</a> <ul class="ui-subnav"> <li class="ui-subnav-item"> <a href="#">subNav Triggle Link</a> <ul class="ui-list" ....
- 多状态:多状态时,用唯一的命名来代替,而非抽象名词。
拿 ui-button 为例:
ui-button ui-button-1pxcorner [, ui-button-indexsign [, ui-button-SOMEID]]
而不要用 ui-button-round,这样,就可能会有: ui-button-round-a ui-button-round-b … 了。按钮又有多个状态,命名就会太长了 ui-button-round-a-disabled
- 统一:
比如你比较喜欢 ui-tip-container ,另外的一个相同作用的地方,就不要写 ui-message-cnt 了,用 [ui-tip-container ui-message-container] 或 [ui-tip-cnt ui-messages-cnt] 这样会是更好的选择
- 关于 .ui-icon-方向
一般情况下,我们经常遇到方向需要用单独标签来作为小图标的例子。比如几乎每个系统都会有的 ui-message 和 ui-tip,都可能会有上下两个部分。推荐这样写:
CLASS SPELL HTML ENTRIES ---------------------------------------------------- .ui-icon-uarr Upward Arrow ↑ .ui-icon-darr Downtward Arrow ↓ .ui-icon-rarr Rightward Arrow → .ui-icon-larr Leftward Arrow ←
四、样式库维护
1. 目录结构
注:目前支付宝使用的样式库管理工具是架构组开发的一套 Maven 解决方案。
你的团队可能不止一个样式库,像支付宝,有`我的支付宝`、`生活助手`和`商家服务`等产品,所以需要根据样式库规范创建不同的样式库。样式库可以是 svn 中的一个代码目录。每个组件的 css 组件都应该有对应的 html demo。当然,如果有对应的预览截图,并形成一个展示平台,那就更好了。下面是代码目录和形成的展示平台。
- system
- systemName
- resource
- demo ----------------------> 组件静态demo目录
- ui-xxx.html ----------------------> 单个组件静态demo源文件
- ui-xxx.html
- thumb ----------------------> 组件截图目录
- ui-xxx.png ----------------------> 单个组件截图
- ui-xxx.png
- global.css ----------------------> 系统全局样式
- ui-xxx.css ----------------------> 单个组件样式源文件
... ---------------------->
- index.html ----------------------> 系统组件库首页
- systemName2
...
像 Alice solutions 的每个组件下,都有一个 Readme.md 说明文档,查看这个范例页面:
https://github.com/sofish/Alice/tree/master/solutions/rotate
2. 打包工具
推荐使用 YUI Compressor 来压缩你的样式。目前支付宝使用的 Maven 解决方案中,集成的压缩工具就是 YUI Compressor。下载和使用文档请看这里:http://developer.yahoo.com/yui/compressor/。这里不再做细述。
关于 YUI Compressor 压缩版本的注释:
如果有些注释不想在压缩的时候删除,可以使用标识符来告诉程序,标识符是一个感叹号 “!”,示例如下:
/*! 这是不会被压缩掉的注释 */ –> /*!这是不会被压缩掉的注释*/
但像 /*中文*/ 这样的注释,如果没有空格把注释隔开可能有问题。所以,当你不想格式化注释,并希望上线的话,请确保注释是英文的,或者有空格把之隔开的中文注释。一般的 hack 注释是不会被压缩的,如:
压缩前:
html> bodyp{
color: blue;
}
压缩后:
html> bodyp{color:blue}
3. 展示平台
可以根据团队需求,构建自身的展示平台。
4. 测试规则
组件应经过严格测试。测试规则详见:《CSS 规范》
五、Alice 解决方案
解决方案的规范,同组件。不同的是:
- 解决方案要实现的是兼容,实现通常需要各种 trick,它是一种手段;而组件则是一个用各种手段实现出来的结果
- 解决方案的通用是指,偏向于指功能的通用;而组件则指视觉效果的通用
解决方案(solution)详见:http://aliceui.com/category/solutions/
二、本规范概述
制定本规范的目的在于使我们的CSS代码更加易于维护和重用,从而提升效率执行本规范时建议的流程 建议使用D(esign)C(oding)D(ebug)V(alidate)R(oundup),即DCDVR的流程。首先需要规划样式并分为共有样式和页面个性化样式,然后才开始编码,编码的同时进行Debug,Validate和代码片断的总结,而不是在所有模板都完成后才进行这三个步骤。
一、关于样式库构建规范
详见:http://aliceui.com/alice-css-guide/
二、selector 命名规范:
- 命名除 .fn- / .ui- / .sl- 外,可自定义命名。请慎用 selected current disabled first last success error
- 一般情况下,如果命名比较通用,比如 current,请限定在相应的上下文环境中。比如其父节点ID为#parent 等比较通用的命名,建议写成 #parent .current{},而非 .current{},即使是为了重用,也应该注意。只有在非常明确不会影响到其他组件工作,并且其他人不会写这种命名的情况下,才让它变成全局通用的。
- 作为JS接口的class或者ID,必须是以 J- 前缀开头的。除 JS 接口命名外,其他命名一律使用小写字母
三、注释:
-
组件注释:
/** * @name: 组件名 * @overview: 组件介绍 * @require: 依赖的样式 * @author: 小鱼(sofish@163.com) */
- 块状或行内元素,都请使用
/* comment */
注释,注释文字前后端保持各有一个空格 - 为了您的体验着想,一目了解的代码,就不要注释了,比如 “display:none; /* 让元素看不见 */” 工作还有很多啊,同学,请为了自己的体力着想。
四、CSS文件
- 文件编码必须使用utf-8(无BOM)
- 文件一律通过 link 链入 (NOT @import)
- 当只是单个页面使用时,才写在 <head> 的 <style> 中
五、Hack 规则
- 一般情况下,不要使用 IE 条件注释: <!–[if IE]><![endif]–>
-
通用 Hack
.all-IE{property:value\9;} :root .IE-9{property:value\0/;} .gte-IE-8{property:value\0;} .lte-IE-7{*property:value;} .IE-7{+property:value;} .IE-6{_property:value;} .not-IE{property//:value;} @-moz-document url-prefix() { .firefox{property:value;} } @media all and (-webkit-min-device-pixel-ratio:0) { .webkit{property:value;} } @media all and (-webkit-min-device-pixel-ratio:10000),not all and (-webkit-min-device-pixel-ratio:0) { .opera{property:value;} } @media screen and (max-device-width: 480px) { .iphone-or-mobile-s-webkit{property:value;} }
-
当然,强烈建议你使用更优雅的hack方式。那就是避免hack。或者在书写上,做点小trick。比如:
.selector .child{property:value;} /* for ie-6 */ .selector > .child{property:value;} /* except ie-6 */
- 关于Hack: 在firefox写完,IE有问题?还是其他浏览器也出现了。你知道IE Hack 能解决。我想,你也可能知道,用其他方法也能绕过。建议少用Hack。
六、书写规范:
1. 以如下写法为例:
第一种方式:(强烈推荐)
/* 区域模块-1 */
.tech, .ued{
background:#f60 url(alipay.com/orange.png) no-repeat 0 0;
}
/* 区域模块-2 */
.tech{
width:950px;
margin:0 auto;
}
.tech .wd{
width:620px;
float:left;
}
第二种方式:(如果让其他人看,请先格式化)
/* 区域模块-3 */
.ued{width:100%;padding:30px 50px;}
.ued .visual{display:inline-block;font:700 normal 12px/1.5 arial;}
2. 非常重要,需要你注意的点:
- 区域模块间用空行分隔
- 多个选择器写一起时,逗号(,)后紧跟一个空格
- 避免行内样式,即使是JS,也应该尽量使用class/ID来决定显示,而非行内样式
- 避免使用低效选择器(所以,别滥用class;当然,不滥用ID我相信你是知道的)详见:http://code.google.com/speed/page-speed/docs/rendering.html
-
尽量使用缩写,比如 font:700 normal 12px/1.5 arial; 一般不要写成
font-style:normal; font-size:12px; line-height:1.5; font-family:arail;
通常需要使用缩写规则的:
padding: toprightbottomleft; padding: top-bottomright+left; padding: topleft-rightbottom; padding: top-right-bottom-left; 如:padding:1px 2px3px4px; margin: 同上 如使用像`red`这样的颜色名,采用小写;16进制写法使用大写;写3位,还是6位,自便: color: red; color;#FFF; color:#ABCABC background: colorimageUrlrepeatattachmentposition; 如:background:#ddd url(alipay-wd.png) no-repeatscroll10px20px; border: sizestylecolor; 如: border:1px solid#ddd; font: weightvariantstylesize/lineHeightfamily; 如 font:700 small-capsitalic12px/1.5 "Courier New"; font-weight统一用 500代替 normal, 用 700代替 bold; list-style: typepositionimage; 如:list-style: squareinsideurl(alipay-wd.png);不过,通常我们要使用的是 list-style:none;
-
CSS3 书写规范:浏览器私有写法在前,标准写法在后
-moz-box-shadow: 1px2px3px#ddd; -webkit-box-shadow: 1px2px3px#ddd; box-shadow: 1px2px3px#ddd;
- 1.书写顺序
不强制书写顺序。但我们应该养成良好的习惯,让看代码的人更易理解。易读对于团队协作来说是非常重要的:1. 框架为先,细节次之比如写一个浮动容器的样式,我们应该先让这个容器的框架被渲染出来,让大家看到基本的网站框架。然后再再去渲染容器里面的内容。最终呈现给用户. 通常像 color font padding 之类的,写在后面。
.selector{float:left;width:300px;height:200px;font-size:14px;color:#f36;}
- 2. 有因才有果
比如想使用”图片替换文字“技术,通常要使用的text-indent。如果我们使用标签的是 span:<span class="thepic">这个文字将被图片替换</span>我们应该是先将 span 变成”块级元素“(使用 display:block,虽然他永远不是块级元素),再将文字 indent。而不是先 indent 再变成块级的:
.thepic{display:block;text-indent:-9999em;}
又如我们,如果想让一个 span 使用 margin, 那么我们应该这样写:span{display:block;margin-bottom:10px;} 而非 span{margin-bottom:10px;display:block;}。因为没有 display 之前,行内元素是没有 margin 的。
七、IE私有特性
1. expression
记住一句话:无论什么时候,都不要使用它。用 Javascript 吧。更优雅,更灵活。
2. filter
- 应该尽量避免使用 AlphaImageLoader
- 可以适当在投影/发光/渐变/去色方面上使用
3. IE bug
常见BUG,详见:http://sofish.de/1400
八、如何规划你的 CSS 文件结构
1.一定要有全局设置
全局设置可以避免重复书写同样的东西。比如3人在一个项目中,假设项目中涉及到的链接有 10 种颜色,如果有全局重设,我们就可以统一设置颜色。如果没有,我们可能每个都会为自己所负责部分的链接定义相应的颜色。这样一来就导致多处定义,且定义不统一。以后维护需要到各个地方都改。这是很麻烦的事。另外就是css文件也会因此变大。所以,在写之前,大家应该先分析视觉稿,统一全局设置。
/* global reset */
body{padding:0;margin:0;font.....}
a{color:#07f;}
a:hover{color:#555;}
需要注意的是,一般情况下,不要直接给标签写样式。而应该使用 class。像下面这种写法,并不是很合适:
h1{font-size:30px}
h2{font-size:20px}
h3{font-size:10px;}
如果有另外一个 h2 也要使用 10px 的,而其他的都仍使用 20px 的,那可就不好办了。所以,推荐用这种方法:
/* global classes */
.text-size30{font-size:30px;}
.text-size20{font-size:20px;}
.text-size10{font-size:10px;}
<h2 class="text-size20">… <h2 class="text-size10">…
2.一定要模块化
有两点需要注意的,一是,注意代码重用的模块化;一是,注意 HTML 结构的模块化,而不是分块。
-
我们是这样重用的:
<div id="module-1" class="module"> <h3>TITLE</h3> <p class="module-item"> some text </p> </div> <div id="module-2" class="module"> < h3>TITLE</h3> <p class="module-item"> some text </p> </div>
/* module, reuse style in module scrope*/ .module{} .module-status{} .module-item{} .module-status .module-1-item{} /* customize */ #module-1 .module-item{} #module-2 .module-item{}
-
HTML 的模块化:我们应该这样写(他们的视觉是一体的,代码也应该是一体的):
<div id="module-1" class="module"> <h3>TITLE</h3> <p class="module-item"> some text </p> </div> <!-- #module .module -->
而不是这样写:
<h3>TITLE</h3> <!-- 第一块 --> <div id="module-1" class="module> <p class="module-item"> some text </p> </div> <!-- 第二块 -->
九、值得注意的事
1.Background Color:
- 一般我们都会写: background:url(path/to/image) no-repeat 0 0;
- 当元素背景是深色的时候,比如#000,我们通常会选择一种比较浅的颜色来做为文本的颜色,比如#fff,为了避免网速缓慢导致CSS已经 加载,而图片仍未加载完成或图片服务器挂掉时文本不可见,请尽量使用加上CSS定义的背景颜色,如:background:#e8edef url(path/to/image) no-repeat 0 0;
2. has Layout
别用轻易使用hack,IE下很多兼容性问题都是 has Layout 引起的。试着给元素加上:
display: inline-blockheight: (除 auto外任何值)
(除 auto外任何值)
float: (left或 right)
position: absolutewriting-mode: tb-rlzoom: (除 normal外任意值)