LESS CSS:滥用&运算符进行嵌套?

13

Less使用&运算符来增强嵌套规则的可能性

.header        { color: black;
  .navigation  { font-size: 12px;
    &.class    { text-decoration: none }
  }
}

这会导致将&替换为父选择器,并将实际选择器连接到父选择器的右边,从而产生.header .navigation.class而不是正常的追加,这将导致.class成为后代:.header .navigation .class

现在还有以下可能性(也可以在这里查看):

.header        { color: black;
  .navigation  { font-size: 12px;
    #some-id & .foo   { text-decoration: none }
  }
}

这将导致以下结果: #some-id .header .navigation .foo在这里试一试。执行替换操作后,我已经在父选择器前面添加了一个选择器(#some-id)。

除了我永远不会以这种方式编码之外,因为这可能会很快捣乱你的样式表,我的问题是:

由于此功能未记录在文档中,它是一个功能还是更可能是错误?
有哪些可能的副作用?


1
不明白你的意思,"#some-id &" 的意义是什么?错误的代码肯定会导致错误的编译/转换结果,而且不可能记录所有错误行为。 - Denis Agarev
1
@DenisAgarev 你有 LESS 的经验吗?如果没有,请只读不要写... - Christoph
有足够的经验,但是忘记了这个语法,抱歉。也许像这样编码对于编辑一些现有的大型CSS文件很有用,但我认为这种替换的常规用途可能是危险的。 - Denis Agarev
2
这是有意的行为。在 less.js 源代码中搜索 '&' 可以明确这一点。LESS 文档并不完善,这很可能是未记录此行为的原因。可能的副作用包括:在选择器中间使用 & 可能会令人困惑。 - thirtydot
1
这是文档:http://lesscss.org/features/#parent-selectors-feature,奇怪的是它只提到了前置 :) - TWiStErRob
2个回答

10

自从我们在引用的那个问题中遇到这个用法后,我一直在进一步思考它的用途。虽然我不能明确回答这是否是对&的“错误”使用(BoltClock似乎认为这不是一个错误),但我想为其价值辩护(这意味着从逻辑上讲,这不是一个错误)。

在逻辑论证之前,我找到了另一个简短的、简单的引用(在“嵌套规则”部分),它似乎表明这至少不是无意的:“&表示当前选择器的父级。”就是这样。正如BoltClock所争论的,无论是前缀还是后缀似乎都不重要。所有的意图都是它成为指向该点当前“选择器父级”的占位符号。它总是与语言的“嵌套”使用一起提到,这意味着它被设计为指定嵌套中该占位符所处的位置的完整选择器字符串。如何使用该字符串(作为前缀还是后缀)似乎由编码人员决定。

现在,你提到(以前也提到过)你“永远不会以这种方式编码”,然而我发现自己看到了一个非常有价值的用法。考虑以下论点。

插图的HTML设置

为了举例说明,假设在body元素上动态设置三个可能的类(“浅色”、“中度”、“暗色”主题),以更改网站的“外观”。我们有两列,以及一些我们想要针对每个主题在每个列中分别为其样式化的链接类型(textLink, picLink, textWithIconLink)。

<body class="light">
  <div class="leftCol">
     <a class="textLink"></a>
     <a class="picLink"></a>
     <a class="textWithIconLink"></a>
  </div>
  <div class="rightCol">
     <a class="textLink"></a>
     <a class="picLink"></a>
     <a class="textWithIconLink"></a>
  </div>
</body>

现在需要问的问题是,在看这两个方法时,以下哪种方法...

  1. 代码更少(LESS)
  2. 更好地组织了LESS中的代码
  3. 输出更少的CSS代码
  4. 最佳地组织输出的CSS

"最佳"可能有些主观。我会让你自己从下面的证据中权衡。

选项#1 典型嵌套

LESS(大约99行代码)

/*Light Color Theme */
    .light {
      .leftCol {
        .textLink {
          color: fooL1;
          &:hover { color: barL1;}
        } 
        .picLink {
          background-image: url(/fooL1.jpg);
          &:hover { background-image: url(/barL1.jpg);}
        }
        .textWithIconLink {
          color: fooL2;
          background-image: url(/fooL2.jpg);
          &:hover { color: barL2; background-image: url(/barL2.jpg);}
        }   
      }
      .rightCol {
        .textLink {
          color: fooL3;
          &:hover { color: barL3;}
        } 
        .picLink {
          background-image: url(/fooL3.jpg);
          &:hover { background-image: url(/barL3.jpg);}
        }
        .textWithIconLink {
          color: fooL4;
          background-image: url(/fooL4.jpg);
          &:hover { color: barL4; background-image: url(/barL4.jpg);}
        }   
      }
    }
/*Medium Color Theme */
    .medium {
      .leftCol {
        .textLink {
          color: fooM1;
          &:hover { color: barM1;}
        } 
        .picLink {
          background-image: url(/fooM1.jpg);
          &:hover { background-image: url(/barM1.jpg);}
        }
        .textWithIconLink {
          color: fooM2;
          background-image: url(/fooM2.jpg);
          &:hover { color: barM2; background-image: url(/barM2.jpg);}
        }   
      }
      .rightCol {
        .textLink {
          color: fooM3;
          &:hover { color: barM3;}
        } 
        .picLink {
          background-image: url(/fooM3.jpg);
          &:hover { background-image: url(/barM3.jpg);}
        }
        .textWithIconLink {
          color: fooM4;
          background-image: url(/fooM4.jpg);
          &:hover { color: barM4; background-image: url(/barM4.jpg);}
        }   
      }
    }
/*Dark Color Theme */
    .dark {
      .leftCol {
        .textLink {
          color: fooD1;
          &:hover { color: barD1;}
        } 
        .picLink {
          background-image: url(/fooD1.jpg);
          &:hover { background-image: url(/barD1.jpg);}
        }
        .textWithIconLink {
          color: fooD2;
          background-image: url(/fooD2.jpg);
          &:hover { color: barD2; background-image: url(/barD2.jpg);}
        }   
      }
      .rightCol {
        .textLink {
          color: fooD3;
          &:hover { color: barD3;}
        } 
        .picLink {
          background-image: url(/fooD3.jpg);
          &:hover { background-image: url(/barD3.jpg);}
        }
        .textWithIconLink {
          color: fooD4;
          background-image: url(/fooD4.jpg);
          &:hover { color: barD4; background-image: url(/barD4.jpg);}
        }   
      }
    }

CSS 输出(大约 87 行输出,按主题组织)

 /*Light Color Theme */
.light .leftCol .textLink { color:fooL1; }
.light .leftCol .textLink:hover { color:barL1; }
.light .leftCol .picLink { background-image:url(/fooL1.jpg); }
.light .leftCol .picLink:hover { background-image:url(/barL1.jpg); }
.light .leftCol .textWithIconLink {
  color:fooL2;
  background-image:url(/fooL2.jpg);
}
.light .leftCol .textWithIconLink:hover {
  color:barL2;
  background-image:url(/barL2.jpg);
}
.light .rightCol .textLink { color:fooL3; }
.light .rightCol .textLink:hover { color:barL3; }
.light .rightCol .picLink { background-image:url(/fooL3.jpg); }
.light .rightCol .picLink:hover { background-image:url(/barL3.jpg); }
.light .rightCol .textWithIconLink {
  color:fooL4;
  background-image:url(/fooL4.jpg);
}
.light .rightCol .textWithIconLink:hover {
  color:barL4;
  background-image:url(/barL4.jpg);
}
/*Medium Color Theme */
.medium .leftCol .textLink { color:fooM1; }
.medium .leftCol .textLink:hover { color:barM1; }
.medium .leftCol .picLink { background-image:url(/fooM1.jpg); }
.medium .leftCol .picLink:hover { background-image:url(/barM1.jpg); }
.medium .leftCol .textWithIconLink {
  color:fooM2;
  background-image:url(/fooM2.jpg);
}
.medium .leftCol .textWithIconLink:hover {
  color:barM2;
  background-image:url(/barM2.jpg);
}
.medium .rightCol .textLink { color:fooM3; }
.medium .rightCol .textLink:hover { color:barM3; }
.medium .rightCol .picLink { background-image:url(/fooM3.jpg); }
.medium .rightCol .picLink:hover { background-image:url(/barM3.jpg); }
.medium .rightCol .textWithIconLink {
  color:fooM4;
  background-image:url(/fooM4.jpg);
}
.medium .rightCol .textWithIconLink:hover {
  color:barM4;
  background-image:url(/barM4.jpg);
}
/*Dark Color Theme */
.dark .leftCol .textLink { color:fooD1; }
.dark .leftCol .textLink:hover { color:barD1; }
.dark .leftCol .picLink { background-image:url(/fooD1.jpg); }
.dark .leftCol .picLink:hover { background-image:url(/barD1.jpg); }
.dark .leftCol .textWithIconLink {
  color:fooD2;
  background-image:url(/fooD2.jpg);
}
.dark .leftCol .textWithIconLink:hover {
  color:barD2;
  background-image:url(/barD2.jpg);
}
.dark .rightCol .textLink { color:fooD3; }
.dark .rightCol .textLink:hover { color:barD3; }
.dark .rightCol .picLink { background-image:url(/fooD3.jpg); }
.dark .rightCol .picLink:hover { background-image:url(/barD3.jpg); }
.dark .rightCol .textWithIconLink {
  color:fooD4;
  background-image:url(/fooD4.jpg);
}
.dark .rightCol .textWithIconLink:hover {
  color:barD4;
  background-image:url(/barD4.jpg);
}

选项#2 最终目标分组

我称之为"最终目标分组",因为这是我看待使用&来添加父级选择器的另一种方式的实际效果。现在,人们可以根据实际被样式化的最终目标元素进行编码。

LESS(大约88行代码)

/*Links */
/*Text  Links*/
.textLink {
  .light .leftCol &  {
      color: fooL1;
      &:hover { color: barL1;}
    }      
  .light .rightCol &  {
      color: fooL3;
      &:hover { color: barL3;}
    } 
  .medium .leftCol &  {
      color: fooM1;
      &:hover { color: barM1;}
    } 
  .medium .rightCol &  {
      color: fooM3;
      &:hover { color: barM3;}
    } 
  .dark .leftCol &  {
      color: fooD1;
      &:hover { color: barD1;}
    } 
  .dark .rightCol &  {
      color: fooD3;
      &:hover { color: barD3;}
    } 
}
/*Picture Links */
.picLink {
  .light .leftCol &  {
      background-image: url(/fooL1.jpg);
      &:hover { background-image: url(/barL1.jpg);}
    } 
  .light .rightCol &  {
      background-image: url(/fooL3.jpg);
      &:hover { background-image: url(/barL3.jpg);}
    } 
  .medium .leftCol &  {
      background-image: url(/fooM1.jpg);
      &:hover { background-image: url(/barM1.jpg);}
    } 
  .medium .rightCol &  {
      background-image: url(/fooM3.jpg);
      &:hover { background-image: url(/barM3.jpg);}
    } 
  .dark .leftCol &  {
      background-image: url(/fooD1.jpg);
      &:hover { background-image: url(/barD1.jpg);}
    } 
  .dark .rightCol &  {
      background-image: url(/fooD3.jpg);
      &:hover { background-image: url(/barD3.jpg);}
    } 
}
/*Text with Icon Links */
.textWithIconLink {
  .light .leftCol &  {
      color: fooL2;
      background-image: url(/fooL1.jpg);
      &:hover { color: barL2; background-image: url(/barL1.jpg);}
    } 
  .light .rightCol &  {
      color: fooL4;
      background-image: url(/fooL3.jpg);
      &:hover { color: barL4;  background-image: url(/barL3.jpg);}
    } 
  .medium .leftCol &  {
      color: fooM2;
      background-image: url(/fooM1.jpg);
      &:hover { color: barM2; background-image: url(/barM1.jpg);}
    } 
  .medium .rightCol &  {
     color: fooM4;
      background-image: url(/fooM3.jpg);
      &:hover { color: barM4; background-image: url(/barM3.jpg);}
    } 
  .dark .leftCol &  {
     color: fooD2;
      background-image: url(/fooD1.jpg);
      &:hover { color: barD2; background-image: url(/barD1.jpg);}
    } 
  .dark .rightCol &  {
      color: fooD4;
      background-image: url(/fooD3.jpg);
      &:hover { color: barD4; background-image: url(/barD3.jpg);}
    } 
}

CSS(大约88行输出[由于一个额外的注释],按最终目标元素组织;但请注意,由于类结构仍然存在主题的子组织)

/*Links*/
/*Text  Links*/
.light .leftCol .textLink { color:fooL1; }
.light .leftCol .textLink:hover { color:barL1; }
.light .rightCol .textLink { color:fooL3; }
.light .rightCol .textLink:hover { color:barL3; }
.medium .leftCol .textLink { color:fooM1; }
.medium .leftCol .textLink:hover { color:barM1; }
.medium .rightCol .textLink { color:fooM3; }
.medium .rightCol .textLink:hover { color:barM3; }
.dark .leftCol .textLink { color:fooD1; }
.dark .leftCol .textLink:hover { color:barD1; }
.dark .rightCol .textLink { color:fooD3; }
.dark .rightCol .textLink:hover { color:barD3; }
/*Picture Links */
.light .leftCol .picLink { background-image:url(/fooL1.jpg); }
.light .leftCol .picLink:hover { background-image:url(/barL1.jpg); }
.light .rightCol .picLink { background-image:url(/fooL3.jpg); }
.light .rightCol .picLink:hover { background-image:url(/barL3.jpg); }
.medium .leftCol .picLink { background-image:url(/fooM1.jpg); }
.medium .leftCol .picLink:hover { background-image:url(/barM1.jpg); }
.medium .rightCol .picLink { background-image:url(/fooM3.jpg); }
.medium .rightCol .picLink:hover { background-image:url(/barM3.jpg); }
.dark .leftCol .picLink { background-image:url(/fooD1.jpg); }
.dark .leftCol .picLink:hover { background-image:url(/barD1.jpg); }
.dark .rightCol .picLink { background-image:url(/fooD3.jpg); }
.dark .rightCol .picLink:hover { background-image:url(/barD3.jpg); }
/*Text with Icon Links */
.light .leftCol .textWithIconLink {
  color:fooL2;
  background-image:url(/fooL1.jpg);
}
.light .leftCol .textWithIconLink:hover {
  color:barL2;
  background-image:url(/barL1.jpg);
}
.light .rightCol .textWithIconLink {
  color:fooL4;
  background-image:url(/fooL3.jpg);
}
.light .rightCol .textWithIconLink:hover {
  color:barL4;
  background-image:url(/barL3.jpg);
}
.medium .leftCol .textWithIconLink {
  color:fooM2;
  background-image:url(/fooM1.jpg);
}
.medium .leftCol .textWithIconLink:hover {
  color:barM2;
  background-image:url(/barM1.jpg);
}
.medium .rightCol .textWithIconLink {
  color:fooM4;
  background-image:url(/fooM3.jpg);
}
.medium .rightCol .textWithIconLink:hover {
  color:barM4;
  background-image:url(/barM3.jpg);
}
.dark .leftCol .textWithIconLink {
  color:fooD2;
  background-image:url(/fooD1.jpg);
}
.dark .leftCol .textWithIconLink:hover {
  color:barD2;
  background-image:url(/barD1.jpg);
}
.dark .rightCol .textWithIconLink {
  color:fooD4;
  background-image:url(/fooD3.jpg);
}
.dark .rightCol .textWithIconLink:hover {
  color:barD4;
  background-image:url(/barD3.jpg);
}

总结思路

还有一些需要考虑的问题:

首先,大多数主题颜色(以及可能的其他主题方面)都将使用变量设置,在上面的选项2中甚至可以按主题分组放置 - 因此,散布在代码中的输出CSS的主题结构并不一定是不好的。

其次,任何类型元素的“标准”代码都定义在任何主题代码之上。我的示例未显示这一点,但是假设所有 .textLink 元素都设置了 text-decoration: none; ,那么它将在选项2中出现一次,而无需进一步的选择器代码,并且会出现在所有主题更改下面。对于选项1,我需要设置一个新的,非嵌套.textLink 选择器(至少需要另外一行代码)来将其应用于所有带有主题的链接,而该类的基本代码将再次与其余主题链接信息的代码无关。

第三,作为开发人员,如果我遇到了与我的页面上的 picLinks(一种特定类型的元素)有关的问题,则选项2使得检查我代码中与该元素相关的代码更加容易,因为所有主题的代码都位于一个位置。

显然,最终 LESS 和 CSS 的组织方式将是决定其价值的主要因素。 我在这里要表达的观点仅仅是为了证明以这种方式使用 & 添加父级选择器的方法非常有用和合理。


啊... "占位符" 就是我一直想不起来的那个词。(实际上,我当时在 iPhone 上写下了这个答案,当时无法集中精力... 当然现在我好多了!) - BoltClock
@BoltClock--很高兴我能读懂你的潜意识。现在如果我能掌握你的其余CSS知识就好了... - ScottS
谢谢您的详细帖子,我非常感激。但是我想解释一下我的说法“永远不会这样编码”。想象一下一个500-1000行的文件。对于大型项目来说应该没有问题。现在你想调试你的CSS - 它被压缩了。如果没有这种“滥用”的用法,选择器#test .foo .bar .hello由于嵌套的限制只能有一个位置。通过这种“滥用”的使用,您无法确定在哪个嵌套级别查找规则,因为CSS选择器可以位于任何地方。 - Christoph
1
@Christoph--首先,我不尝试调试缩小的代码,而是源代码。但我承认这并不总是可能的。然而,其次,如果按照我展示的方式使用,你的选择器路径仍然只有“一个位置”:在代码的.hello“终点目标”部分下面。换句话说,我的建议使用是一种反向嵌套。所有直接影响.hello的代码都在一起。我认为问题可能出现的地方是如果一个人在某个中间点使用了&。所以#test .foo [& = .bar] .hello,你现在正在将_两个_父级和子级结合在一起。 - ScottS

6

完全不算是滥用 & 组合器; 你可以在嵌套选择器的任何位置放置它,它都会被替换为它上方(所谓的父选择器)的内容。

[& 组合器] 用于将嵌套选择器连接到其父选择器,而不是作为后代元素。

注意它说的是“连接”,并没有说您只能在嵌套选择器前缀或后缀父选择器。连接并不仅限于特定的方向。

此外,“后代”一词与默认情况下嵌套选择器被视为由后代组合器链接所发挥的作用有关。这并不固有地将 & 的使用限制在仅限于后代,也不意味着父选择器必须代表父级或祖先元素,以使嵌套选择器仅附加到其中,而不能将其前置或甚至插入其中间部分。


我知道这是如何工作的以及为什么(它是一个简单的替换),但我想知道这是否是有意为之,以及这是否有多大的意义。这是一个相当理论性的问题。 - Christoph
如果这不是预期的行为,文档很可能会说明。在这里非常清楚,这是预期的功能。 - BoltClock
我认为你没有理解我的观点...文档指出,这是用于将额外的类、伪元素/-类连接到最近选择器中。然而,它并没有记录在文档中,用于在嵌套树的某个位置前置额外的选择器。 - Christoph
它并没有说你只能附加选择器。我已经编辑了我的答案。 - BoltClock
请再仔细阅读我的编辑,特别是我添加的引用下面的段落。 - BoltClock

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接