Alter LESS Mixin when body class is present? - less

I have a LESS mixin. When a certain body class is present I want to alter one value of the mixin.
.my-style() {
font-weight: bold;
color: red;
}
.my-style-altered() {
color: blue;
}
.element {
.my-style;
}
.body-class .element {
.my-style-altered;
}
This is working fine. However my list of selectors is getting longer:
.my-style() {
font-weight: bold;
color: red;
}
.my-style-altered() {
color: blue;
}
.element,
.element-2,
.element-3 {
.my-style;
}
.body-class .element,
.body-class .element-2,
.body-class .element-3 {
.my-style-altered;
}
Is there a smarter way of writing my list of selectors so I dont have to repeat them twice? Ideally I would write them once, and for all of them my-style-altered() would be also applied if .body-class is present.

Method 1: (Using different mixins for the base version and the body-class specific version)
Yes, you could avoid having to write all the selectors multiple times by nesting the .body-class * variants of the selector within the generic one and appending the parent selector like in the below snippet. When this code is compiled, Less compiler will automatically replace the & with each one of the parent selectors.
.my-style() {
font-weight: bold;
color: red;
}
.my-style-altered() {
color: blue;
}
.element, .element-2, .element-3 {
.my-style;
.body-class &{
.my-style-altered;
}
}
Compiled CSS:
.element, .element-2, .element-3 {
font-weight: bold;
color: red;
}
.body-class .element,
.body-class .element-2,
.body-class .element-3 {
color: blue;
}
Method 2: (Using same mixin for the base version and the body-class specific version)
Alternately, if you wish to avoid having to use two different mixins and output both the content (the default one and the .body-class * variant) through the same mixin, it can be done like below:
.mixin() {
font-weight: bold;
color: red;
.body-class &{
color: blue;
}
}
.element, .element-2 {
.mixin()
}

Related

Generate rules via LESS plugin

I'd like to write a plugin that can generate a LESS function named alt that can do the following transformation:
.button {
background-color: alt(red, blue);
color: alt(black, white);
}
And output the following:
.button {
background-color: red;
color: black;
body.alt & {
background-color: blue;
color: white;
}
}
There doesn't seem to be much documentation about writing LESS plugins on the site, so hoping someone can provide an example of how this might be written :) Thanks!
I think a mixin would be best for this. Something like the following LESS:
.alt(#property, #primary-color, #alternate-color) {
#{property}: #primary-color;
body.alt & {
#{property}: #alternate-color;
}
}
.button {
.alt(background-color, red, blue);
.alt(color, black, white);
}
Which will compile to the following CSS:
.button {
background-color: red;
color: black;
}
body.alt .button {
background-color: blue;
}
body.alt .button {
color: white;
}

Less: class then node type

I have two <p> and one <button> that extend a certain class named test. I want to know if it is possible to add certain style rules to .test and then specific rules for the element type?
I thought of something like this:
.test {
font-weight: bold;
color: blue;
&p {
font-size: 26px;
}
&button {
font-size: 20px;
}
}
I know it is impossible to write it like that. This example is only for a concept example.
I've read the documentation and alas i found nothing...
Any idea or is this just impossible to achieve?
If I understand correctly you should use :extend:
LESS:
.test {
font-weight: bold;
color: blue;
}
p:extend(.test) {
font-size: 26px;
}
button:extend(.test){
font-size: 20px;
}
Output:
.test, p, button {
font-weight: bold;
color: blue;
}
p {
font-size: 26px;
}
button {
font-size: 20px;
}

Extend in Less like it Sass can

I like to use :extend() in Less like I can do it in Sass.
Example in SCSS: http://codepen.io/Grawl/pen/qEeQPG
Example in Less: http://codepen.io/Grawl/pen/qEeQpz (not worked)
Expected output:
.datalist-item {
display: block;
}
.datalist-item-term {
font-weight: normal;
}
.datalist-item-description {
font-weight: bold;
}
.datalist-float .datalist-item {
display: inline-block;
}
.datalist-float .datalist-item:not(:last-of-type) {
margin-right: 1em;
padding-right: 1em;
border-right: 1px solid;
}
The purpose is to not self-repeat, so if I rename one class in Sass I have not to rename others.
I know I can put root class in a variable and use it twice with it http://codepen.io/Grawl/pen/qEeQpz but it looks ugly :(
Your Sass (SCSS) example uses #extend-Only Selectors which is some special form of extending which does not exists in Less.
Firstly a "normal" extend:
SCSS:
.class {
p: 1;
}
.class2 {
#extend .class;
}
and Less:
.class {
p: 1;
}
.class2 {
&:extend(.class);
}
both compile into:
.class,
.class2 {
p: 1;
}
In Less .class2 { &:extend(.class); } can also be written as .class2:extend(.class1){}
Now consider the following SCSS code which uses #extend-Only Selectors:
%class {
p: 1;
}
.class2 {
#extend %class;
}
The preceding code compile into CSS code as follows:
.class2 {
p: 1; }
Sass documentation tells you:
#extend-Only Selectors
Sometimes you’ll write styles for a class that you only ever want to
#extend, and never want to use directly in your HTML. This is
especially true when writing a Sass library, where you may provide
styles for users to #extend if they need and ignore if they don’t.
If you use normal classes for this, you end up creating a lot of extra
CSS when the stylesheets are generated, and run the risk of colliding
with other classes that are being used in the HTML. That’s why Sass
supports “placeholder selectors” (for example, %foo).
Placeholder selectors look like class and id selectors, except the #
or . is replaced by %. They can be used anywhere a class or id could,
and on their own they prevent rulesets from being rendered to CSS.
In Less you will have two options to have code that does not generate output:
1) use a mixin, mixins do not generate output:
.class() {
p: 1;
}
.class2 {
.class();
}
outputs:
.class2 {
p: 1;
}
2) put your classes which should not output in a different file and import this file with the reference kewyword:
file1.less:
.class {
p: 1;
}
file2.less:
#import (reference) "file1";
.class2 {
&:extend(.class);
}
lessc file2.less will output now:
.class2 {
p: 1;
}
But i agree with #seven-phases-max in the comments in the first place. In your example there is no need to use extend. #seven-phases-max shows you some examples to solve this use case. Alternatively you can consider; changing selector order with parent reference, which should work in both Less and SASS:
.datalist-item {
display: block;
&-term {
font-weight: normal;
}
&-description {
font-weight: bold;
}
.datalist-float & {
display: inline-block;
&:not(:last-of-type) {
margin-right: 1em;
padding-right: 1em;
border-right: 1px solid;
}
}
}
Compile into:
.datalist-item {
display: block;
}
.datalist-item-term {
font-weight: normal;
}
.datalist-item-description {
font-weight: bold;
}
.datalist-float .datalist-item {
display: inline-block;
}
.datalist-float .datalist-item:not(:last-of-type) {
margin-right: 1em;
padding-right: 1em;
border-right: 1px solid;
}
Finally notice that you are using nesting of properties such as:
border: {
right: 1px solid;
};
which should compile into:
border-right {
1px solid;
}
Less does NOT support nesting of properties.

Alter CSS applied by LESS Mixin when body class is present?

I have a LESS mixin. When I apply this to an element I want it be styled slightly differently if a body class is present.
This:
.mixin() {
font-weight: bold;
color: red;
}
.element {
.mixin()
}
Outputs to this:
.element {
font-weight: bold;
color: red;
}
But I also want this to be outputted:
.body-class .element {
color: blue;
}
You can define your mixin this way:
.mixin() {
font-weight: bold;
color: red;
.body-class & {
color: blue;
}
}

Inherit from a Class Which Name Is Composed Using the `&` character in Less

How can I inherit from a class which name is composed using the & character (e.g. &-rule), please?
Desired Output
.prefix-rule-extended,
.prefix-rule {
color: white;
}
.prefix-rule-extended {
background-color: black;
}
or
.prefix-rule {
color: white;
}
.prefix-rule-extended {
color: white;
background-color: black;
}
Non-working Approaches
.prefix {
&-rule {
color: white;
}
}
plus
.prefix-rule-extended:extend(.prefix-rule) {
background-color: black;
}
or
.prefix-rule-extended {
.prefix-rule();
background-color: black;
}
Ideal Approach
.prefix {
&-rule {
color: white;
}
&-rule-extended:extend(&-rule) {
background-color: black;
}
}
Note 1: I know :extend(&-rule) is currently not supported.
Note 2: .prefix-rule is not so simple, i.a. there are nested rules inside so the following will not work:
.prefix {
&-rule {
color: white;
&-extended {
background-color: black;
}
}
}
Thank you.
(Ok, so as always to not leave this one w/o an answer - a summary of comments above):
Currently it's impossible to extend that kind of things. For the moment extend can't match selector identifiers generated via "concatenation" so .prefix {&.rule { ... would be a valid extend target (as it's "two elements" -> "two identifiers") but .prefix {&-rule { ... won't (since it's "two elements" -> "one identifier").
So if you plan to use extend don't be keen on such kind of nesting, keep it more simple.
Here are three valid Less snippets (each having its pros and cons) to get the desired CSS output.
1:
.prefix-rule {
color: white;
&-extended:extend(.prefix-rule) {
background-color: black;
}
}
2:
.prefix-rule {
&, &-extended {
color: white;
}
&-extended {
background-color: black;
}
}
3:
.rule-base {
color: white;
}
.prefix-rule {
&:extend(.rule-base);
&-extended:extend(.rule-base) {
background-color: black;
}
}