Does LESS have an "extend" feature? - css

SASS has a feature called #extend which allows a selector to inherit the properties of another selector, but without copying the properties (like mixins).
Does LESS have this feature as well?

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;
}

Easy way to extend a function in Less framework
.sibling-1 {
color: red
}
.sibling-2 {
background-color: #fff;
.sibling-1();
}
Output
.sibling-1 {
color: red
}
.sibling-2 {
background-color: #fff;
color: red
}
Refer https://codepen.io/sprushika/pen/MVZoGB/

Less allows us to do :extend(.class) or :extend(#id)

Related

The Sass ampersand and attribute selectors

I want to create a sass file that the selectors will be attribute selectors.
When I work with class selectors, in most of the cases I will do
.parent {
&-child {
}
}
which gives me the following css: .parent-child {}.
I want to achieve the same thing with attribute selectors:
[data-parent] {
&-child {
}
}
which I want to become: [data-parent-child] {}
someone knows how to achieve this? thanks.
You can use this mixin as a workaround to get the desired result.
#mixin child-attribute($child) {
$string: inspect(&);
$original: str-slice($string, 3, -4);
#at-root #{ selector-replace(&, &, "[#{$original}#{$child}]" ) } {
#content;
}
}
The code simply does the following
$string variable is responsible for turning the parent selector to a string using the inspect function
$original variable is responsible for getting the text content of the $string variable i.e the value 'data-parent' from '([data-parent])'
selector-replace function then replaces the parent selector with the concatenation of the $original variable and child variable
When used in the following ways
[data-parent] {
#include child-attribute('-child') {
color: green;
}
}
The css output
[data-parent-child] {
color: green;
}
Depending on what you want to achieve, it can also be used like this
[grandparent] {
#include child-attribute('-parent') {
color: white;
#include child-attribute('-child') {
color: blue;
}
}
}
Which generates the following css
[grandparent-parent] {
color: white;
}
[grandparent-parent-child] {
color: blue;
}
Hope this helps you
You can create mixin that will set styles for elements with data attribytes.
Scss:
#mixin data($name) {
[data-#{$name}] {
#content;
}
}
* {
#include data('lol') {
color: red;
};
}
Css output:
* [data-lol] {
color: red;
}
DEMO
I would go down a slightly different route of having a class on your elements that contain the data attributes.
<div class="data-obj" data-parent="true"></div>
<div class="data-obj" data-parent-child="true"></div>
then in your SASS do
.data-obj {
...
&[data-parent] { ... }
&[data-parent-child] { ... }
}

How can I create a Sass mixin with a class as a variable

I am trying to write something like this :
#mixin variableChild($child:".theChild") {
//some css
$child {
//css specific to the child
}
}
#parent { #include variableChild(".specificChild"); };
So it would generate this CSS :
#parent {//some css}
#parent .specificChild {
//css specific to the child
}
You were almost right, you just missed the #{} around your child selector I think. There’s more information about it in the Sass documentation.
#mixin variableChild($child:".theChild") {
#{$child} {
color: red;
}
}
#parent {
#include variableChild(".specificChild");
};
http://jsfiddle.net/UrLdB/

Multiple two-class selectors in Sass

Having multiple two-class selectors for a single declaration block, is it possible to simplify the following (i.e. not having to repeat the body tag):
body.shop, body.contact, body.about, body.faq {background-color:#fff;}
try this:
body{
&.shop, &.contact, &.about, &.faq {
background-color:#fff;
}
}
In this case we can use #each directive:
$pages: shop, contact, about, faq;
body {
#each $page in $pages {
&.#{$page} {
background-color:#FFF;
}
}
}
sassmeister.com
body {
&.shop, &.contact {
// Styles here...
}
}
If you are using sass compiled by the node, that may do.
body {
.shop, .contact, .about, .faq {
background-color:#FFFFFF;
}
}
Parent child relationship in sass
parent_tag {
.child {
// rules here
}
}

SASS function for #extend

What I'm trying to achieve, is simply a shorter version of the #extend function in sass.
I have a heap of classes which I use all over my site for layout.
Example:
.grid1 {width:40px;}
.grid2 {width:80px;}
.grid3 {width:120px;}
.grid4 {width:160px;}
.grid5 {width:200px;}
I know you can use the extend function to remove duplicate css all over the site with:
.class {#extend .grid1}
which would output
.class {width:40px}
What I'm after is something a little more simple.
.class{grid(1)};
Here's what I've tried:
#function grid($n){
#extend unquote(".grid#{$n}");
}
Obviously this doesn't work, any ideas?
#functions in SASS are meant to be used to manipulate values. So the reason why this will not work is due to the fact that you are trying to return selectors and declaration blocks. This is what mixins are for.
One way of doing this would be:
$grids: ((5, 40), (10, 80), (15, 120), (20, 160));
#mixin grid($n, $fluid: false) {
#if($fluid) {
width: nth(nth($grids, $n), 1) + "%";
} #else {
width: nth(nth($grids, $n), 2) + "px";
}
}
.foo {
#include grid(3);
}
.bar {
#include grid(4, true);
}
Which produces:
.foo {
width: "120px"; }
.bar {
width: "20%"; }

Sass #extend sibling selector referencing parent selector (ampersand)

I'm trying to accomplish the following CSS output with Sass:
.selector1 + .selector1, .selector2 + .selector2 {
margin-top: -80px;
}
The #extend functionality should do the job:
%sibling-selector {
& + & {
margin-top: -80px;
}
}
.selector1 {
#extend %sibling-selector;
}
.selector2 {
#extend %sibling-selector;
}
But it seems the extend function has problems with the two parent references (&) in the extend only class definition (%sibling-selector).
This is the output:
.selector1 + .selector1, .selector2 + .selector1,
.selector1 + .selector2, .selector2 + .selector2 {
margin-top: -80px;
}
So the #extend function is making sibling selectors for each combination of selectors that use the #extend definition.
While I would expect the #extend stays in the "scope" of the current selector, and so the ampersand is replaced by the current selector.
Is this a bug or a feature? :-)
I know I could use a mixin for this job,
#mixin sibling-selector {
& + & {
margin-top: -80px;
}
}
.selector1 {
#include sibling-selector;
}
.selector2 {
#include sibling-selector;
}
but that would create duplicate CSS definitions:
.selector1 + .selector1 {
margin-top: -80px;
}
.selector2 + .selector2 {
margin-top: -80px;
}
Is there a way to get it right with Sass?
It seems #extend is not the way to get the wanted result: https://github.com/nex3/sass/issues/848#issuecomment-20903684
So to "automate" the creation of the sibling selectors I've used a small #each loop to create a list of selectors.
$siblingSelectors: ();
#each $selector in selector1 selector2 selector3 {
$classSelector: unquote('.prefix-' + $selector);
$siblingSelectors: append($siblingSelectors, unquote($classSelector + ' + ' + $classSelector), comma);
}
#{$siblingSelectors} {
margin-top: 80px;
&.large {
margin-top: -100px;
}
}
Which gives the following result:
.prefix-selector1 + .prefix-selector1, .prefix-selector2 + .prefix-selector2 {
margin-top: -80px;
}
.prefix-selector1 + .prefix-selector1.large, .prefix-selector2 + .prefix-selector2.large {
margin-top: -100px;
}

Resources