Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
322 views
in Technique[技术] by (71.8m points)

css selectors - LESS CSS: abusing the & Operator when nesting?

Less uses the & Operator to enhance the possibilities for nesting.

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

which causes a substitution of the & with the parent selector and results in a concatentation of the actual selector right to the parent selector: .header .navigation.class instead of the normal appending, which would result in .class being a decendant: .header .navigation .class.

Now what also is possible is the following (see also here):

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

which would result in the following: #some-id .header .navigation .foo try here . The substition takes place and i have prepended a selector (#some-id) to my parent selector.

Besides the fact that I would never code this way, since this probably messes up your stylesheet in no time, my question:

As this functionality is not documented, is it a feature or more likely a bug?
Which are possible side-effects?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I also have been pondering this use further since we encountered it in that question you referenced. While I cannot answer definitively that this is a "bug" use for & (BoltClock seems to make a good argument that it is not a bug), I want to argue for the value of it (which argues it is not a bug from a logical standpoint).

However, before the logical argument, I did find another short, simple quote (in the "nested rules" section) that seems to indicate it is at least not unintended: "& represents the current selector parent." That's it. As BoltClock argues, whether prepending or appending seems irrelevant. All that was intended was that it be a placeholder for that "selector parent" that is current up to that point. The fact that it is always mentioned in conjunction with the "nesting" use of the language implies it is designed to designate the full selector string of the nest up to the point of the nest that it resides within. How that string is used (to pre- or append) would seem up to the coder.

Now, you mention (and previously mentioned) that you "would never code this way," and yet I find myself seeing what appears to be a very valuable use for this. Consider the following argument.

The HTML Setup for the Illustration

Assume, for the sake of illustration, there is a dynamic setting of three possible classes ('light', 'medium', 'dark' themes) on the body element that change the "look" of the site. We have two columns, and some various types of links we want to style (textLink, picLink, textWithIconLink) differently in each column for each theme.

<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>

Now the questions to ask are, just looking at the links, of the two following methods, which...

  1. Is less code in LESS
  2. Best organzies the code in LESS
  3. Outputs less code in CSS
  4. Best organizes the outputted CSS

"Best" may be somewhat subjective. I'll let you weigh that evidence yourself from below.

Option #1 Typical Nesting

LESS (approx. 99 lines of code)

/*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 Output (approx. 87 lines of output, organized by theme of course)

 /*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);
}

Option #2 End Target Grouping

I've named it "End Target Grouping," because that's really how I see using the & in this other way of adding parent selectors. One is now coding based off the final end target element that is actually being styled.

LESS (approx. 88 lines of code)

/*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 (approx. 88 lines of output [due to one extra comment], organized by end target element; but notice, there is still a suborganization by theme because of the class structure)

/*Links*/
/*Text  Links*/
.light .leftCol .textLink { color:fooL1; }
.light .leftCol .textLink:hover { color:barL1; }
.light .rightCol .textLink { color:fooL3; }
.light .r

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...