Extract value from variable - css

I just want to ask if it is possible in LESSCSS to use the extract function while the value is stored in LESS Variable?
This is what I'm using:
#basic: #ffffff, #000000, #333333;
#classes: white, black, gray;
.make-color(#i: length(#basic)) when (#i > 0) {
.make-color(#i - 1);
#color: extract(#basic, #i);
#class: extract(#classes, #i);
.#{class} {
color: #color;
}
}
}
This is what I want
#white: #ffffff;
#black: #000000;
#gray: #333333;
#basic: #white, #black, #gray;
#classes: white, black, gray;
.make-color(#i: length(#basic)) when (#i > 0) {
.make-color(#i - 1);
#color: extract(#basic, #i);
#class: extract(#classes, #i);
.#{class} {
color: #color;
}
}
}
When I tried the second one it returns a compiled css like this:
.white{
color: #white;
}
.black{
color: #black;
}
.gray{
color: #gray;
}
but my target is like this:
.white{
color: #ffffff;
}
.black{
color: #000000;
}
.gray{
color: #333333;
}

Related

Removing quotes from selector names when generating styles with Less mixin

I'm working on a legacy project that uses an old version of Less, and moving off it isn't an option anytime soon. I'm refactoring some repetitive theming and I've been trying to use Less mixins to help, but I'm a little stuck, and Less isn't something I've used to any great extent.
I've defined the following themes and mixin:
#theme-green: #91ab7a;
#theme-green-text: #fff;
#theme-yellow: #efdf91;
#theme-yellow-text: #00395d;
#theme-red: #722d3d;
#theme-red-text: #fff;
#theme-brown: #a9a196;
#theme-brown-text: #fff;
#theme-grey: #f3f3f3;
#theme-grey-text: #00395d;
#theme-darkBlue: #00395d;
#theme-darkBlue-text: #fff;
#theme-default: #theme-darkBlue;
#theme-default-text: #theme-darkBlue-text;
#theme-navyBlue: #007db5;
#theme-navyBlue-text: #fff;
#theme-cyan: #00adee;
#theme-cyan-text: #fff;
#theme-lightBlue: #b1e7ff;
#theme-lightBlue-text: #00395d;
#themes: 'green' 'yellow' 'red' 'brown' 'grey' 'darkBlue' 'navyBlue' 'cyan' 'lightBlue' 'default';
#themes-light: 'grey' 'lightBlue';
#themes-dark: 'green' 'yellow' 'red' 'brown' 'darkBlue' 'navyBlue' 'cyan' 'default';
#theme-count: length(#themes);
.createThemes(#theme-count);
.createThemes(#n, #i: 1) when (#i =< #n) {
#theme : extract(#themes,#i) ;
.dashboard-#{theme} {
background-color: ~'#{theme-#{theme}}' ;
color: ~'#{theme-#{theme}-text}';
}
.createThemes(#n, (#i + 1));
}
And here's the output:
.dashboard-'green' {
background-color: #91ab7a;
color: #fff;
}
.dashboard-'yellow' {
background-color: #efdf91;
color: #00395d;
}
.dashboard-'red' {
background-color: #722d3d;
color: #fff;
}
.dashboard-'brown' {
background-color: #a9a196;
color: #fff;
}
.dashboard-'grey' {
background-color: #f3f3f3;
color: #00395d;
}
.dashboard-'darkBlue' {
background-color: #00395d;
color: #fff;
}
.dashboard-'navyBlue' {
background-color: #007db5;
color: #fff;
}
.dashboard-'cyan' {
background-color: #00adee;
color: #fff;
}
.dashboard-'lightBlue' {
background-color: #b1e7ff;
color: #00395d;
}
.dashboard-'default' {
background-color: #00395d;
color: #fff;
}
This is very nearly what I want, but for the fact that the theme name is quoted in the generated selector, eg instead of dashboard-'navyBlue' I should see dashboard-navyBlue. How can I adjust the mixin to remove these quotes?
After a little bit of tinkering, I was able to find the following working solution:
#theme-green: #91ab7a;
#theme-green-text: #fff;
#theme-yellow: #efdf91;
#theme-yellow-text: #00395d;
#theme-red: #722d3d;
#theme-red-text: #fff;
#theme-brown: #a9a196;
#theme-brown-text: #fff;
#theme-grey: #f3f3f3;
#theme-grey-text: #00395d;
#theme-darkBlue: #00395d;
#theme-darkBlue-text: #fff;
#theme-default: #theme-darkBlue;
#theme-default-text: #theme-darkBlue-text;
#theme-navyBlue: #007db5;
#theme-navyBlue-text: #fff;
#theme-cyan: #00adee;
#theme-cyan-text: #fff;
#theme-lightBlue: #b1e7ff;
#theme-lightBlue-text: #00395d;
#themes: 'green' 'yellow' 'red' 'brown' 'grey' 'darkBlue' 'navyBlue' 'cyan' 'lightBlue' 'default';
#themes-light: 'grey' 'lightBlue';
#themes-dark: 'green' 'yellow' 'red' 'brown' 'darkBlue' 'navyBlue' 'cyan' 'default';
#theme-count: length(#themes);
.createThemes(#theme-count);
.createThemes(#n, #i: 1) when (#i =< #n) {
#theme : extract(#themes,#i) ;
#selector: ~'dashboard-#{theme}';
#{selector} {
background-color: ~'#{theme-#{theme}}' ;
color: ~'#{theme-#{theme}-text}';
}
.createThemes(#n, (#i + 1));
}

Call different variables color in a loop in Sass

I have 20 different buttons on my page (class buttonCareCenter) and 10 different colors for its background.
Instead of using 10 times:
&:nth-child(10n + x) {
.btn.btn-primary {
background-color: #xxxxxx;
}
}
I would love to find a way to use a loop #for with nth-child to set the right colors for my buttons. But it seems that
#{$color-$i};
is not the right way to call my different variables.
$color-0: #ff5722;
$color-1: #ff4514;
$color-2: #647c8a;
$color-3: #3f51b5;
$color-4: #2196f3;
$color-5: #00b862;
$color-6: #afdf0a;
$color-7: #a7b61a;
$color-8: #f3e562;
$color-9: #ff9800;
.all-buttonCareCenter{
#for $i from 0 through 9 {
&:nth-child(10n + #{$i}) {
.btn.btn-primary {
background-color: #{$color-$i};
}
}
}
.buttonCareCenter{
height: $button-height;
border: 0;
box-shadow: 0px 2px 2px 0px rgba(0,0,0,0.3);
}
}
Any ideas?
You could solve this by adding all the colors in another variable called $colors and loop through it. It's much easier to maintain if one of the colors change.
$button-height: 20px;
$color-0: #ff5722;
$color-1: #ff4514;
$color-2: #647c8a;
$color-3: #3f51b5;
$color-4: #2196f3;
$color-5: #00b862;
$color-6: #afdf0a;
$color-7: #a7b61a;
$color-8: #f3e562;
$color-9: #ff9800;
$colors: $color-0, $color-1, $color-2, $color-3, $color-4, $color-5, $color-6,
$color-7, $color-8, $color-9;
.all-buttonCareCenter {
#for $i from 1 through length($colors) {
&:nth-child(#{length($colors)}n+#{$i}) {
.btn.btn-primary {
background-color: nth($colors, $i);
}
}
}
.buttonCareCenter {
height: $button-height;
border: 0;
box-shadow: 0px 2px 2px 0px rgba(0, 0, 0, 0.3);
}
}
See this CodePen example I created, click right top ยป View Compiled CSS to view the compiled code with all the iterations.
An other solution I found :
%color-0 {
background-color: #ff5722;
}
%color-1{
background-color: #ff4514;
}
%color-2 {
background-color: #647c8a;
}
%color-3{
background-color: #3f51b5;
}
%color-4 {
background-color: #2196f3;
}
%color-5{
background-color: #00b862;
}
%color-6 {
background-color: #afdf0a;
}
%color-7{
background-color: #a7b61a;
}
%color-8 {
background-color: #f3e562;
}
%color-9{
background-color: #ff9800;
}
#for $i from 0 through 9 {
&:nth-child(10n + #{$i}) {
.btn.btn-primary {
#extend %color-#{$i};
}
}
}

How can I combine classes on a button using .less?

I have this .less file for buttons:
button {
background: #button-background;
color: #text;
&.primary {
background-image: linear-gradient(#79d858, #569e3d);
border-color: #4a993e;
color: white;
}
&.primary:hover {
background-image: linear-gradient(#89e868, #66ae4d);
border-color: #4a993e;
color: white;
}
&.primary:active,
&.primary:focus {
background-image: linear-gradient(#99f878, #76be5d);
border-color: #4a993e;
color: white;
}
}
Can someone give me advice on how I can combine all the &.primary into one ?
Is this what you want:
button {
background: #button-background;
color: #text;
&.primary {
background-image: linear-gradient(#79d858, #569e3d);
border-color: #4a993e;
color: white;
&:hover {
background-image: linear-gradient(#89e868, #66ae4d);
}
&:active, &:focus {
background-image: linear-gradient(#99f878, #76be5d);
}
}
}
DEMO

How do I apply the same styling to all immediate children classes?

In less I have the following:
.some-class{
> li{
a{
color: white;
background: #fti-lightgrey;
border-radius: 0px;
padding: 1px 15px;
// a color for the partcular tab that is chosen. (the color for each tab can be set inside mura)
&.orange{
&:hover{ background: #fti-orange; }
&:hover{ color: white; }
}
&.black {
&:hover{ background: black; }
&:hover{ color: white; }
}
&.topaz{
&:hover{ background: #fti-topaz; }
&:hover{ color: white; }
}
}
}
}
How do I avoid writing &:hover{ color: white; } multiple times?
Is there a way to apply this line to all of the immediate class descendants somewhere inside the a tag?
It depends on the desired result.
Do you want:
1) White hover color by default, regardless of whether it also has the one of the .orange, .black, or .topaz classes?
.some-class{
> li{
a{
color: white;
background: #fti-lightgrey;
border-radius: 0px;
padding: 1px 15px;
// a color for the partcular tab that is chosen. (the color for each tab can be set inside mura)
&.orange{
&:hover{ background: #fti-orange; }
}
&.black {
&:hover{ background: black; }
}
&.topaz{
&:hover{ background: #fti-topaz; }
}
}
a:hover{ color: white; }
}
}
2) Or do you only want it to be white on hover if it also has one of .orange, .black, .topaz classes?
.some-class{
> li{
a{
color: white;
background: #fti-lightgrey;
border-radius: 0px;
padding: 1px 15px;
// a color for the partcular tab that is chosen. (the color for each tab can be set inside mura)
&.orange{
&:hover{ background: #fti-orange; }
}
&.black {
&:hover{ background: black; }
}
&.topaz{
&:hover{ background: #fti-topaz; }
}
}
a:hover {
&.orange, &.black, &.topaz{
color: white;
}
}
}
}
You could do
a:hover {
&.orange,
&.black,
&.topaz { color: white; }
}
then define the background individually. This is assuming the hover for your anchor is different colour than white by default and you want the coloured classes to be white(not in a human race way!).
or use the same style as you have
a {
&.orange, &.black, &.topaz {
&:hover { color: white; }
}
}
if you have a common class for the colours then you could always target that common class
In this case I would recommend to simply remove &:hover { color: white; } rules, as long as you have it set on a tag already and there is no something like a:hover rules which might override this.
In case if you have some a:hover rule with different color, simply add &:hover { color: white } right inside of a block.
.some-class{
> li{
a{
color: white;
background: #fti-lightgrey;
border-radius: 0px;
padding: 1px 15px;
// a color for the partcular tab that is chosen. (the color for each tab can be set inside mura)
&.orange{
&:hover{ background: #fti-orange; }
}
&.black {
&:hover{ background: black; }
}
&.topaz{
&:hover{ background: #fti-topaz; }
}
}
}
}

Simply-fy my less using LESS functions

I would like to make the following code more maintainable (but less understandable is okay) by creating some sort of looping function that would create the CSS code using my LESS parser;
.box {
&.ebay {
background-color:#ebay-color;
h2, p{
color: lighten(#ebay-color, 15%);
}
}
&.google-shopping {
background-color:#google-shopping-color;
h2, p{
color: lighten(#google-shopping-color, 15%);
}
}
&.website {
background-color:#website-color;
h2, p{
color: lighten(#website-color, 15%);
}
}
&.feed {
background-color: #feed-color;
h2, p{
color: lighten(#feed-color, 15%);
}
}
&.twitter {
background-color: #twitter-color;
h2, p{
color: lighten(#twitter-color, 15%);
}
}
&.facebook {
background-color:#facebook-color;
h2, p{
color: lighten(#facebook-color, 15%);
}
}
}
So wouldn't it be great if I had a function that would A) loop over all the colors (ebay,google-shopping etc) and then another function that would output the style with the right colors.
Question
Is there a way to store my colours in an array and have a function that accepted the style for one of the above 6 blocks and then produced the same style (with the parameter for the color) in each block? and, what is this way?
I guess you could just do this:
.fn(#color) {
background-color: #color;
h2, p{
color: lighten(#color, 15%);
}
}
.box {
&.ebay {
.fn(#ebay-color);
}
&.google-shopping {
.fn(#google-shopping-color);
}
&.website {
.fn(#website-color);
}
&.feed {
.fn(#feed-color);
}
&.twitter {
.fn(#twitter-color);
}
&.facebook {
.fn(#facebook-color);
}
}
Change .fn to whatever you want.
There is a Bug that Prevents the Perfect Approach
This is using LESS 1.4+. The following achieves it, but the lighten() has to be predone because of a bug currently in LESS (see explanation following solution).
LESS
#numAssociations: 6;
#Associations: ebay google-shopping website feed twitter facebook;
#ebay-color: #ff0000;
#ebay-color-contrast: lighten(#ebay-color, 15%);
#google-shopping-color: #0000ff;
#google-shopping-color-contrast: lighten(#google-shopping-color, 15%);
#website-color: #ffff00;
#website-color-contrast: lighten(#website-color, 15%);
#feed-color: #ffffff;
#feed-color-contrast: lighten(#feed-color, 15%);
#twitter-color: #ffc0cb;
#twitter-color-contrast: lighten(#twitter-color, 15%);
#facebook-color: #ffa500;
#facebook-color-contrast: lighten(#facebook-color, 15%);
//loop code
.buildClassColorAssociations(#i) when (#i =< #numAssociations) {
#className: extract(#Associations, #i);
#bkgColor: ~'#{#{className}-color}';
#color: ~'#{#{className}-color-contrast}';
&.#{className} {
background-color: #bkgColor;
h2, p {
color: #color;
}
}
.buildClassColorAssociations(#i + 1);
}
//end the loop
.buildClassColorAssociations(#i) when (#i = (#numAssociations + 1)) {}
//call the loop
.buildClassColorAssociations(1);
CSS Output
.ebay {
background-color: #ff0000;
}
.ebay h2,
.ebay p {
color: #ff4d4d;
}
.google-shopping {
background-color: #0000ff;
}
.google-shopping h2,
.google-shopping p {
color: #4d4dff;
}
.website {
background-color: #ffff00;
}
.website h2,
.website p {
color: #ffff4d;
}
.feed {
background-color: #ffffff;
}
.feed h2,
.feed p {
color: #ffffff;
}
.twitter {
background-color: #ffc0cb;
}
.twitter h2,
.twitter p {
color: #ffffff;
}
.facebook {
background-color: #ffa500;
}
.facebook h2,
.facebook p {
color: #ffc04d;
}
This can, of course, be nested inside any class, so just call the mixin from within
.box { .buildClassColorAssociations(1); }
to get your original, desired output for that class.
BUG EXPLANATION:
Ideally, the code would be something like this:
LESS
#numAssociations: 6;
#Associations: ebay google-shopping website feed twitter facebook;
#ebay-color: #ff0000;
#google-shopping-color: #0000ff;
#website-color: #ffff00;
#feed-color: #ffffff;
#twitter-color: #ffc0cb;
#facebook-color: #ffa500;
//loop code
.buildClassColorAssociations(#i) when (#i =< #numAssociations) {
#className: extract(#Associations, #i);
#color: color(~'#{#{className}-color}'); //<-- color conversion fails, yet is
needed for lighten() to work so...
&.#{className} {
background-color: #color;
h2, p {
color: lighten(#color,15%); //<-- ... lighten fails, making a compile error
}
}
.buildClassColorAssociations(#i + 1);
}
//end the loop
.buildClassColorAssociations(#i) when (#i = (#numAssociations + 1)) {}
//call the loop
.buildClassColorAssociations(1);
BUT, the CSS Output shows that LESS is not handling the color conversion
properly, so the lighten() function fails (it makes a compile error), because the #color is producing this CSS output:
.ebay {
background-color: #NaNeebbaaNaNNaNccNaNNaNNaNNaNNaN;
}
.ebay h2,
.ebay p {
/* color: lighten(#color,15%); yields an error */
}
.google-shopping {
background-color: #NaNNaNNaNNaNNaNNaNeeNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNccNaNNaNNaNNaNNaN;
}
.google-shopping h2,
.google-shopping p {
/* color: lighten(#color,15%); yields an error */
}
.website {
background-color: #NaNNaNeebbNaNNaNNaNeeNaNccNaNNaNNaNNaNNaN;
}
.website h2,
.website p {
/* color: lighten(#color,15%); yields an error */
}
.feed {
background-color: #NaNffeeeeddNaNccNaNNaNNaNNaNNaN;
}
.feed h2,
.feed p {
/* color: lighten(#color,15%); yields an error */
}
.twitter {
background-color: #NaNNaNNaNNaNNaNNaNeeNaNNaNccNaNNaNNaNNaNNaN;
}
.twitter h2,
.twitter p {
/* color: lighten(#color,15%); yields an error */
}
.facebook {
background-color: #NaNffaacceebbNaNNaNNaNNaNccNaNNaNNaNNaNNaN;
}
.facebook h2,
.facebook p {
/* color: lighten(#color,15%); yields an error */
}

Resources