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

Unexpected behavior of ampersand combinator (&) within nested rules #1575

Closed
jacobcarpenter opened this issue Oct 2, 2013 · 8 comments
Closed

Comments

@jacobcarpenter
Copy link

I'm running into unexpected behavior using the & combinator within nested rules.

Here is a fragment of pseudo-html I'm attempting to style with less.

<section class="details">
  <div class="info">...</div>
  <table class="info">...</table>
  <div class="info">..</div>
</section>

If I write:

.info {
  margin-top: 12px;

  table& {
    width: 100%;
  }
}

as desired, I get:

.info {
  margin-top: 12px;
}
table.info {
  width: 100%;
}

That is, all elements with the info class have margin-top applied, plus table elements with the info class get width: 100%.

However, if I nest these rules within details, the ampersand (&) combinator ceases to generate what I expect.

I would expect

.details {
  .info {
    margin-top: 12px;

    table& {
      width: 100%;
    }
  }
}

to turn into:

.details .info {
  margin-top: 12px;
}
.details table.info {
  width: 100%;
}

Instead, it turns into:

.details .info {
  margin-top: 12px;
}
table.details .info {
  width: 100%;
}

Is this a bug, or are my expectations flawed? Thanks!

@seven-phases-max
Copy link
Member

No, not a bug. & refers to a complete list of parent selectors, not only to the nearest ancestor.
Well, strictly speaking, the official documentation does not mention this (and to be honest I don't know if it was invented intentionally), but current behaviour makes sense. Notice that you still can get what you need in relatively short form:

.details {
    .info {
        margin-top: 12px;
    }

    table.info {
        width: 100%;
    }
}

While appending a full outer list would require you to repeat all of the parent selectors once again if & was only a nearest one... And it's quite common design pattern to have some extra customization (like a "theme switch" for example) by using a special class at root elements (e.g. html or body)...

@jacobcarpenter
Copy link
Author

Thanks for the reply and the recommendation to restate the class name to get the table rule to work. I certainly can do that; I was just looking for a way to not repeat myself.

Can you explain the situation in which the current behavior is desirable more specifically? I'm having trouble following the explanation of the common design pattern you mention.

@seven-phases-max
Copy link
Member

Something like that:

.some {
    > .very {
        > .very {
            > .deep {
                #element {
                    .theme-red  & {
                        color:           white;
                        background-color:  red;
                    }
                    .theme-blue & {
                        color:          yellow;
                        background-color: blue;
                    }
                }
            }
        }
    }
}

Now you can switch between two color themes by assigning corresponding .theme-* class to some grandparent element (e.g. body).
It's not that I'm a big fan of such implementation (personally I would write this using parametric mixins or so) but...


Of course both versions of the & expansion make sense in general and the difference is quite subtle, both have their pros and cons in various use-cases. But it seems like & -> complete parent list road is just a little bit less painful when trying to cover as many use-cases as possible.


P.S. to correct myself: this feature is actually mentioned here: Parent-Selectors (it's not very easy to find though)... Either way you can always check SomMeri/less4j/wiki as it covers almost every LESS feature in details (for example: Appender).

@jacobcarpenter
Copy link
Author

Oooh. That documentation you linked to looks very nice. Thank you.

I agree that both forms make sense in general and have their potential uses. Is there a way I can request consideration of a new type of appender to support the expansion I originally expected & to perform? Something like ^, or maybe even &^ to refer to just the enclosing context when using a "Parent-Selector".

@seven-phases-max
Copy link
Member

Is there a way I can request consideration of a new type appender to support the expansion I originally expected & to perform?

You just did I guess, however I suspect you need to invent some more well-grounded and/or generalized use-case than your example above. You know... "Less is very conservative in adding syntax".

@SomMeri
Copy link
Member

SomMeri commented Oct 4, 2013

@jacobcarpenter Maybe you could join the discussion in issue #1075 or simply add +1 if it would solve your problem.

@jacobcarpenter
Copy link
Author

@SomMeri this looks exactly like what I was wanting. Thanks!

@jacobcarpenter
Copy link
Author

Closing as duplicate of #1075.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants