I'm trying to create mixin that applies CSS hacks for different browsers:
@mixin browsers($browsers) {
$selectors: (
chrome: '&:not(*:root)',
firefox: '@-moz-document url-prefix()',
ie: '@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none)'
);
@each $browser in $browsers {
#{map-get($selectors, $browser)} {
@content;
}
}
}
For example:
#test {
@include browsers(firefox ie) {
background: red;
}
}
Expected compilation output is:
@-moz-document url-prefix() {
#test {
background: red;
}
}
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
#test {
background: red;
}
}
but it fails with:
Error: expected selector.
@-moz-document url-prefix(){
^
Of course I can use if/else statements inside @each like:
@if $browser == chrome {
&:not(*:root) {
@content;
}
} @else if $browser == firefox {
@-moz-document url-prefix() {
@content;
}
} @else if $browser == ie {
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
@content;
}
}
but is it possible to do that more... elegant?
After three and a half years, I've finally found a workaround and opened an issue in GitLab 🥳.
https://github.com/sass/sass/issues/3636
@mixin only-ie {
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
@content;
}
}
@mixin only-chrome {
&:not(*:root) {
@content;
}
}
@mixin only-firefox {
@-moz-document url-prefix() {
@content;
}
}
@mixin only-for-browsers($browsers) {
@each $browser in $browsers {
@if $browser == ie {
@include only-ie {
@content;
}
}
@else if $browser == chrome {
@include only-chrome {
@content;
}
}
@else if $browser == firefox {
@include only-firefox {
@content;
}
}
}
}
// Usage:
#test {
@include only-for-browsers(ie firefox) {
background: blue;
}
color: red;
}
It turned out to be much simpler, you just need to use @#{}
instead of #{}
in at-rules cases.
@mixin only-for-browsers($browsers) {
$selectors: (
chrome: '&:not(*:root)',
firefox: '@-moz-document url-prefix()',
ie: '@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none)'
);
@each $browser in $browsers {
$selector: map-get($selectors, $browser);
@if str-slice($selector, 1, 1) == "@" {
@#{str-slice($selector, 2)} {
@content;
}
} @else {
#{$selector} {
@content;
}
}
}
}
#test {
@include only-for-browsers(chrome firefox) {
color: #e25922;
}
@include only-for-browsers(ie) {
color: #1ebbee;
}
}