Description
Problem
Sass variables defined at module root are global. They leak across files, and changing a variable in one module affects other modules (unless the variable is redefined at the top of each module).
This can lead to nasty bugs. Leaky variables are not what you expect from an addon with module
in it's name.
Cause
Unfortunately, Sass does not have a !local
flag that would make a variable defined at the root of a file to be local to that file.
Proposed solution
I've come up with a Sass hack to resolve this issue.
I wrap all the module's code with @at-root {}
.
Such directive is meaningless: without a selector it does nothing. The resulting CSS is identical to what it used to be before wrapping with @at-root
. The specificity of selectors is not affected.
But thanks to a pair of curlies, it has a side-effect: all variables defined inside are now local!
Note that you can still define/overwrite global variables using the !global
flag.
Example
app/pods/components/foo-bar/styles.scss
Before:
$padding: 20px;
.header: {
padding: $padding;
}
.footer {
padding: $padding;
}
When I wrote the code above, I wasn't aware that a global variable $padding
was already used throughout the app. I changed it's value globally.
In the best case, I would receive a compile-time error like incompatible units px and rem
.
In the worst case, it would compile, and half of the app's components will end up defaced. The exact amount depends on the alphabetic order of components, I guess.
After:
@at-root {
$padding: 20px;
.header: {
padding: $padding;
}
.footer {
padding: $padding;
}
}
Now the $padding
variable is local to this module. Assigning a value to it does not affect other components that use a global variable with the same name.
TL/DR
We have to wrap every our module with @at-root {}
by hand.
It would be nice if ember-css-modules
did it automatically.