构建稳固的、可升缩的CSS框架的八大原则

.myapp-Header {> nav > p > a {color: blue;}}

在文章 多年的可行经验中,我们被告知要避免使用选择器的嵌套(包括>) 。为什么呢?作者陈列出了以下三个原因:

  • 级联风格最终将毁了你一天。选择器嵌套的越多,越可能在无意间与多个样式选择规则相匹配。读到这,你该知道我们已经排除了这种可能性--使用了严格的命名空间前缀且在需要的地方使用了孩子选择器。

  • 太多的特异性将减少可重用性。如:nav p a这样的样式规则即使是在特定的环境下也不能被复用。但是我们也不希望发生这种情况。事实上,当样式规则不能与我们的目标--组件间的相互隔离--相契合时,我们会禁止这种样式的复用性。

  • 过多的特异性会使重构困难。该种情况在现实中有所体现。比如:在.myapp-Header-link a这条规则下,你可以随意在你的HTML组件里移动a元素,且同样的样式仍旧起作用。然而一旦使用的是> nav > p > a这样的规则,你就需要更新选择器以匹配a元素在该HTML组件中的新位置。但考虑到我们想通过小且具有隔离性的组件来组装UI库时,这个理由也就没有了实际意义。当然,如果你不得不在重构项目时考虑到全部的HTML和CSS文件,这将带来可怕后果。但是如果你是将一个个具有样式的小沙盒组合起来使用并且知道沙箱之外的都不需要纳入考量,那么这种类型的变化就不再是一个问题。

  • 这是一个很好的例子来帮助你理解这个规则。于是,你会知道该在什么时候打破这个规则。在我们的架构中,选择器嵌套不只是可行的,有时它是你不得不去做的事情。为它而疯狂吧!

    防止将样式注入到组件中

    当我们为我们的样式规则设置了“沙盒”之后,这些组件是否都能独立于彼此而独立存在了呢 ?简要介绍一下:

    • 通过在每个类名前加上组件的命名空间防止了样式向 组件外部 泄露的问题:
      +-------+|       ||    -----X--->|       |+-------+
    • 除此之外,该种方法还防止了项目组件间的影响问题:
       +-------+     +-------+ |       |     |       | |    ------X------>   | |       |     |       | +-------+     +-------+
    • 通过使用孩子选择器我们还防止了组件内的组件 被影响:
      +---------------------+|           +-------+ ||           |       | ||    ----X------>   | ||           |       | ||           +-------+ |+---------------------+
    • 但是,值得注意的是, 外部样式可以“入侵”到我们的组件中来:
       +-------+      |       |---------->   |      |       |      +-------+
      比如,我们的组件具有以下的样式规则:
      .myapp-Header {> a {color: blue;}}
      但是我们引入了有“不良行为”的第三方库,它包含了以下的CSS样式:
      a {font-family: "Comic Sans";}
      目前没有简单的方法能规避这样的问题--external abuse, 所以我们通常举手投降。

    Give up

    幸运的是,你通常可以在一定程度上控制你引入的库, 而且可以很快的找到一个表现良好的替代方案。

    当然,我是说过没有简单的方法来帮助你规避这个问题,但是并不代表没有。 这些方法里提出了很多折中的解决方案:

    • 直接覆盖: 如果你引入了 CSS reset ,并将其设置到相应的能“胜过”第三方组件设定的规则的选择器上,你就成功了。但是只要你的应用很小(也就是说,一个第三方共享的button组件都能嵌入到你的网页), 这个方法就会失效。所以,这并不是个好方法,列在这儿只是为了方法论介绍的完整性。

    • all: initial 是一个鲜为人知的CSS属性。它的作用便是用于处理这种问题。除了可以 阻止一个元素继承属性, 还能作为局部样式的重置方法使用, 只要其具有特异性争议 (and as long as you repeat it for each element you want to protect). Its implementation includes some intricacies 并且 并未得到全部浏览器的支持 ,但是最终 all: initial可能成为一个隔离style设置的有效工具。

    • Shadow DOM在上面已经提到过了。 它可以作为处理该项任务的一个工具,因其能在js和css中对组建的边界进行明确的声明。 尽管 在最近的safari版本中看到了一些希望,但是近年来,对于 Web组件规范的支持并没有多大进展。所以 除非你只考虑在已经支持的浏览器上工作,否则不要依赖于Shadow DOM去解决问题.