denii denii - 5 months ago 7
CSS Question

What is the use of parent selector (&) alone as a selector? Is it bad practice to use such selectors?

After reading tutorial after tutorial regarding Less (LessCSS), I was just wondering how this

&
operator is supposed to be used. I know it's referring the parent element like:

div {
&.fullheight {
height: 100%;
}
}

// turns into

div.fullheight {
height: 100%;
}


But I often saw this:

div {
span {
& {
padding: 1em;
margin: 1em;
}
}
}

// turns into

div span {
padding: 1em;
margin: 1em;
}


Like when using ONLY the
&
operator inside of a class, it represents pretty much the parent element, but is doing this bad practise since you can have the same result when you would type like this:

div {
span {
padding: 1em;
margin: 1em;
}
}


Both work, so is it bad/good practise or are each of them maybe used in different situations?




For extra clarity, below is the link to an answer where I first saw that you can write
&
only in a class without anything else.

LESSCSS - use calculation and return value - First post by ScottS, fourth solution in his post.

Answer

Generally writing something like below would be considered as bad practice because the & there is just redundant and does no value add at all. It just outputs the entire parent selector div span.

div {
  span {
    & {
      padding: 1em;
      margin: 1em;
    }
  }
}

So, you should avoid writing such selectors which use only the & (parent selector).


The other example to which you have linked is an interesting case which I would term as an educated hack to get around the variable scoping and lazy loading concepts in Less.

Assume that the same code was written without the parent selectors (like below).

@unit:em;
@basevalue:1;
@val: 1;
@setUnit: unit(@basevalue*@val, @unit);

.someAwesomeClass { 
  @val: .2; 
  padding: @setUnit;
  @val: .1; 
  margin: @setUnit;
}

Here the @val variable is declared twice within the same block. Since Less does lazy loading of the variables, they need not be declared before being used (and) if the same variable is declared twice or more within the same scope, the last declaration would win.

When defining a variable twice, the last definition of the variable is used, searching from the current scope upwards. This is similar to CSS itself where the last property inside a definition is used to determine the value.

So, the compiled CSS output would have the value as 0.1em for both padding and margin whereas the expectation is for padding to be 0.2em and for margin to be 0.1em.

To overcome this, the author of that answer has introduced two namespaces (with no name) and has thus restricted the scoping issue. The variable defined within each nested block becomes local to that block only and so will be considered as two separate variables.

@unit:em;
@basevalue:1;
@val: 1;
@setUnit: unit(@basevalue*@val, @unit);

.someAwesomeClass { 
  &{
    @val: .2; /* this declaration applies only within this nest */
    padding: @setUnit;
  }
  &{
    @val: .1; /* this declaration applies only within this nest */
    margin: @setUnit;
  }
}

As indicated by the author of that answer (in the first line), it was a workaround because there was no way to create a true function with Less.

But starting with Less v2, we can define our own custom functions in Less and use them as described in this answer by Bass Jobsen. The ability to write such custom functions should eliminate the need to write such hacks.

You can also refer to the comment by seven-phases-max in the same thread for a solution without the need for such hacks.


Bottomline is that usage of & alone as a selector is a bad practice. The solution in the linked answer was a hack which was useful in earlier versions of Less. It is still useful but there are alternate options and so & alone as a selector should be used only in extremely rare circumstances where none of the other option work.