How do I extend a class/mixin which has dynamically formed selector
Extending a dynamically formed selector (loosely using the term) like that is currently not possible in Less. There is an open feature request to support this. Till it is implemented, here are two work-around solutions to it.
Option 1:
Write the contents of .hello
and .hello-world
selectors into a separate Less file (say test.less
), compile it to get the CSS. Create another file for the rules of .foo
, import the compiled CSS as a Less file (using the (less)
directive) and then extend the .hello-world
as you had originally intended to.
test.less:
.hello {
&-world {
color: red;
}
}
extended-rule.less:
@import (less) "test.css";
.foo {
&:extend(.hello-world);
font-size: 20px;
}
Compiled CSS:
.hello-world,
.foo {
color: red;
}
.foo {
font-size: 20px;
}
This method would work because by the time the test.css
file is imported, the selector is already formed and is no longer dynamic. The drawback is that it needs one extra file and creates dependency.
Option 2:
Write a dummy selector with rules for all properties that need to be applied to both .hello-world
and .foo
and extend it like:
.dummy{
color: red;
}
.hello {
&-world:extend(.dummy) {};
}
.foo:extend(.dummy){
font-size: 20px;
}
This creates one extra selector (dummy) but is not a big difference.
Note: Adding my comment as an answer so as to not leave the question unanswered and also because the work-around specified in the thread linked in comments doesn't work for me as-is.
Extending a class that its name is generated in a mixin
You could do the following to extend a class that was generated in a mixin:
@mixin classGenerator {
.error {
color: red;
font-size: 9px;
}
}
@include classGenerator;
.seriousError {
@extend .error;
font-size: 20px;
}
EDIT
According to the changes in your question:
@mixin errorLevels($x){
.level-#{$x} {
font-size: #{12 + $x}px
}
}
@include errorLevels(1);
.seriousError {
@extend .level-1;
}
Is there any (good) way to extend a class within a mixin, and then use that mixin within a media query, using Less?
In short, yes, currently it is somewhat possible but requires some additional wrapping for a top level classes:
// extensions.less
.block {
display: block;
}
// mixins.less
@import (reference) "extensions";
.mixin() {
&:extend(.block);
margin: auto;
}
// styles.less
@media all { // !
@import "mixins";
.element1 {
.mixin();
}
.element2 {
.mixin();
}
}
@media only screen and (max-width: 768px) {
@import (multiple) "mixins";
.element3 {
.mixin();
}
.element4 {
.mixin();
}
}
.element1
and .element2
(and any other class to extend .block
) have to be put into @media all
because currently:
Top level extend matches everything including selectors inside nested media
So if .element1
and .element2
stay in the global scope they leak into every other @media
.block
declaration.
(Hmm, actually for me this "top level extend matches everything" thing looks questionable and contradicts another "extend inside a media declaration should match only selectors inside the same media declaration" rule (obviously because global scope = @media all
thus they should work identically)).
How do I extend a class/mixin which has dynamically formed selector
Extending a dynamically formed selector (loosely using the term) like that is currently not possible in Less. There is an open feature request to support this. Till it is implemented, here are two work-around solutions to it.
Option 1:
Write the contents of .hello
and .hello-world
selectors into a separate Less file (say test.less
), compile it to get the CSS. Create another file for the rules of .foo
, import the compiled CSS as a Less file (using the (less)
directive) and then extend the .hello-world
as you had originally intended to.
test.less:
.hello {
&-world {
color: red;
}
}
extended-rule.less:
@import (less) "test.css";
.foo {
&:extend(.hello-world);
font-size: 20px;
}
Compiled CSS:
.hello-world,
.foo {
color: red;
}
.foo {
font-size: 20px;
}
This method would work because by the time the test.css
file is imported, the selector is already formed and is no longer dynamic. The drawback is that it needs one extra file and creates dependency.
Option 2:
Write a dummy selector with rules for all properties that need to be applied to both .hello-world
and .foo
and extend it like:
.dummy{
color: red;
}
.hello {
&-world:extend(.dummy) {};
}
.foo:extend(.dummy){
font-size: 20px;
}
This creates one extra selector (dummy) but is not a big difference.
Note: Adding my comment as an answer so as to not leave the question unanswered and also because the work-around specified in the thread linked in comments doesn't work for me as-is.
use variables on mixin or extend in Less.js
You are trying to call a mixin using selector interpolation, which is not possible.
As for extend, Less documentation states it clearly:
Extend is NOT able to match selectors with variables. If selector contains variable, extend will ignore it.
Related Topics
Css3 ::Selection Behaves Differently in Ff & Chrome
Is There Any Pros and Cons If I Use Always CSS Class Instead CSS Id for Everything
Scss Extend a Nested Selector and Override the Nested Rulesets
Background Color of Tabs in Shiny Tabpanel
Vertically Centering Content of :Before/:After Pseudo-Elements
Newline Character Sequence in CSS 'Content' Property
CSS How to Make an Element Fade in and Then Fade Out
Is There a 'Box-Shadow-Color' Property
Zoom Control and Streetview Not Showing on My Google Map
Zebra Striping a Table with Hidden Rows Using CSS3
How to Render Multiple Columns with Markdown in Github Readme
Sass @Each Variable Interpolation
Build List of Selectors with Less
Bootstrap 4 Navbar and Content Fill Height Flexbox