在 SASS/SCSS 中过度嵌套选择器在实践中有多糟糕?
Posted
技术标签:
【中文标题】在 SASS/SCSS 中过度嵌套选择器在实践中有多糟糕?【英文标题】:How bad is it in practice to over-nest selectors in SASS/SCSS? 【发布时间】:2012-11-28 02:59:20 【问题描述】:我有一个 .scss 文件,其中包含以下内容:
nav
font-size: 0;
ul
margin: $padding/3;
li
z-index: 10;
position: relative;
display: inline-block;
font-size: $fontSize;
/**
* If we want separated, Uncomment!
margin: $padding/3;
@include border-radius(5px);
*/
&:first-child
@include border-radius(0 5px 5px 0);
&:last-child
@include border-radius(5px 0 0 5px);
padding: $padding/3 0;
@include background(linear-gradient(lighten($textColor, 10%), $textColor));
border: 1px solid lighten($textColor, 20%);
a
color: $brightColor;
padding: $padding/3 $padding;
font-weight: bold;
text-decoration: none;
@include transition(.2s all);
//Nested menues
ul
opacity: 0;
//display: none;
position: absolute;
margin: 0;
top: 0;
left: 0;
right: 0;
z-index: 5;
pointer-events: none;
@include transition(.2s all);
li
@include background(linear-gradient(darken($brightColor, 10%), darken($brightColor, 30%)));
display: block;
border: 1px solid lighten($textColor, 20%);
&:first-child
@include border-radius(0);
&:last-child
@include border-radius(0 0 5px 5px);
a
color: $textColor;
&:hover ul
pointer-events: all;
top: 100%;
opacity: 1;
//display: block;
它在实践中有多糟糕/有害?我听过很多关于“不要超过 3 个嵌套选择器!”的讨论。但它真的有害吗?它对页面加载有任何明显的影响吗?我所做的基准测试说不,但我有什么遗漏吗?
【问题讨论】:
我最担心的是它们生成的 CSS 文件的大小,但我相信编译器知道如何缩小... 如果能真正收到关于这个问题的正确答案,我会非常棒。幕后是否有一些编译器优化?当特定的 SCSS 规则(选择器?)被翻译成可能性能不佳的东西时,是否有可能收到来自编译器的警告? @ZenMaster - 我不知道警告,但我知道正在进行优化(尽管它可能是 Compass 的事情)。我见过许多将具有匹配属性的选择器组合在一起的情况(所以pcolor:red divcolor:red
变成了p, divcolor:red
)。
【参考方案1】:
这取决于页面加载后对 DOM 和样式进行多少动态操作。问题不是页面加载(大部分)或初始布局上的slow selectors,而是重绘/重排。
现在,Steve Souders 这么说on the average site it's simply not a real concern。但是,在 Web 应用程序或高度交互的网站上,CSS 规则 can make your repaints slower 的性能比它们必须的要差。如果你有很多重绘...
Nicole Sullivan、Paul Irish 和 Steve Souders 等专家介绍了 CSS 与 javascript 交互的方式以及如何编写高性能的 CSS 选择器。这不仅仅是深度(不同的选择器有不同的性能),但一个好的经验法则是限制深度和复杂性,以免自己陷入麻烦——但不是那么多的性能问题,请继续阅读。
然而,正如jankfree.org 所指出的,并不是certain properties in certain contexts (html5rocks.com) 的后代或特定选择器使油漆变得昂贵。我认为长或复杂的选择器更像是a maintainability issue (Nicolas Gallagher) 而不是性能问题——请记住,可维护性与性能相互作用。高度可维护的代码可以更快地迭代并且更容易调试(帮助您发现和修复性能问题)。
现在,关于 Sass 优化。是的,Sass 可以优化你的 CSS。但它无法优化您的选择器。 4 级嵌套块将作为 4 级嵌套选择器输出。 Sass 无法在不使您的 CSS 无法正常工作的情况下更改它。作为作者,你必须优化你编写 Sass 的方式来优化你的输出。我个人仅以有限的方式使用嵌套(对我来说,Sass 中的一个杀手级功能是使用 @extend
和占位符组合样式)。但是,如果您真的喜欢嵌套,您可以使用Sass parent selector reference(或更新的@at-root)在一定程度上调整您的输出。
据我所知,Sass 和 Compass 都没有内置工具来分析选择器并发出警告。可以使用AST 创建一个工具来执行此操作(设置最大深度并让您的预处理器警告您)。更直接地说,Google Page Speed does 具有提供一些信息的现有功能。 SCSS Lint 有一个嵌套选项。还有CSS Lint。 (如果您还没有使用 Grunt 或 Gulp 之类的东西,这些理论上可以添加到 Compass 配置的 on_stylesheet_saved
中运行)。
【讨论】:
【参考方案2】:想想你想如何编写实际的 css 选择器。不要仅仅因为它是元素的子元素就嵌套所有内容。
nav li ul li a
/* over specific, confusing */
.sub-menu a
/* add a class to nested menus */
一旦你开始链接这么多选择器,覆盖就变得很痛苦,并可能导致特异性问题。
【讨论】:
【参考方案3】:只是为了插话并执行其他人所说的话。从性能的角度来看,这不一定是一种不好的做法(与优化选择器相比,移除模糊/阴影和圆角可能会增加绘制时间),而是从可维护性的角度来看。
选择器的嵌套越重,生成的 CSS 规则就越具体(您已经知道了)。因此,当您想在某个时候“胜过”该规则时,您必须在级联的下方编写一个相同(或更高)特异性的规则以推翻第一个规则。如果您在其中有一个 ID,这也将使其更加具体(所以避免,除非您需要它们并且知道您不需要覆盖下一行)。
要遵循这个逻辑结论,除非需要,否则不要嵌套。不要有这样的规则:
.selector .another .yeah-another
什么时候可以做同样的工作:
.yeah-another
它只是让每个人(包括你)的生活更轻松。
【讨论】:
【参考方案4】:不要嵌套 CSS。我们觉得嵌套 css 很舒服,因为这与我们在 HTML 中所做的非常相似。嵌套为我们提供了.some-child
在.some-parent
内部的上下文。它使我们能够对级联进行一些控制。但仅此而已。
正如 SMACSS 建议的那样,我将嵌套在类名中。即,使用.child-of-parent
而不是.parent .child
或.parent > .child
在实践中糟糕的嵌套会导致页面极其缓慢。看看 github 如何加速他们的差异页面。你至少应该遵循inception rule 声明你不应该嵌套超过 4 个级别。
但是,我会更进一步说我们根本不应该嵌套 CSS。我写了一个blog post 表达我的意见。希望这有用。
【讨论】:
一个写得很好的答案。谢谢你。我也会读你的博文:)【参考方案5】:我的看法:
你告诉我哪个对你的眼睛更不利
来自操作
nav li ul li a color: $textColor;
或者按照建议
.nav-menuitem-menu-menuitem-link color: $textColor;
所以...
问题是“在 SCSS 中过度嵌套是不好的做法吗?” (或者是 SASS?)我说不。 但这是一个辅助论点。
WORSE 做法在于将 SASS(或者是 SCSS?)输出以机器驱动的状态用于生产。
S*SS 只是你的技巧包中的一个工具,与 Notepad++、Git 或 Chrome 没有什么不同。它的作用是通过将一些非常通用的编程概念带到构建一些 css 的地步,让您的生活更轻松一些。 它的作用不是构建你的 css。 你不能期望它为你完成你的工作并创建完全可用、可读、执行的输出。
尽可能多地和尽可能深地筑巢,然后遵循良好实践...
...之后将通过您的 css 并进行手动调整。使用您的超嵌套输出进行测试、构建等。当 S*SS 在上面创建我的第一个示例时,给该锚一个类并使用 nav .class
调用它。
【讨论】:
我喜欢同时使用 S@SS :P 谢谢你的回答,我同意这里所说的很多,但是,似乎存在过度嵌套的问题它涉及页面的动画和重排。所以“神话”本身也有一些优点。不过,你会得到我的 +1 :) @MadaraUchiha 在同一点上很好,.if .your .nested div #is .too-deep
让网站正常运行,你怀疑这是问题所在,然后毫不犹豫地把它拉到一边,在 S* SS(或者是 S@SS?)并给它一个更短的选择器。【参考方案6】:
虽然不能直接回答您的问题,但您可以为自己的目的保留高度嵌套的 sass,但仍然使用@at-root
。看看here。
.parent
@at-root
.child1 ...
.child2 ...
// compiles to ...
.child1 ...
.child2 ...
【讨论】:
这有什么帮助?它只会让事情变得更加混乱。 例如我喜欢在 sass 文件中使用深度嵌套(可读性、组织性),因此为了避免 css 输出中出现复杂的选择器,我使用了@at-root。正如我所说,这并不完全是您问题的答案,但如果您容易出现大量嵌套,请记住这一点:)以上是关于在 SASS/SCSS 中过度嵌套选择器在实践中有多糟糕?的主要内容,如果未能解决你的问题,请参考以下文章