set parent selector as a variable - less

div .mymixin('red','green')
.mymixin(#a, #b){
a {
color: #a;
span {
color: #b;
}
}
}
This code will produce the following css:
div a{color:red;}
div a span{color: green;}
I need it to produce this:
div a{color:red;}
div:not(.open) a span{color: green;}
I was trying to do something like this:
div .mymixin('red','green')
#parent: &;
.mymixin(#a, #b){
a {
color: #a;
#{parent}:not(.open) span {
color: #b;
}
}
}
But it doesn't work the right way, producing
div a &:not(.open) span{color:green;}
Is there a way to assign parent to a variable or do it some other way to achieve what I am after?
Thank you.
P.S. Here is the actual nesting I have:
.icfld(#name, #width, #height, #opacity, #open) {
> a {
...
> .icon {
...
}
&.disabled > .icon {
...
}
//&:not(.open) :not(.disabled):hover... will NOT work, because & at this point refers to
//"parent" > a and makes it "parent" > a:not(.open), while I need "parent":not(.open)
//the following line, however, works
&:not(.disabled):hover {
& when (#open=false) {
...
> .icon {
...
}
}
}
}

Came up with the following work around:
.mymixin2(#a, #b, #open){
a {
color: #a;
& when(#open = false){
span {
color: #b;
}
}
}
}
.mymixin1(#a,#b){
&.open {.mymixin2(#a,#b,true);}
&:not(.open) {.mymixin2(#a,#b,false);}
}
div .mymixin1('red', 'green');
This seems to do the trick.

Related

How do I force line break in donut chart label?

I'm using C3 donut chart,
But the label is too long and I need a word-break like feature.
So I tried to set the following properties, non of them works
axis: {
x: {
tick: {
width: 100
}
}
},
legend: {
maxWidth: 100px;
},
Any ideas?
UPDATE
The tooltip.format.name function can partially solve this problem. But I'm unable to add newline here, tried "\n", <br/> and
tooltip: {
format: {
name: function (name, ratio, id, index) {
if (name.length > 70) {
return name.substr(0, 70) + ' 
 ...'
} else {
return name
}
}
}
}

Can't define reusable comma separated selector lists in Less

Consider the following Less code:
.a {
button,
input[type='button'],
input[type='submit'],
input[type='reset'] {
background: red;
}
}
.b {
button,
input[type='button'],
input[type='submit'],
input[type='reset'] {
background: blue;
}
}
What I'd like to be able to do is define the four possible types of buttons in a reusable way. I used to be able to do this easily in SASS, but have switched to Less in order to use Semantic UI. I can't find a syntax to do this in Less - is it possible?
Okay, I have a solution to this now, derived from this post:
#all-buttons: {
button,
input[type='button'],
input[type='reset'],
input[type='submit'] {
.get-props()
}
};
.set-props(#selectors; #rules; #extension: ~'') {
#selectors();
.get-props() {
&#{extension} { #rules(); }
}
}
.all-buttons(#rules; #extension: ~'') {
.set-props(#all-buttons; #rules; #extension);
}
.a {
.all-buttons({
background: red;
});
}
.b {
.all-buttons({
background: blue;
});
}
// Also enables an extension such as a pseudo selector for each button type
.c {
.all-buttons({
background: green;
}, ~':hover');
}

Why cannot we use ruleset within the same ruleset?

I am trying to use the same .formater() ruleset within itself.
I am getting syntax error.
Why cannot we use a ruleset within itself?
.formater(#className;#rules){
.#{className}{
#rules();
}
}
.formater(mainContainer;{
display:block;
line-height:2em;
& a{
colour: blue;
&.formater(link;{
colour:red;
});
}
});
Any help would be appreciated.
The reason for the syntax error is because you are appending & to a mixin call which is not allowed. & can be attached only to selectors. If you remove the & from before the mixin call then your code would compile fine.
.formater(#className; #rules){
.#{className}{
#rules();
}
}
.formater(mainContainer; {
display:block;
line-height:2em;
& a{
colour: blue;
.formater(link; {
colour:red;
});
}
});
The above Less code when compiled would produce the following CSS:
.mainContainer {
display: block;
line-height: 2em;
}
.mainContainer a {
colour: blue;
}
.mainContainer a .link {
colour: red;
}
As you would have noticed, the final selector that is output above is .mainContainer a .link and not .mainContainer a.link. If you are trying to achieve the latter then one option would be for you to add the & within the .formater mixin's code itself.
.formater(#className; #rules) {
&.#{className} {
#rules();
}
}
I wouldn't really recommend using the below option but if you need the .formater() mixin to support both variations then you could use a variable along with guard conditions and use as appropriate.
.formater(#className; #rules; #parent-append: false) {
& when not (#parent-append = false) {
&.#{className} {
#rules();
}
}
& when (#parent-append = false) {
.#{className} {
#rules();
}
}
}
You can then call the mixin as
.formater(link; {colour:red;}; true); /* if & should be appended */
or
.formater(link; {colour:red;};); /* if & need not be appended */

Less adds unexpected space to variable

For some reason, the output of nth child is rendered with un unexpected space. Can anyone help?
Renders:
// Part of render
body.domain-bsci-fta-local #block-domain-switcher ul li:nth-child( 3) {
background-color: #e14313;
}
From code:
// Variables
#a-primary: #018f9e;
#b-primary: #2b6a7c;
#c-primary: #e14313;
#d-primary: #009966;
#domain-a: 'a-local';
#domain-b: 'b-fta-local';
#domain-c: 'c-fta-local';
#domain-d: 'd-fta-local';
#domains: #domain-a #a-primary 1, #domain-b #b-primary 2, #domain-c #c-primary 3, #domain-d #d-primary 4;
// Call
body {
.generate-menus();
}
// Functions
.generate-menus() {
.for(#domains);
.-each(#domain) {
#dn: e(extract(#domain, 1));
#dc: extract(#domain, 2);
#dr: extract(#domain,3);
.generate-menu(#dn, #dc, #dr);
}
}
.generate-menu(#domainname, #domaincolor, #domaincount) {
&.domain-#{domainname} {
#block-domain-switcher {
ul {
li {
&:nth-child(#{domaincount}) {
background-color: #domaincolor;
a {
border-bottom: 5px solid;
color: white !important;
}
}
}
}
}
.navigation .submenu {
background-color: #domaincolor;
}
}
}
// ............................................................
// .for
.for(#i, #n) {
.-each(#i)
}
.for(#n) when (isnumber(#n)) {
.for(1, #n)
}
.for(#i, #n) when not (#i = #n) {
.for((#i + (#n - #i) / abs(#n - #i)), #n);
}
// ............................................................
// .for-each
.for(#array) when (default()) {
.for-impl_(length(#array))
}
.for-impl_(#i) when (#i > 1) {
.for-impl_((#i - 1))
}
.for-impl_(#i) when (#i > 0) {
.-each(extract(#array, #i))
}
Note: As mentioned by seven-phases-max in his comments to the question, this was a bug which has already been fixed in v2.x. Leaving this answer (with the work-around solution) as-is to help future readers who can't upgrade their compiler for whatever reason.
The problem happens only for selectors which use selector interpolation and are nested within one or more parent selectors. It can be solved by using a temporary variable which contains the pseudo-selector like below: (it uses escaped string feature)
Option 1:
ul {
li {
#selector: ~":nth-child(#{domaincount})"; /* the selector is formed here */
&#{selector} { /* and used here */
background-color: #domaincolor;
a {
border-bottom: 5px solid;
color: white !important;
}
}
}
}
Option 2:
li {
#count: ~"(#{domaincount})";
&:nth-child#{count} { /* and used here */
background-color: #domaincolor;
a {
border-bottom: 5px solid;
color: white !important;
}
}
}
Sample Compiled Output:
body.domain-a-local #block-domain-switcher ul li:nth-child(1) {
background-color: #018f9e;
}
Related Links:
concatenate values in less (css) without a space
Redudant space in interpolated selectors like nth(...)
As mentioned above and in the linked issue thread, the issue happens only when the selector is formed using selector interpolation and is nested under one or more parents.
This works
// Variables
#list: a 1;
#num: extract(#list, 2);
// Usage
body div:nth-child(#{num}) {
color: #444;
}
But this doesnt
// Variables
#list: a 1;
#num: extract(#list, 2);
// Usage
body {
div:nth-child(#{num}) {
color: #444;
}
}

LESS Preprocessing and null arguments?

This might be difficult to explain. Is there a way to have less not write out the #child argument without overloading the mix-in? I really don't want two mix-ins. If I use "" double quotes are outputted. I would like the LESS compiler to leave it blank.
LESS CODE
.build-on(size, #child)
{
&--1-1 #{child}
{
width: 100%;
}
&--1-2 #{child}
{
width: 50.0%;
}
&--1-3 #{child}
{
width: 33.3%;
}
&--1-4 #{child}
{
width: 25.0%;
}
&--1-5 #{child}
{
width: 20.0%;
}
}
// I might need to provide a child element
.data-table
{
.build-on(size, table);
}
// I might not
.grid
{
.build-on(size, "");
}
Pass it like so:
.yourClass
{
.build-on(size, ~'');
}
Or Better Yet...
Define a default: .build-on(size, #child: ~'') { ... } then no second is needed:
.yourClass
{
.build-on(size);
}