Reputation: 10390
I wish to nest a number of rules inside a parent css selector using Less CSS. Usually this works just fine, but I've encountered a construct in Twitter Bootstrap's css that's problematic. Here's the pattern in question as a mixin:
.responsive-invisibility() {
&,
tr&,
th&,
td& { display: none !important; }
}
Here's how I wish to use it:
body.force-sm-viewport-or-higher {
.visible-xs {
.responsive-invisibility();
}
/* more stuff */
}
Here's what this produces:
body.force-sm-viewport-or-higher .visible-xs,
trbody.force-sm-viewport-or-higher .visible-xs,
thbody.force-sm-viewport-or-higher .visible-xs,
tdbody.force-sm-viewport-or-higher .visible-xs {
display: none !important;
}
What I want:
body.force-sm-viewport-or-higher .visible-xs,
body.force-sm-viewport-or-higher tr.visible-xs,
body.force-sm-viewport-or-higher th.visible-xs,
body.force-sm-viewport-or-higher td.visible-xs {
display: none !important;
}
Is this possible without "expanding" manually the mixins inside a body.force-sm-viewport-or-higher
parent? Expanding the mixins would be very error-prone and tedious when upgrading Bootstrap.
NOTE
Here's where I found out what using the ampersand after a nested class name does: LESS CSS: abusing the & Operator when nesting?
I also need to do the same thing with this mixin which is more complicated.
.responsive-visibility() {
display: block !important;
table& { display: table; }
tr& { display: table-row !important; }
th&,
td& { display: table-cell !important; }
}
Upvotes: 2
Views: 874
Reputation: 11820
Possible solution is to provide class name to append as mixin parameter:
.responsive-invisibility(@postfix) {
@{postfix},
tr@{postfix},
th@{postfix},
td@{postfix} {display: none !important;}
}
body.force-sm-viewport-or-higher {
.responsive-invisibility(~'.visible-xs');
/* more stuff */
}
Edit: you need to define that mixin on you own, i.e. do not modify the original Bootstrap .responsive-invisibility
, then you'll be able to use both w/o conflict.
A future-proof compatible solution similar to the solution suggested in @Scotts answer (and isnpuired by it) but producing less junk:
.invisible_ {
.responsive-invisibility(); // use original Bootstrap mixin
}
.responsive-invisibility(@postfix) {
@{postfix},
tr@{postfix},
th@{postfix},
td@{postfix} {&:extend(.invisible_);}
}
body.force-sm-viewport-or-higher {
.responsive-invisibility(~'.visible-xs');
/* more stuff */
}
This way you won't have to modify invisibility styles if they do that in Bootstrap (but you still have to keep tracking the tr, th, td
list in case they change it).
Upvotes: 3
Reputation: 72261
Agree with seven-phases-max that it is not possible. I have only been able to come up with a similar workaround to his, though in this version you do not repeat the property code block from bootstrap as it still calls the original bootstrap mixin. But what it is going to do is pollute your css with a bunch of "junk" that is not needed.
Make This LESS extension
.responsive-invisibility(@selector) {
& @{selector},
& tr@{selector},
& th@{selector},
& td@{selector}{
.responsive-invisibility();
}
}
Use it "outside" the selector you intend to target like so
Note this can take a long selector string--it does not need to be just one class.
body.force-sm-viewport-or-higher {
.visible-xs {
/*visible-xs stuff*/
}
.responsive-invisibility(~'.visible-xs');
/* more stuff */
}
CSS Output (note the "junk" you get along with your desired output)
body.force-sm-viewport-or-higher {
/* more stuff */
}
body.force-sm-viewport-or-higher .visible-xs {
/*visible-xs stuff*/
}
body.force-sm-viewport-or-higher .visible-xs, //you want this
body.force-sm-viewport-or-higher tr.visible-xs, //you want this
body.force-sm-viewport-or-higher th.visible-xs, //you want this
body.force-sm-viewport-or-higher td.visible-xs, //you want this
trbody.force-sm-viewport-or-higher .visible-xs, //junk
trbody.force-sm-viewport-or-higher tr.visible-xs, //junk
trbody.force-sm-viewport-or-higher th.visible-xs, //junk
trbody.force-sm-viewport-or-higher td.visible-xs, //junk
thbody.force-sm-viewport-or-higher .visible-xs, //junk
thbody.force-sm-viewport-or-higher tr.visible-xs, //junk
thbody.force-sm-viewport-or-higher th.visible-xs, //junk
thbody.force-sm-viewport-or-higher td.visible-xs, //junk
tdbody.force-sm-viewport-or-higher .visible-xs, //junk
tdbody.force-sm-viewport-or-higher tr.visible-xs, //junk
tdbody.force-sm-viewport-or-higher th.visible-xs, //junk
tdbody.force-sm-viewport-or-higher td.visible-xs //junk
{
display: none !important;
}
This may be more "upgrade" friendly since it still ultimately calls boostrap's mixin, but it is not very friendly on the css output.
Upvotes: 3