许多编程语言在部署之前都会经过代码审查。 无论是快速浏览、深入的同行评审还是完整的单元测试,代码审查都有助于我们充满信心地将代码发布到生产环境中。
我开始想象 CSS 代码审查可能是什么样的。 CSS 可以用多种方式编写,最佳方式通常取决于项目。 我当然不是想通过这样的帖子来固执己见,而是为如何在发布之前从 CSS 中获得最大收益奠定基础。
为什么需要对 CSS 进行审查?
人们可能会质疑为什么要对 CSS 进行审查。 审查是又一个需要时间、成本和精力的步骤,这些东西似乎都在阻碍我们发布产品。
与此同时,代码审查让我们能够后退一步,脱下战斗装备,对我们的工作进行诚实的评估,或者将其交给其他人进行新的视角。 这使我们 区别于机器,最终可以让我们免受处理本来可以在发布之前捕获的错误和性能修复的麻烦。
这里的好处远不止预先消除错误。 我发现将审查分解为关注这些好处的特定领域有助于构建对话并优先考虑这些积极的结果。 对您来说,好处可能与我这里列出的不同,但这些是我经常发现自己反复提及的。
区域 0:它能完成工作
我们不要过多地关注这一点,但也不要忘记它。 CSS 的首要任务是为页面设置样式,使其看起来像预期的那样。 它与设计师的模型匹配或符合样式指南,或执行它应该做的任何事情。 它可以处理可变内容(不同长度的标题和内容、不同大小的图像等)。 如果不能,则需要首先修复它。
如果设计是响应式的,请确保设计按预期在每个断点流畅地运行。
区域 1:样式和一致性
这里的目标是确保 CSS 写得很好、组织良好且有文档。 我们中那些继承了其他开发人员项目的人知道这里的好处。 使用一致的命名约定并包含完整文档的代码更容易理解,并为将来如何维护和增强代码提供说明。
要问的问题
- 此项目是否有可用的 CSS 样式指南? 如果有,代码是否遵循它?
- 代码是否经过了彻底的文档记录? 是否存在令人困惑的元素、属性或黑客,会阻止其他开发人员了解为什么某些东西以这种方式编写?
- 元素的命名方式或属性的组织方式是否存在明显的差异?
可用资源
- CSS Lint:用于查找错误或不一致的优秀工具。 它甚至可以作为 Grunt 和 Gulp 任务,可以配置为根据您自己的规则集进行检查。
- CSS 样式指南:样式指南示例的汇总,可作为创建您自己的样式指南的灵感来源。
- 什么是好的文档?:Dave DeSandro 深入浅出地介绍了文档与营销的关系。
区域 2:浏览器兼容性
一旦 CSS 组织良好且一致,我倾向于将注意力转向它在不同浏览器和设备上的外观。 写得好的代码是一回事,但如果它不能在它应该的地方和时间工作,那就毫无价值。
要问的问题
- 此项目支持哪些浏览器和设备? 我们是否有权访问它们进行测试?
- 此网站是否有分析数据? 如果有,它们是否能让我们了解哪些浏览器更重要,需要优先测试?
- 是否存在针对特定浏览器或设备的“黑客”? 如果有,是否有其他方法可以避免使用它们? 它们是否经过了良好的文档记录?
可用资源
- Can I Use:一个中央存储库,用于参考哪些 CSS 属性与任何浏览器和版本兼容。
- Ghostlab:一个用于跨多个设备同步浏览器测试的应用程序。
- OpenDeviceLab.com:一个交互式地图,用于查找附近的设备实验室以进行测试。
- 建立一个开放式设备实验室:Smashing Magazine 深入探讨了设备实验室的好处以及如何建立一个设备实验室的技巧。
- 支持与优化:Brad Frost 精妙地阐述了这两者的区别以及它们如何影响代码的编写方式。
- 跨浏览器测试服务:Cross Browser Testing 或 Browserstack.
区域 3:特异性
现在是衡量代码中元素的具体程度以及确定是否有重构机会的时候了。 这将创建一个负责任的样式级联,其中元素要么像我们想要的那样模块化,要么像我们想要的那样具体。
要问的问题
- 任何地方都使用过 ID 吗? 如果是这样,是否可以使用类名代替? 样式指南对此有何说法?
!important
是否出现在代码中? 如果是这样,为什么使用它? 代码是否可以重构以避免使用它?- 我们是否依赖于前缀,如果是,前缀是否以一种有条理的方式进行组织,以便为不支持的浏览器提供适当的默认值?
- 元素的模块化程度如何? 它们是否通过“所有元素”测试,即它们都在同一个 HTML 文档中一起使用?
可用资源
- CSS 特异性图生成器:一个可视化整个样式表中特异性的工具。
- 特异性计算器:一个很好地可视化元素特异性程度的方法。
- CSS 特异性的细节:一篇关于特异性是什么以及它对样式级联的影响的帖子。
- 响应式交付:我非常喜欢创建“迷你 Bootstrap”的想法,但测试特异性也是一个好主意。
区域 4:预处理器使用
如果项目没有使用预处理器,请忽略这一点。 但如果使用了,那么肯定还有一些额外的需要考虑的东西。
要问的问题
- 是否在应该使用的地方使用了现有的变量? 是否引入了新的变量? 如果是这样,它们是否有意义,是否经过了文档记录?
- 是否有效地使用了其他抽象(例如扩展、mixin、循环、映射等)? 它们是否符合代码的其他部分的执行方式?
- 新的 CSS 是否放置在正确的部分中? 是否使用了新的部分? 它们在架构上是否有意义?
- 它们是否遵循任何既定的预处理器特定样式指南?
可用资源
区域 5:性能
我在审查的最后部分加入性能,不是为了贬低它,而是为了确保它是我们审查圣代的点睛之笔。 高性能 CSS 通常是关于优化以及如何打包和提供服务的,因此将其作为审查过程的收尾似乎很合适,即使在工作过程中我们始终将性能放在心上。
要问的问题
- 最终的 CSS 文件大小是多少?我们是否计划进行压缩和 gzip 压缩(是的,请!),以及压缩后的文件大小差异是多少?
- 我们正在加载多少个不同的样式表(通过 `<link>` 或原生 `@import`)?我们可以减少数量吗?它们可以根据条件提供吗?异步?
- 我们在生产环境中缓存 CSS,对吧?
可用资源
- CSS Stats: 输入网站的 URL,并获得大量返回的统计数据,包括对所有使用的字体和颜色的报告。
- CSS Dig: 与 CSS Stats 非常类似,但打包为方便的 Chrome 浏览器扩展。
- unCSS: 通过将 CSS 与 HTML 和 JavaScript 标记进行比较,删除未使用的 CSS 的任务运行器。可用于 Grunt、Gulp 和 Broccoli。
- Critical CSS: 另一个任务运行器,但它基于给定页面的 HTML 标记创建单独的 CSS 文件。这种优化一直受到 Google PageSpeed Insights 的推荐。
- loadCSS: 用于异步加载 CSS 的函数
总结
我绝对不会说这里提到的每个问题和工具都是所有项目所需要的,甚至相关。实际上,可能还有更多问题和工具需要考虑。在发布 CSS 之前,你是否会定期提出一些问题?例如,可访问性对你来说应该放在哪里?请分享!
另外,请记住,审核我们的代码的目的是不是让它完美。出于多种原因(无论是有意还是无意),我们在 CSS 中做出了妥协,最终,尽力做好 就足够了,这也是其中的一部分努力。
我认为应该有一个专门用于嵌套的区域,尽管它被包含在一些样式指南中。
没有提到 SMACSS 吗?它对我们的团队来说是一个福音,在组织项目结构和可扩展性方面。
总体而言,这是一篇关于 CSS 代码审查的不错的概述。谢谢!
我认为 SMACSS(或任何类型的 CSS 样式约定)都是隐含的。目标是确保采用任何标准都一致地执行,并且团队中的每个人都对此负责。
我要在 0 区添加一点:它不会做它不应该做的事情。
我在一个部门工作,这个部门会生成很多基于网络的项目,这些项目“类似于你之前做的那个,但……”因此,许多这些项目的起点是复制之前项目的代码,默认情况下是为新项目添加代码。结果通常是庞大的 CSS,其中经常包含新项目中甚至不存在的选择器。
因此,进行一次审查来指出这些文件试图做很多与新项目无关的事情,并且在过程中降低了加载速度,将是一个有用的步骤。
这是一个很好的观点:明确定义 CSS 对项目的意义,并确保它既没有违反这些标准,也没有超出范围。
在构建自动化过程中添加验证任务可以减少容易出错的人为因素。非常容易地不断检查你的 CSS 是否符合先前定义的标准。
我喜欢使用 Scss-lint 来检查项目是否遵循非常严格的样式指南,包括选择器的命名约定。此外,你可以创建自己的正则表达式来进行测试。
同意,自动化任务很酷!现在,并行运行这些任务,以及某种共享代码样式指南,将非常出色,而不是必须在两个地方维护这些标准和文档。
我经常对我们训练营学生的 CSS 进行“评分”,我可以说初学者经常做出非常糟糕的 CSS 选择器决策。换句话说,他们页面上可能只有一个 `header` 元素,所以他们会编写 `header {}`,而没有预料到另一个 header。或者,他们可能会编写 `some-component div {}`,因为他们认为现在他们的组件只有一个 div,所以这看起来还可以。我想说的是,初学者很难预测项目的未来,以及选择器的编写方式如何在添加更多标记时不可避免地被破坏。在这种情况下,`primary-header` 和 `some-component .sub-component` 可能更强大。
显然,我们不能以防范未来标记更改的方式编写选择器,但我可以说,在审查中要寻找的另一个东西是,我称之为“面向未来”的选择器,这将降低这种情况发生的可能性。
这确实是一个很好的观点,而且对于许多团队来说也是如此。这就是在某种代码样式指南中预先定义标准的好处,知道它也需要维护和更改,因为标准在不断发展……就像我们今年早些时候对 Sass 样式指南做的那样:https://css-tricks.org.cn/sass-style-guide/
还有一点值得一提的是 parker https://github.com/katiefenn/parker
非常实用的 CSS 统计工具。
我们之前在一家公司做过 CSS 和 HTML 审查(实际上,每一行代码在进入生产环境之前都会被审查)。
它所花费的时间比人们想象的要少得多。我们没有寻找详细的分析,甚至没有查看渲染的内容——只是代码。QA 将会发现任何视觉上的错误/浏览器不一致。实际上,我们检查了上面除了 0 区和 5 区以外的所有内容。
你可能会对审查中发现的错误感到惊讶。
我同意你的观点,它几乎不需要任何时间,而且你做得越多,你越善于发现不一致之处。在我第一份工作中,我在每个项目结束时都会进行代码审查,这让我成为一个更好的开发者,毕竟,如果你不知道它们是错误,你就无法从自己的错误中吸取教训。
我同意这些观点,除了 `!important`。它有其用途,但应该仅在特定情况下使用。
我遵循 ITCSS 系统来组织 CSS,在这个系统中,我有一个 `trumps` 部分,它位于样式表的最后,其中包含一个始终必须胜出的辅助函数列表,因此在这个文件中,所有内容都添加了 `!important`。
除此之外,任何找到的 `!important` 都应该受到审查,同样,任何 ID 也应该受到审查。
Geoff,很棒的文章!在过去的几个月里,我一直在我团队中实施许多类似的技术。我们一直在特别努力地使用 SCSS Lint 和 CSSComb 来共同在分布式团队中执行和自动化我们的样式指南约定。通过尽可能地自动化样式约定,这让我们能够将实际的代码审查时间集中在更具战略意义的决策上,例如类命名、特异性和何时使用或打破现有的站点模式。
我特别喜欢 Atom 和 SublimeText 的 scss-lint 编辑器插件,因为它们在你进行操作时,可以作为样式指南的视觉提醒。视觉提醒的另一个好处是,你可以看到哪里出错了,而不是等到构建失败才发现。在我们这里,我们正在努力改进一个大型遗留系统,因此我想要一个能够逐步帮助我们改进各个部分的工具,而不是迫使我们在准备好之前进行彻底的改变。
在我们的 CSS 代码审查中,有一个领域引发了一些争论,那就是关于后处理器的使用以及它们如何影响最终输出的代码。例如,你可能会遇到以下情况:
你可能会认为合理的批评可能包括
padding: 0px;
– *删除“0”值的单位*
transform: translate(20px,0);
– *供应商前缀?*
line-height: 0.9;
– *这里不需要“0”*
font-size: 16px;
– *你可以通过使用“font-size: 1pc”来节省一些字节*
margin: 0 !important;
– *为什么使用“!important”?添加一个注释来解释为什么你需要这样做,此外,你也不需要最后的半冒号*
问题是,我们的后处理器(在本例中是 **postcss**)处理了所有这些事情(除了注释)。所以问题是 - 在审查代码时,你如何区分预处理代码质量和后处理后的最终输出?如何在坚持良好的编码实践和让后处理器完成其工作之间取得平衡?
仔细阅读 Geoff 的建议后,我认为我们可以通过更多地关注 **区域 1**、**3** 和 **4**,以及更少关注语义和微性能增强器来改进我们自己的流程,这将是我从中学到的东西。
我认为处理后的代码质量并不重要,没有人会去阅读它,它是为机器准备的。
预处理代码是我们应该遵循最佳实践和标准的地方。
就像我在上面的评论中提到的,如果你使用的是一个用于严格覆盖的 trumps 文件,那么注释是多余的,但我同意在其他任何地方都应该添加注释。任何魔法数字也应该添加注释。
一般来说,当我看到类似 margin: 0; 这样的代码时,我总是想知道它正在撤消哪个样式,如果它覆盖了浏览器默认样式(比如引用块的边距),那就没问题。但如果它覆盖了之前声明的 CSS,那么很可能底层结构存在一些问题,如果我们发现自己需要覆盖很多样式,那么我们可能在过早地声明它们。
我认为在预处理代码中省略某些单位或最后一个声明的分号等问题并不重要,我们的后处理器可以删除所有这些内容。我个人更喜欢保留分号,原因与我认为在 JavaScript 中移除分号是一个糟糕的想法相同 - 这是错误和混淆的常见来源。
非常好。谢谢