Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parent selectors not working within mixins using (reference) #1979

Closed
luishdez opened this issue Apr 19, 2014 · 10 comments
Closed

Parent selectors not working within mixins using (reference) #1979

luishdez opened this issue Apr 19, 2014 · 10 comments

Comments

@luishdez
Copy link

Having on mixin.less

.mixin-test() {
  .test {
    color: red;
    &:first-child {
      color: blue;
    }
  }
}

And main.less

@import (reference) "mixin.less";

.mixin-test();

It Outputs:

.test {
  color: red;
}

but if I remove the (reference) it prints

.test {
  color: red;
}
.test:first-child {
  color: blue;
}

lessc 1.7.0 (LESS Compiler) [JavaScript]

Not sure if it's related to: #1851

@aonez
Copy link

aonez commented Nov 7, 2014

Same here. If the mixin.less is something like this works:

.mixin-test() {
    .test {
        color: red;
    }
    .test:first-child {
        color: blue;
    }
}

So the point is in reference import only the first level nested rules are used. It goes no deeper than that.

Another example:

less code:

#hola {
    display: block;
    background-color: red;
    height: 30em;
    & > div {
        height: 20em;
        width: 80%;
        background-color: white;
        & > div {
            height: 10em;
            width: 80%;
            background-color: green;
        }
    }
}

html code:

<div id="hola">
    <div>
        <div></div>
    </div>
</div>

You'll only see two of the three divs.

@seven-phases-max
Copy link
Member

@aonez Could you elaborate what your second example has to do with (reference)?

@aonez
Copy link

aonez commented Nov 7, 2014

Sure, sorry I copy-pasted some code and now it does lack some meaning:

Take a common.less file:

.hola {
    display: block;
    background-color: red;
    height: 30em;
    & > div {
        height: 20em;
        width: 80%;
        background-color: white;
        & > div {
            height: 10em;
            width: 80%;
            background-color: green;
        }
    }
}

Take a someName.less file that imports common.less and uses its classes:

@import 'common';

#hola
{
    .hola;
}

The html page is the same as in my first comment, and will be using the someName.less file:

<link rel="stylesheet/less" type="text/css" href="someName.less"/>
<script type="text/javascript" src="less.min.js"></script>

<div id="hola">
    <div>
        <div></div>
    </div>
</div>

The css output, just using plain import is the expected:

.hola {
  display: block;
  background-color: red;
  height: 30em;
}
.hola > div {
  height: 20em;
  width: 80%;
  background-color: white;
}
.hola > div > div {
  height: 10em;
  width: 80%;
  background-color: green;
}
#hola {
  display: block;
  background-color: red;
  height: 30em;
}
#hola > div {
  height: 20em;
  width: 80%;
  background-color: white;
}
#hola > div > div {
  height: 10em;
  width: 80%;
  background-color: green;
}

Oviously we only need the #hola part in this case, so common.less must be imported using reference:

@import (reference) 'common';

#hola
{
    .hola;
}

The new ouput:

#hola {
  display: block;
  background-color: red;
  height: 30em;
}
#hola > div {
  height: 20em;
  width: 80%;
  background-color: white;
}

As you can see, it lacks any nested rule but the first level. In that case, the code should be:

#hola {
  display: block;
  background-color: red;
  height: 30em;
}
#hola > div {
  height: 20em;
  width: 80%;
  background-color: white;
}
#hola > div > div {
  height: 10em;
  width: 80%;
  background-color: green;
}

It lacks the third div properties:

#hola > div > div {
  height: 10em;
  width: 80%;
  background-color: green;
}

Hope this helps 😄

@seven-phases-max
Copy link
Member

I see, thanks. So the second example is just more verbose variant of the original snippet.

@aonez
Copy link

aonez commented Nov 7, 2014

You mean it's useless for you?

@seven-phases-max
Copy link
Member

I just add a sort-of self-note to save some time when reading this issue in future... (well, honestly, yes, it's sort of useless then since it adds nothing new).

@aonez
Copy link

aonez commented Nov 7, 2014

The point is that reference ignores third level and up nested rules, not rules with parent selectors as the tittle of this ticket says.

@seven-phases-max
Copy link
Member

The point is that reference ignores third level and up nested rules

But all examples here use parent selector... (i.e. &). So as I said #hola example above is just more verbose version of the initial snippet.
And if you change your example to :

.hola {
    display: block;
    background-color: red;
    height: 30em;
    > div {
        height: 20em;
        width: 80%;
        background-color: white;
        > div {
            height: 10em;
            width: 80%;
            background-color: green;
        }
    }
}

which btw. is equal style (& is redundant there) you'll find it works with (reference) just fine. So I still can't see anything specific about this example. (So it is & issue as the title says).

@radium-v
Copy link
Contributor

We use Modernizr classes in our build - here's an example of our justify-align hack:

.justify(@flex: true) {
  line-height: inherit;
  width: 100%;

  .__hack() { // named for the technique, not related to the bug
    font-size: 0.1px;
    text-align: justify;

    &::after {
      content: '';
      display: inline-block;
      height: 0;
      width: inherit;
    }
  }

  .flexbox & when (@flex = true) {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
  }

  .no-flexbox & when (@flex = true) {
    .__hack();
  }

  & when (@flex = false) {
    .__hack();
  }
} ._justify { .justify(); } // intended for extending the default result
@import (reference) "justify"; // prevents the ._justify class from being output
.box {
  .justify();
}

Expected output:

.box {
  line-height: inherit;
  width: 100%;
}

.flexbox .box {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

.no-flexbox .box {
  font-size: 0.1px;
  text-align: justify;
}

.no-flexbox .box::after {
  content: '';
  display: inline-block;
  width: 100%;
}

Actual output:

.box {
  line-height: inherit;
  width: 100%;
}

.flexbox .box {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

.no-flexbox .box {
  font-size: 0.1px;
  text-align: justify;
}

The key is that the & is used in places where cascaded nesting wouldn't work. If the import isn't using reference, the ::after pseudo-element gets output (and so does ._justify, which we treat as an internal, extend-only helper). With reference, the ::after doesn't get output.

The only working solution would be to change the mixin and reduce the nesting, like so:

.justify(@flex: true) {
    line-height: inherit;
    width: 100%;

    .__hack() {
        font-size: 0.1px;
        text-align: justify;
    }

    .__hack-after() { // move the ::after to its own mixin, to reduce duplication I guess
        content: '';
        display: inline-block;
        height: 0;
        width: inherit;
    }

    .flexbox & when (@flex = true) {
        display: flex;
        flex-wrap: wrap;
        justify-content: space-between;
    }

    .no-flexbox & when (@flex = true) {
        .__hack();
    }

    .no-flexbox &::after when (@flex = true) {
        .__hack-after();
    }

    & when (@flex = false) {
        .__hack();
    }

    &::after when (@flex = false) {
        .__hack-after();
    }

} ._justify { .justify(true); }

@SomMeri
Copy link
Member

SomMeri commented Jan 23, 2015

I think I incidentally fixed this by #2410 . So I will just add unit test for this into that one.

SomMeri pushed a commit to SomMeri/less-rhino.js that referenced this issue Jan 23, 2015
Name: Parent selectors not working within mixins using (reference)
Number: less#1979
@SomMeri SomMeri closed this as completed Jan 27, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants