LESS: Extend a previously defined nested selector
LESS currently does not support extending a "concatenated name" selectors (basically, .top &-first &-item
is interpreted as three distinct selector elements and never found by extend
looking for a single selector).
A workaround for your particular case:
.top {
&-first {
background: black;
}
&-second {
background: green;
}
&-first, &-second {
&-item {
color: white;
}
}
}
LESS: Extend a previously defined nested selector
LESS currently does not support extending a "concatenated name" selectors (basically, .top &-first &-item
is interpreted as three distinct selector elements and never found by extend
looking for a single selector).
A workaround for your particular case:
.top {
&-first {
background: black;
}
&-second {
background: green;
}
&-first, &-second {
&-item {
color: white;
}
}
}
Extend function doesn't work with nested selectors
Reason:
Quoting Less Website: emphasis is mine
Extend by default looks for exact match between selectors. It does matter whether selector uses leading star or not. It does not matter that two nth-expressions have the same meaning, they need to have to same form in order to be matched. The only exception are quotes in attribute selector, less knows they have the same meaning and matches them.
The following would work because the parameter to the extend
function exactly matches another selector that is already defined. (Note: I have removed some properties to keep it simple.)
.gradientBg { background: rgb(200, 200, 200); }
.gr-box, .btn-1 { &:extend(.gradientBg); }
But the below would not work because the compiled selector path of the nested selector would be .parent .gradientBg
and the parameter provided to the extend
function is not an exact match.
.parent{
.gradientBg { background: rgb(200, 200, 200); }
}
.gr-box, .btn-1 { &:extend(.gradientBg); }
Less compiler would not even throw an error in the above scenario because it fails silently when there is no match.
Solution:
When using extend
feature to extend nested selectors, an exactly matching selector (full selector path) should be provided (or) the all
keyword should be used.
The below would work as the full matching selector path is provided to the extend
function.
.parent{
.gradientBg { background: rgb(200, 200, 200); }
}
.gr-box, .btn-1 { &:extend(.parent .gradientBg); }
Or, depending on your needs even this would work because the all
keyword is used.
.parent{
.gradientBg { background: rgb(200, 200, 200); }
}
.gr-box, .btn-1 { &:extend(.gradientBg all); }
But note how the output selector has the structure .parent .gr-box
and .parent .btn-1
. This is because Less replaces only the matched part of the selector with the new selector. In .parent .gradientBg
(original selector), the matched part (provided as parameter to extend
) is only .gradientBg
and hence the output selector after extend
would be .parent .gr-box
.
Here is what the Less website says about extend "all": emphasis is mine
When you specify the all keyword last in an extend argument it tells Less to match that selector as part of another selector. The selector will be copied and the matched part of the selector only will then be replaced with the extend, making a new selector.
Another thing that should also be noted when using all
keyword is that, Less would extend properties of all selectors that have a matching part. So, for example if we consider the below Less code.
.parent{
.gradientBg { background: rgb(200, 200, 200); }
}
.parent2{
.gradientBg{ color: red; }
}
.gr-box, .btn-1 { &:extend(.gradientBg all); }
the output would be as follows because .gradientBg
selector is used both within .parent
and .parent2
.
.parent .gradientBg, .parent .gr-box, .parent .btn-1 {
background: #c8c8c8;
}
.parent2 .gradientBg, .parent2 .gr-box, .parent2 .btn-1 {
color: red;
}
extend parent and children nested selectors in less
The issue with parentChildProperty
not being applied to the ul
element can be fixed by also extending .parent-class .child-class
in the ul
styles
This will not resolve all the issues. It will still leave many unnecessary selectors in the generated CSS, but it will generate the required CSS to allow the page to display correctly.
Updated less:
.parent-class{
parentProperty: value;
.child-class { parentChildProperty: value; }
}
.child-class {
childProperty:value;
& > li{ childLiProperty:value; }
}
nav{
&:extend(.parent-class all);
ul{
&:extend(.child-class all);
&:extend(.parent-class .child-class);
}
}
Does LESS have an extend feature?
Yes, Less.js introduced extend
in v1.4.0.
:extend()
Rather than implementing the at-rule (@extend
) syntax used by SASS and Stylus, LESS implemented the pseudo-class syntax, which gives LESS's implementation the flexibility to be applied either directly to a selector itself, or inside a statement. So both of these will work:
.sidenav:extend(.nav) {...}
or
.sidenav {
&:extend(.nav);
...
}
Additionally, you can use the all
directive to extend "nested" classes as well:
.sidenav:extend(.nav all){};
And you can add a comma-separated list of classes you wish to extend:
.global-nav {
&:extend(.navbar, .nav all, .navbar-fixed-top all, .navbar-inverse);
height: 70px;
}
When extending nested selectors you should notice the differences:
nested selectors .selector1
and selector2
:
.selector1 {
property1: a;
.selector2 {
property2: b;
}
}
Now .selector3:extend(.selector1 .selector2){};
outputs:
.selector1 {
property1: a;
}
.selector1 .selector2,
.selector3 {
property2: b;
}
, .selector3:extend(.selector1 all){};
outputs:
.selector1,
.selector3 {
property1: a;
}
.selector1 .selector2,
.selector3 .selector2 {
property2: b;
}
,.selector3:extend(.selector2){};
outputs
.selector1 {
property1: a;
}
.selector1 .selector2 {
property2: b;
}
and finally .selector3:extend(.selector2 all){};
:
.selector1 {
property1: a;
}
.selector1 .selector2,
.selector1 .selector3 {
property2: b;
}
Extending nested selectors in LESS
With the requirements you listed you will want to do something like this:
.table tr {
&:hover {
color: red;
.c1, .c2, .c3 {
color: green;
}
}
}
Think of &
as anything you want to be at the same level as the parent level, whether it be a class
or a pseudo class
.
When you nest items usually it matches the HTML structure/hierarchy so deciding how and where to nest is fairly straightforward. You want to share as much as possible without going overboard in getting to "nested hell".
LESS: How to fully extend two classes when relationships between both of them exist
The all
option will add the new selector to all the hierarchical relationships / nested selectors that already exist.
So, in the nested selector .parent .child
when extending .parent
with .newParent
it will extend the nested selector with .newParent .child
, because this relationship with .child
has been defined. When extending .child
with .newChild
, the nested selector gets extended by .parent .newChild
, because the relationship between .child
and .parent
exists. And you end up with this CSS:
.parent .child,
.newParent .child,
.parent .newChild {
color: white;
}
Note: This does not create selectors based on nested selectors created with the extension. Prior to the extension there is neither a definition of .newParent .child
nor is there one of .parent .newChild
, which could result in .newParent .newChild
being created after the rule extension.
I am not completely sure how exacty you want your CSS output to look like, but you can always extend the "relationship"/combined/nested selector as well and avoid the all
option, so that you don't generate all the hybrid selectors (like .parent .newChild
and .newParent child
):
.newParent {
&:extend(.parent);
}
.newChild {
&:extend(.child);
}
.newParent .newChild {
&:extend(.parent .child);
}
or in a nested form:
.newChild {
&:extend(.child);
}
.newParent {
&:extend(.parent);
.newChild {
&:extend(.parent .child);
}
}
and the CSS output will be:
.parent,
.newParent {
color: blue;
}
.child,
.newChild {
color: red;
}
.parent .child,
.newParent .newChild {
color: white;
}
If desired, you can now simply add all the nested selector combinationsh by adding the all
option. This will get you all the permutations of the selectors, and acchieve this CSS:
.parent,
.newParent {
color: blue;
}
.child,
.newChild {
color: red;
}
.parent .child,
.parent .newChild,
.newParent .child,
.newParent .newChild {
color: white;
}
Less CSS :extend() doesn't work when an extra selector is attached to parent selector
There is a primary difference between the two extend modes that are given in the question and that is why one works while the other doesn't.
The first method (extending using parent selector (&
)) is generally used by placing it within another selector block like:
.test{
a:a
}
#dummy{
&:extend(.test all);
}
This is called as Extend inside Ruleset and this generally does not require the curly braces {}
at the end of the line. In fact, for this aproach, an error would be thrown only when the braces are provided.
The second method is called as Extend attached to a selector because here a new selector is being created by attaching an extra class to the parent selector and for this approach the curly braces are required mandatorily at the end. Compilation error would be thrown otherwise.
Including the curly braces like in the below snippet would cause the code to compile properly:
.test{
a:a
}
#dummy{
&.a_class:extend(.test all){};
}
In my opinion, curly braces are required for the 2nd method and not the 1st because without braces, the 2nd one is generally not how we write the rules in CSS - where every selector must have a body ({}
) to contain its rules. The first selector already has its body because the extend itself is placed within it.
Related Topics
Css-Moving Text from Left to Right
How to Use Commas in a CSS Variable Fallback
Lesscss Stops Processing Styles
Zoom Out Shiny App at Default in Browser
Sass Extend and Parent Selector
How to Make a Button Stretch Across the Width of a Column
How to Get Multiple Borders with Rounded Corners? CSS
Why Bootstrap 3 Navbar Dropdown Doesn't Work in IE8
CSS Transition on an Initially Hidden Elemement
How to Get Attribute Value Using Selenium and CSS
CSS -Moz-Available Equivalent in Webkit
How to Rotate Clip Path Without Rotating Image
Using Less Variables in Media Queries
Position: Sticky (Firefox) on a <Table> Element
Dotted/Dashed Circle Shapes Using CSS - Not Rendering Right in Chrome