大型项目中的结构化CSS

写CSS很容易。 写持续可维护的CSS则很难。

你也许听说过不下100 次了。因为在CSS中默认都是全局的申明。如果你是个C的程序员你知道全局变量是糟糕的。同时不管你是什么程序员,你该了解独立及可组合的模块是一个可维护系统的关键所在。

已经有很多CSS指南帮助人们构建可维护的CSS:SMACSS, OOCSS, BEM, ITCSS, ACSS, CCSS, Atomic Design, Maintanable CSS, rscss, 也许更多.

然而CSS的问题在哪里呢?

span {
  font-size: 11px;
}
.header-right {
  font-size: 22px;
  text-align: right;
}

如上的CSS定义, 样式立即在全局生效,并且影响到引用到此段代码的所有页面。 这里没有封装以及独立的模块。

在一个标准的程序语言中, 仅为需要实现的方法引入需要的模块即可,例:

# Python modules
import requests
from Flask import url_for
// Node modules
var express = require(‘express’)

这样就知道引入模块将会怎样影响到你的代码,且引用的资源会明显地影响到你正在实现的功能。

在CSS中这种角色是相反的。每次我写一行css时,会潜在地影响到项目中所有的东西,并且无意中改变了我当前工作以外其它页面的展现。 我的样式不仅仅是抽象渗漏法则能hold住的了, 它们像洪水般涌进我应用中的所有角落和缝隙。

Now this is understandable, and makes sense for basic styling like typography, simple styling of input fields, and styles that are inherently global. This is basically what HTML and CSS was built for. These tools were built for publication. To understand the thought behind these languages, I often imagine typesetting a book: You don’t want every page to look different — no, you want a simple coherent style throughout the book without much riff-raff. That’s why it makes sense to have tags like,s, and styling that is global and ever-present.

现在(从css渗漏的角度)这就变得好理解了,那些基本排版、文本输入框以及全局继承的样式就显得合理了。这是HTML和CSS为何被开诚布公的、公用化地创造出来。 想理解这些语言背后的原因,我常想去总结出一本书:想每页看起来是有规划的, 想一个简单连贯的样式贯穿始终但不需要那些冗余的css代码。那(对冗余代码的兼容)就是为何等标签合理存在并流传至今、始终能影响全局样式的原因。

然而,世界已经变化,web也已经变化。 我们不再单单是写 web 页面,我们开始创建web应用。我们今天不再需要从web上请求很多资源,到处都是已经内建好的HTML和CSS公共模块。

事实上这些所谓 特定样式的新方法 (例如react里js中的css),也可能成为一个构建web的新方向。但是如今,我们已经被CSS和HTML纠结良久,那意味着我们要小心翼翼的去用那些工具制作可管理、可维护的web应用。

Peergrade.io处理CSS的方式

规则1: 使用前缀 (class类名)

在Peergrade.io中我们在所有样式名中使用前缀 .pg。 在你的CSS代码中如果不使用前缀可能会带来些麻烦。原因是无前缀的类名最终将会导致和引入的样式冲突。例如你需要一个选色器datepicker - 你绝对不希望胡乱拼凑的去造轮子构建它(至少我不希望如此!),所以一般你会引用这个组件。 接着你可能在你的样式中随处可见类似 .prev, .next.separator等的类名, 如果你不用前缀它们可能会和你已有的类名产生潜在的冲突。

在很长一段时间内字体是不会在类名中用前缀的, 那意味着你经常会遇到.icon-*之类为前缀的命名冲突(现在他们用 .fa前缀)。我们仍然拥戴作者Mark Otto,虽然我们对他无后缀名的Bootstrap有一点失望。

规则2: 不要嵌套CSS选择器

在Peergrade.io中用到了Sass。 用Sass时,Sass本身有能够快速和HTML匹配的模式,例如:

#user-profile-page
.profile-description
    h3

    ul
      li
        a

过不了多久你会意识到 - 它其实很不友好。当你写它的时候,你也许会想这里仅有一个.profile-description的列表命名,但一两个月后, 你必须要增改另一个列表时,混乱的结构已经超出你能想到的范围。

同样,可以在父元素内的子元素中独立定义样式 - 这并不会受到你在前一阶段Sass这层已经定义好的样式的影响。

你可以通过subtle 和 brittle ways 在CSS中通过做选择器的嵌套来绑定你的HTML结构。

规则3: 构建组件时用边界元法(BEM)命名

尽可能试着用BEM命名去创建独立的组件,我们不必完全按照BEM的规范 - 只是用命名组合,这意味着类名以如下的方式命名:

.block__element--modifier

为了做到这些,我们按照如下方式构建Sass:

.pg-deadline
  &__date
    // becomes `.pg-deadline__date`
    color: $color-gray
&__header
    // becomes `.pg-deadline__header`
    font-weight: 700
&--highlight
      // becomes `.pg-deadline__header--highlight`
      color: $color-green

如下我们用Sass嵌套去创建BEM类名命名方式。这多少有点违背常理, 实际上会产生大量的扁平化CSS结构 - 没有嵌套 - 仅仅只有类名定义在头部。

如规则2预期我同样可允许.block--modifier 方式的类名:

.pg-deadline--editable
  .pg-deadline__header
    background-color: $color-blue

  .pg-deadline__date
    color: $color-black

在这个特殊例子中我们允许一层的CSS选择器嵌套。 这允许我们仅可以修改在特定块(block)级别的修饰符, 并且在子块中不能重复修饰符(可以理解为父子嵌套时不重名;“E”在BEM中即元素elements)。

为了更好的理解BEM体系,可以转向这里 - 由Harry Roberts写的CSS指南 :BEM形式的命名。(事后我们碰到类似的CSS时,自然会提及到Harry的这个命名体系)

向前看

看来没有人真正找到CSS最好的解决方案, 并且当看到Hacker News最新文章 -- 那些差点要变成(替代)CSS的语言 (中文版) 后, 相比较现状,我多少会有些失望。

归根结底:我们相信我们找到了一个CSS的可持续发展的根本, - 当然有更多改善的空间。 这计划就是去经常检查我们的指南书,去看看任务是否如我们所期望的那样去执行, 是否有必要去修正。


往期精选文章

使用虚拟dom和JavaScript构建完全响应式的UI框架

扩展 Vue 组件

使用Three.js制作酷炫无比的无穷隧道特效

一个治愈JavaScript疲劳的学习计划

全栈工程师技能大全

WEB前端性能优化常见方法

一小时内搭建一个全栈Web应用框架

干货:CSS 专业技巧

四步实现React页面过渡动画效果

让你分分钟理解 JavaScript 闭包



小手一抖,资料全有。长按二维码关注京程一灯,阅读更多技术文章和业界动态。

原文发布于微信公众号 - 京程一灯(jingchengyideng)

原文发表时间:2017-11-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券