Skip to content

Issue with rulesets and scope #2156

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

Closed
Rayraz opened this issue Aug 20, 2014 · 6 comments
Closed

Issue with rulesets and scope #2156

Rayraz opened this issue Aug 20, 2014 · 6 comments

Comments

@Rayraz
Copy link

Rayraz commented Aug 20, 2014

I ran into what seems to be a bug with scoping and passing around detached rulesets. I've tried to narrow the problem down to it's essentials. Lets say we start off with setting and calculating a few variables:

@mobile:  ~"only screen and (max-width: 639px)";
@desktop: ~"only screen and (min-width: 640px)";

.mobile-vars() {
    @font-size: 16px;
    @button-height: 24px;
}
.desktop-vars() {
    @font-size: 14px;
    @button-height: 30px;
}
.button-vars(@responsive-vars) {
    @responsive-vars();
    @padding-lr: @font-size;
    @padding-tb: (@button-height - @font-size) / 2;
}

Now I'd like to generate some mobile styles and alter them for use on desktop computers:

.mobile-vars();
.button-vars({
    .mobile-vars()
});
.button {
    font-size: @font-size;
    height: @button-height;
    padding: @padding-tb @padding-lr;
}
@media @desktop {
    .desktop-vars();
    .button-vars({
        .desktop-vars()
    });
    .button {
        font-size: @font-size;
        height: @button-height;
        padding: @padding-tb @padding-lr;
    }
}

This less code compiles to the following:

.button {
  font-size: 16px;
  height: 24px;
  padding: 4px 16px;
}
@media only screen and (min-width: 640px) {
  .button {
    font-size: 14px;
    height: 30px;
    padding: 4px 16px;
  }
}

As you can see, the padding on the button has not changed for desktop styles, despite explicitly passing the desktop variables into the .button-vars() mixin.

However, if I change my less code such that the original mobile styles are scoped within a media query, everything works as expected:

@media @mobile {
    .mobile();
    .button {
        font-size: @font-size;
        height: @button-height;
        padding: @padding-tb @padding-lr;
    }
}
@media @desktop {
    .desktop();
    .button {
        font-size: @font-size;
        height: @button-height;
        padding: @padding-tb @padding-lr;
    }
}

Compiles to:

@media only screen and (max-width: 639px) {
  .button {
    font-size: 16px;
    height: 24px;
    padding: 4px 16px;
  }
}
@media only screen and (min-width: 640px) {
  .button {
    font-size: 14px;
    height: 30px;
    padding: 8px 14px;
  }
}

Same goes for using an empty parent selector:

& {
    .mobile();
    .button {
        font-size: @font-size;
        height: @button-height;
        padding: @padding-tb @padding-lr;
    }
}
@media @desktop {
    .desktop();
    .button {
        font-size: @font-size;
        height: @button-height;
        padding: @padding-tb @padding-lr;
    }
}

Compiles to:

.button {
  font-size: 16px;
  height: 24px;
  padding: 4px 16px;
}
@media only screen and (min-width: 640px) {
  .button {
    font-size: 14px;
    height: 30px;
    padding: 8px 14px;
  }
}

I'm experiening these errors using: lessc 1.7.4 (Less Compiler) [JavaScript]

@seven-phases-max
Copy link
Member

Basically most of it is because of #2064 (It's sort of bug but we agreed to consider it as a "known limitation" for the moment, see also less/less-docs#201). I.e. "Detached rulesets simply do not expose their variables into caller scope".
Notice that in your example the @responsive-vars(); call inside .button-vars has no effect (and corresponding variables are still taken from upper scopes where global one may have higher priority). I.e. the snippet can be simplified to:

@a: 1;

.mixin-1() {
    @a: 2;
}
.mixin-2() {
    @b: @a;
}

z {
    .mixin-1();
    .mixin-2();
    a: @a; // -> 2, but:
    b: @b; // -> 1
}

which in its turn seems like another issue (I suppose it's somewhat close to #1316 but may be not the same. Though I usually redirect all "global scope overrides parent/caller/callee scope" issues to #1316).

@seven-phases-max
Copy link
Member

A workaround for your case could be something like this (or some similar variation depending on your needs).

@Rayraz
Copy link
Author

Rayraz commented Aug 20, 2014

Allright, in that case I'll make sure to use unnamed namespaces to keep things predictable.

Considering this is a "known limitation", can I expect to be relatively safe when using this workaround? Or would a potential future update to overcome the known limitation end up breaking the namespaced workaround?

@seven-phases-max
Copy link
Member

With "known limitation" I refer to "Detached rulesets simply do not expose their variables into caller scope". The unnamed namespace trick is unrelated and I expect it to work in future just fine (unless we'll break the whole idea of & {}).

@Rayraz
Copy link
Author

Rayraz commented Aug 20, 2014

Awesome :D Thanx for the help!

@Rayraz Rayraz closed this as completed Aug 21, 2014
@matthew-dean
Copy link
Member

@seven-phases-max Do you know if this is this related to what I just posted: #2212?

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