Open cssmagic opened 10 years ago
“文件名必须为全小写”未描述多个单词的连接应该用下划线还是连接符(减号)。 下面的例子里文件名有下划线。若使用下划线,且当只有一个mixin时,意味着mixin的命名也变成了下划线?然而mixin的的命名例子都是连接符。另外cmui的例子是用驼峰的。
“声明结尾无分号(这意味着所有每条声明均独立一行)”不如写成“每条声明单独一行,行尾毋需分号”。
“属性名与属性值之间无冒号,只留一个空格”此条我在考虑是否用冒号可以更快的帮助区分选择器?
前面是“当分行时,群组内的多个选择符之间通常可以省略逗号”,下面“建议在群组内的多个选择符之间总是写上逗号”,不清楚。
局部作用域的变量/函数/mixin是否命名需要用特殊前缀?我觉得可能必要性并不是特别高。特殊命名也使得重构(在没有工具帮助的情况下)变得更困难。
@hax 谢谢评论。这篇文档最大的问题是把主站相关的内容混进来了。我会单独为主站写一篇。其它问题解释如下:
“文件名必须为全小写”未描述多个单词的连接应该用下划线还是连接符(减号)……
“声明结尾无分号(这意味着所有每条声明均独立一行)”不如写成“每条声明单独一行,行尾毋需分号”。
好,会补充,会改进。
“属性名与属性值之间无冒号,只留一个空格”此条我在考虑是否用冒号可以更快的帮助区分选择器?
写冒号确实可以避免几乎所有歧义,因此 Stylus v1.0 有可能会要求写冒号。但写冒号实在是不爽啊,到时候再更新这里吧。(cc @HerringtonDarkholme)
前面是“当分行时,群组内的多个选择符之间通常可以省略逗号”,下面“建议在群组内的多个选择符之间总是写上逗号”,不清楚。
我心里对这一点确实有些纠结,我再理一下。在主站的 Stylus 规范中我可能会要求总是写逗号。
@hax 局部作用域的变量/函数/mixin是否命名需要用特殊前缀?我觉得可能必要性并不是特别高。特殊命名也使得重构(在没有工具帮助的情况下)变得更困难。
为什么会更困难?我觉得应该更方便才对?
我指的是如果要调整作用域,你还需要更名。
在没有语言支持的情况下,我们可以用命名约定。但是在本例中,stylus自己有作用域,可能并不需要基于约定。
我指的是如果要调整作用域,你还需要更名。
在这个规范的设计中,只作为 API 存在的变量才应该成为全局变量。因此,一个变量是全局变量还是局部变量(或称 “私有变量”),是早已注定的,不存在调整作用域的情况。
在没有语言支持的情况下,我们可以用命名约定。但是在本例中,stylus自己有作用域,可能并不需要基于约定。
Stylus 有块级作用域,但没有模块级的私有变量。$-
前缀主要用来标记 “私有”。
选择符这一条里可以加上不允许过深嵌套(4层),不允许在逗号分组的选择器下再使用逗号分组(这样会导致编译出来的选择器爆炸)
@cssmagic 我觉得不太好武断的说,不会存在本来私有的变量发现需要暴露,或者本来暴露的接口调整为私有的情况。
我觉得不太好武断的说,不会存在本来私有的变量发现需要暴露,或者本来暴露的接口调整为私有的情况。
实在想不出例子。为降低复杂度,这种想像不出来的极端情况就只能置之度外了。
即使真的要改,手工改改也是 OK 的,而且如果有前缀的话会很容易改 :smile:
更新:稍微改了一下(改回了最开始的版本),给私有变量和私有 mixin 加 $-
和 -
前缀是推荐做法,不强制;只有在不得不暴露到全局作用域时才强制加前缀。——这样究竟好不好,我会在实践中持续反思。
选择符这一条里可以加上不允许过深嵌套(4层),
考虑过这一点,但最终不打算做限制,暂时没有找到充足的限制理由。(甚至,我是鼓励选择符纵深化的。因为越是纵深,代码的目的性就越明确,修改起来就越没有压力。)
不允许在逗号分组的选择器下再使用逗号分组(这样会导致编译出来的选择器爆炸)
同上,不打算做限制。如果真的有必要这样写,也没什么大问题,有 Gzip 呢。
"选择符最末层不应该使用通配选择符(*)",这一条我认为不需要硬性要求,可能并不是很方便的能罗列出所有需要匹配的元素,而布局上又要求必须覆盖到所有。如果是最末层用了通配符,也不会像用在body之类根元素上那样,遍历很多很多个子元素。
"选择符最末层不应该使用通配选择符(*)",这一条我认为不需要硬性要求,可能并不是很方便的能罗列出所有需要匹配的元素,而布局上又要求必须覆盖到所有。
我的考虑是,绝大多数时候我们在最末层使用 *
完全是想偷懒,实践当中也没有发现无法罗列出所有待匹配元素的情况,所以不想放开。因为一旦使用了 *
,即造成代码的未知性(我们无法确定它到底要干嘛),很难修改和维护。所以 CMUI 会严格禁止它,业务代码可以再考虑。
如果是最末层用了通配符,也不会像用在body之类根元素上那样,遍历很多很多个子元素。
禁止它的另一个原因确实是性能因素。(DOM 元素与选择符的匹配过程是从选择符的最右侧开始的,采用这个算法是为了快速失败。而如果我们写的选择符的最右侧是 *
,则无法做到快速失败。)关于性能影响有多大,有争议;但在移动端,我还是想把这一点先限制住。
优先使用
none
来关闭边框或描边样式
没有找到 border 0
与 border none
的实质区别,实际开发中也没有遇到由这两者的差异引发的问题。为避免不必要的复杂度,可能会把这个规则去掉。
border: 0
实际是 border: 0 none currentColor
,border: none
实际是 border: medium none currentColor
。所以两者在与其他样式配合时有微妙的差别。
此外在老浏览器(ie6,7)中,border: none
似乎不能去除 button/input 的边框。
@hax 是的,就是这些区别。但考虑到这些区别并不影响代码质量,打算把这条规则去掉,开发者爱写啥写啥 :smile:
PR CMUI/CMUI#22 已加入对应的 Stylint 配置。
Stylint 的 bug 略多,跑了一下 CMUI v2 的代码,很多合法的代码都被报错。
有时间还是要自己写一个 Stylus 的 lint 工具。@lyt9304 😅
基本概念
对网站项目来说,所有 Stylus 文件分为两类:
@import
)。显然,只有入口文件是需要被编译成 CSS 文件的。
CMUI
可以将 CMUI 各主题的
index.styl
文件视为入口文件,也可以视为模块文件(由众多小模块构成的大模块)。这完全取决于使用者是直接使用编译好的dist/*.css
文件,还是以引用模块的方式来使用各主题的index.styl
文件。(百姓网手机站采用的是后一种方式。)CSS 编码规范
选择符
[强制] 选择符最末层不应该使用通配选择符(
*
)。值
[强制] 当长度值为零时,应省略单位。
[强制]
z-index
的值应为 10 的倍数。[强制] 尽可能精简那些可以自动展开的属性值:
[强制] 小数点前的零不省略:
声明
[推荐] 声明块中的各条声明需要以一定的顺序排列,以便快速浏览和定位。推荐顺序如下:
其它事项
(关于 CSS 的各种最佳实践,请参阅《CSS 编码技巧 · CSS Secrets》。)
文件系统
文件命名
.styl
。text-style.styl
。字符集
[强制] 所有 Stylus 文件一律采用 UTF-8 字符集,文件无 BOM 头。
[强制] 所有 Stylus 文件内部一律不标记
@charset
。如果页面本身没有采用 UTF-8 字符集,则在引用样式文件时需要在
<link>
标签上注明字符集:模块
模块的组织
与 JavaScript 模块类似,每个样式模块对应一个物理文件。模块必须以 mixin 的方式组织,而不是以代码片断的方式组织。比如:
这意味着在导入模块之后,需要手动调用模块中的 mixin。比如,模块的内容是这样的:
而入口文件是这样调用模块的:
或这样的(推荐这种方式,因为这会将模块内的 mixin 导入到局部作用域,可以有效避免同名 mixin 可能引起的冲突):
每个模块可包含一个或多个 mixin,建议只包含一个。不相关的多个 mixin 不应组织到同一个模块中。
模块的导入
[强制] 仅使用
@import
来导入模块,不使用@require
。模块的路径与文件名需要用引号包住。文件路径总是以
./
开头,文件名不需要包含.styl
扩展名:代码风格
大小写
代码块
[强制] 每条声明独占一行,行尾不写分号。
[强制] 属性名与属性值之间无冒号,只留一个空格。
[强制] 声明块(以及其它代码块)采用无花括号的风格,一律采用缩进来表示层级关系。
缩进
[强制] 采用一个 tab。
[强制] 换行符采用
LF
。[强制] 文件末尾至少要保留一个换行符。
[强制] 行末不留空格。
[强制] 括号内侧不加空格。
[强制] Mixin 名(以及函数名)与调用括号之间不加空格。
[强制] 减号的两侧需要用空格间隔,以便与连字符区分(取负运算符同理):
[强制] 逗号在用作分隔符时,其后必须加一个空格:
括号
在需要传入一个值的地方使用表达式时,需要把表达式用括号括起来:
其它字符
[强制] 引号一律使用单引号。
[推荐] 写在
url()
函数内的 URL 是不需要包一层引号的:注释
常规注释
[推荐] 代码中的常规注释优先选择单行注释(
// comment
),而不是原生 CSS 中的多行注释风格(/* comment */
)。[强制] 单行注释的双斜杠之后空一格。
针对代码块的注释独占一行,写在代码块的顶部;针对某个声明(或选择符)的注释写在声明(或选择符)的右侧,与声明之间用一个 tab 间隔(即 Elastic tabstops 风格)。
特殊注释
分隔线是一种特殊的注释,用于把文件划分为多个区段;或者说,它用于把多个代码块分组。分隔线有两种层级,两者的配合使用可以提高代码的组织能力。(尽管分隔线很有用,但我们应该优先通过纵深化的树形结构来体现代码块之间的独立关系。)
区段标记(
/** section mark **/
)是另一种特殊的注释,用于描述各个区段的名称或作用。分隔线和区段标记的使用示例如下:
建议在 IDE 或编辑器中将上述特殊注释设置为可以快速输入的代码片断(比如 WebStorm 中的 Live template)。
选择符
嵌套
尽可能利用选择符嵌套,来把代码归纳为树形结构。
父级引用
除了类、伪类、伪元素、属性选择符等情况之外,父级引用往往是不需要的,建议精简:
群组选择符
单纯由类型选择符所构成的群组选择符可以写在一行;但复杂的群组选择符必须分行:
当分行时,群组内的多个选择符之间建议总是写上逗号:
仅当确定不会产生歧义或解析错误时,才可以省略逗号:
[强制] 变量必须以
$
作为前缀。除前缀外,变量名由全小写英文字母和数字组成,且前缀后的第一个字符必须是英文字母;单词之间以连字符分隔。比如:
$color-bg
。每个变量在定义时应该总是独占一行,禁用内联定义的方式。
作用域
变量是有作用域的。
作为公开 API 提供的变量必须放置在全局作用域,即成为全局变量。
$cm-
开头,比如$cm-color-fg
。Baixing
主题来说,$bx-color-gray
就是个不错的变量名。非公开的变量应该被限制在一定的作用域内(成为局部变量),且建议使用
$-
前缀:如果某个变量不属于公开 API,但由于需要被多个根级代码块共享而不得不暴露到全局作用域,则必须使用
$-
前缀:Mixin
命名
Mixin 名由全小写英文字母和数字组成,且必须以英文字母开头;单词之间以连字符分隔。比如
my-mixin()
。定义
Mixin 内部的选择符不写不必要的父级引用:
调用
Mixin 在调用时必须使用括号。比如:
(注意:“透明 mixin” 不在此列,仍以类似属性声明的方式书写。)
Mixin 在调用时必须位于当前代码块的最顶部:
参数
Mixin 在定义时,其参数必须以
$
开头。除前缀外,参数名由英文字母和数字组成,采用小驼峰拼写方式。比如
$myParam
。作用域
Mixin 是有作用域的。
作为公开 API 提供的 mixin 必须暴露到全局作用域,即成为全局 mixin。具体实现方法如下:
非公开的(即只在内部使用的)mixin 应该被限制在一定的作用域内(成为局部 mixin),且建议使用
-
前缀:如果某个 mixin 不属于公开 API,但由于需要被多个根级代码块共享而不得不暴露到全局作用域,则必须使用
-
前缀。接口
如果某个 mixin 的作用等同于某个作为公开 API 存在的类名,则应该与该类名同名,比如用
cmBtn()
对应.cmBtn
。函数
命名
(参见 mixin 的命名。)
参数
(参见 mixin 的参数。)
作用域
(参见 mixin 的作用域。)
不建议使用的功能
Extend
Extend 功能会重新组织代码顺序,可能会导致无法预料的结果。因此禁用此功能,改用 mixin 来实现类似的代码组织功能:
在上面的示例中,第一段代码使用了 extend 功能,最终生成的 CSS 代码量较少;第二段代码生成的结果与第一段相同,相当于通过人工预先归并代码的方式来减少冗余度,但不易阅读和维护;第三段代码最为清晰,但生成的代码存在冗余部分。
最终,我们选择第三种方式,因为代码冗余会在 Gzip 阶段消化掉,而代码的可维护性永远是第一位的。
Placeholder
Placeholder 并不是一个独立的功能,它实际上是 extend 的一种高级应用形式。基于相同的原因,禁用此功能,改用 mixin 来实现类似的代码组织功能:
Block
Block 所能提供的功能是 mixin 的子集,没有额外优点。为降低复杂度,禁用此功能。
CSS Literal
即 CSS 字面量,由
@css
代码块来定义,其内部代码不会被 Stylus 引擎处理,只会原样输出。实际开发中暂未发现必须使用此功能的场景,为降低复杂度,禁用此功能。如果存在大段遗留的 CSS 代码需要整合到 Stylus 文件中,建议先将 CSS 文件转换为 Stylus 文件(以下操作会在当前目录下得到
foo.styl
文件):属性值引用
这是 Stylus 标榜的独有功能,但实践中发现它对代码质量并没有帮助。为降低复杂度,禁用此功能。应该总是使用变量来实现类似的功能。
其它
其它 Stylint 配置
{valid: true}
- 属性名、属性值、选择符必须是有效值。{mixins: ['...', '...']}
- 指定自定义的透明 mixin。{none: false}
- 不强制是否使用none
来关闭边框或描边样式(即border 0
和border none
均可)。{noImportant: false}
- 不禁用!important
的使用,因为较底层的样式代码可能需要它。{depthLimit: false}
- 不限制选择符的嵌套层数。{duplicates: false, globalDupe: false}
- 不检查声明与规则的重复情况。{maxErrors: false, maxWarnings: false}
- 输出所有校验结果。{namingConvention: false, namingConventionStrict: false}
- Stylint 的变量命名检测功能粒度过大,暂时关闭之。{extendPref: false, placeholder: false, blocks: false}
- 已禁用 Extend 和 Block 相关功能,因此关闭这些选项。{sortOrder: false}
- 这个选项用于校验声明的顺序,但由于我们很难罗列出所有属性,暂时关闭之。浏览器前缀
在源码中不书写任何浏览器前缀,只书写标准的 CSS 属性名或属性值。加前缀的事情由 nib 或 Autoprefixer 来自动完成。
压缩
相关阅读
(如有任何意见,请直接回复。)