Maps and themes - css

I am new to using CSS pre-compilers and started using Less. I found Sass code to add themes to my web app and it works great.
https://codepen.io/dmitriy_borodiy/pen/RKzwJp
I am trying to convert it to Less and having difficulty rewriting it. I have gone through Less documentation but sorry to say that I am not even able to create a multilevel themes variable.
sass variable is as follows:
$themes: (
light: (
backgroundColor: white,
textColor: #408bbd
),
dark: (
backgroundColor: #222,
textColor: #ddd
),
);
Below conversion is totally wrong but this is what I have tried:
#set: {
light: {
backgroundColor: white,
textColor: #408bbd
},
dark: {
backgroundColor: #222,
textColor: #ddd
},
}
EDIT:
Example of what I am trying to achieve:
.theme(key) {
return all outcomes using #themes variable.
}
div {
background: .theme(divBackgroundColor)
}
it should return the following css :
.light-theme div{
background: white
}
.dark-theme div{
background:grey
}
Any help is appreciated.

A question like this ...
... ("I'm learning a language X and I found some program in language Y that looks like what I need. How to do the same thing using X?") is pretty much impossible to answer in (and too broad for) the SO format, as soon as the snippet goes beyond a single distinct minimalistic statement/feature.
Either way, to not leave the Q unanswered:
To be able to write a similar code in Less you will need to get familiar with the following features:
Maps
Rulesets as values/parameters
plus all typical language basic facilities like variables, functions, scope etc. etc. and the last (but not the least) Mixins.
Answering how to make something like background: .theme(backgroundColor) to do what you need would require explaining all of this from scratch (i.e. turning the answer into a book or a very loooong tutorial). Technically, you should not really be able to miss that the code in the linked snippet is a waaaaaay more complex than just background: .theme(backgroundColor).
And here's a (minimalistic) Less equivalent of the snipped at CodePen you pointed to.
(No comments there. They are pointless since nothing magic happens in it - to understand what it does you just need to get familiar with the languages features I listed above):
#theme: {
#light: {
backgroundColor: white;
textColor: #408bbd;
}
#dark: {
backgroundColor: #222;
textColor: #ddd;
}
}
// ....................................
// usage:
.themify({
div {
background: .theme[backgroundColor];
}
span {
color: .theme[textColor];
}
// etc.
});
// ....................................
// impl.:
.themify(#style) {
each(#theme, {
#name: replace(#key, '#', '.');
.theme() {#value()}
#{name}-theme {#style()}
});
}
For other possible techniques and solutions related to similar "Theming" use-cases see also:
Variables based on ancestor class
How to thematize in ...
and other Q/As linked/referenced there.

Try this code
#light: #f9f9f9;
#dark: #333333;
.theme(#theme: #color, #background: #background) {
color: #theme;
background: #background;
a {
color: #theme;
}
}
.light-theme {
.theme(#theme: #light, #background: #dark);
}
.dark-theme {
.theme(#theme: #dark, #background: #light)
}
<div class="light-theme">
Light Theme<br> Light Theme
</div>
<div class="dark-theme">
Light Theme<br> Light Theme
</div>

Related

Get value from a list of properties / map

Currently, I've a list of colors (for example):
#colors: {
base: #716aca;
brand: #716aca;
danger: #c14549;
warning: #ffb822;
success: #34bfa3;
primary: #5867dd;
black: #000000;
}
I have each function that iterates over all the colors and makes all the possible rule colors that we can use:
each(#colors, .(#value, #key, #index) {
.rules-here-#{key} {
attribute: #value;
}
}
What I can't make work is something like this:
.getColor(#color);
Where I would use on other places, like:
div.system-warning-notification {
background-color: .getColor('base');
color: .getColor('danger');
}
I have no idea if this is even possible. I have been losing my mind over this for over a week now without any progress.
If that isn't possible, can I generate the variables so I can access them like:
#color-base: #716aca;
Without having to manually create them?
Thank you very much and I hope I asked this right. I am new here.

Atom Editor, change color of function call

currently I am trying to "hack" my Atom-editor and I am stuck here: I want to change the color of whenever I call a function in python - just like it is in the basic setup of SublimeText3. I am using the following code in my styles.less:
atom-text-editor::shadow {
.meta.function-call.python {
color: red;
}
}
The Problem is that this code also changes the color of all instances & modules to red leaving me with this mess here: URL
atom-text-editor.editor {
.syntax--meta.syntax--function-call.syntax--generic {
color: #66D9EF;
}
}
This works for me using magicpython.
Screenshot
Try this:
atom-text-editor .syntax--function-call {
color: red;
}
Edit: Fixed as per first comment.

Updating a Variable through a Mixin

So lets say I set the background of 10 elements on the page to #base, then a user lands on the "Foo" page which has the class on the body of the page.
How does one update the #base via a css declaration? I understand that variables are local to a function (or css declaration) but there must be a method to do this! (would make styling alternative pages so easy!)
#base: #00000;
body.foo{
#base = #FFF;
}
LESS is a Preprocessor so...
...it all has to be precompiled into CSS ahead of time. That means all possible class combinations need to be made into valid CSS ahead of time. If you wanted something like this, you would need to do something like the following in your LESS:
LESS
#base: #000000;
.setColorOptions(#className: ~'', #base: #base) {
#classDot: escape(`('#{className}' == '' ? '' : '.')`);
#class: escape(#className);
body#{classDot}#{class} {
someElement {color: #base;}
.someClass {color: #base;}
// etc.
}
}
.setColorOptions();
.setColorOptions(foo, #fff);
.setColorOptions(bar, #ccc);
CSS Output
body someElement {
color: #000000;
}
body .someClass {
color: #000000;
}
body.foo someElement {
color: #ffffff;
}
body.foo .someClass {
color: #ffffff;
}
body.bar someElement {
color: #cccccc;
}
body.bar .someClass {
color: #cccccc;
}
Obviously if there were many elements and a lot of color dependent things going on, this could get big fast. Imagine 100 elements under body with three color variations as above, and you have 300+ lines of CSS, 200+ (two-thirds) of which do not apply to any one page. And this doesn't account for other changes, like background colors, etc. In such a case, it is best to set up different LESS files that import a different set of values for #base and build different style sheets to be loaded on the pages that need it. However, if you are just doing a small subset of color changes to a page, this could be a valid way to go.
There is no way to do that.
LESS has no way to know whether the selector body.foo will apply at compile time.

Can I create Less color themes with variables that rely on other variables?

Does anyone know how to do what I am attempting to do here?
#theme (dark) {#primary: black;}
#theme (light) {#primary: white;}
#theme (#_) {#primary: yellow;}
#name: dark;
#theme(#name);
.rule {
color: #primary;
}
I am trying to define a few "themes" which will have colors and images (possibly) that will be used throughout the various Less files. I have made do in the past with defining them globally and commenting out those that are not in use, but I am trying to see if there are people who have found better strategies in Less than what I have.
I had at one point found a feature that used to be (?) a part of Less but it doesn't seem to work.
.theme {
#color: red;
}
.rule {
color: .theme > #color;
}
This would be great, if it worked.
After a bit of messing with LESSCSS, I've come up with a reasonable way to change all variables based on a single #theme variable.
The trick is to use variable interpolation to specify a variable reference to a variable.
//this can be either "dark" or "light"
#theme: dark;
#theme-primary: "#{theme}-primary"; //this will evaluate to "dark-primary"
#theme-secondary: "#{theme}-secondary"; //this will evaluate to "dark-secondary"
#dark-primary: #F00;
#dark-secondary: #000;
#light-primary: #333;
#light-secondary: #FFF;
body {
//#theme-secondary evaluates to "dark-secondary"
//#dark-secondary evalutates to #000
background-color: ##theme-secondary;
//#theme-primary evaluates to "dark-primary"
//#dark-primary evaluates to #F00
color: ##theme-primary;
}
Older version
While I don't know of an easy way to conditionally define variables, if you're going to change one word and change a color theme, you might as well change an import statement:
#import ’themes/dark.less’;
//#import ’themes/light.less’;

Defining Variable Variables using LESS CSS

Say I have three separate color schemes that are used on various pages in a site. Each color has a a light, medium and dark tint defined, and the color scheme is defined by a class in the body. Assume that the "red" color scheme is the default. Like this:
Color Definitions:
#red-lt: #121;
#red-md: #232;
#red-dk: #343;
#green-lt: #454;
#green-md: #565;
#green-dk: #676;
#blue-lt: #787;
#blue-md: #898;
#blue-dk: #909;
Basic Default Style Example
body { background-color: #red-dk;
#container { background-color: #red-md;
p { color: #red-dk; }
}
}
Different Color Scheme Style Example
body.green { background-color: #green-dk;
#container { background-color: #green-md;
p { color: #green-dk; }
}
}
I'd like to use variables so that I don't have to re-write all of the color variations for each scheme, so that I can just write something like this:
body.[color-var] { background-color: #[color-var]-dk;
#container { background-color: #[color-var]-md;
p { color: #[color-var]-dk; }
}
}
…but I can't quite wrap my head around how to accomplish that. Help…?
Use interpolation and escaping, parentheses in the selector and parametric mixins to get the desired effect:
Dynamic variables by interpolation: In a string, "#{variable}" is replaced with the value of the variable. They can also be nested: Given #{#{var}-foo} and #var: bar;, the result is "barfoo".
The resulting value is quoted. To remove these quotes, prefix ~.
Dynamic selectors by Selector interpolation: body.#{var} turns into body.bar.
Example:
#red-md: #232;
#red-dk: #343;
.setColor(#color) {
body.#{color} { background-color: ~"#{#{color}-dk}";
#container { background-color: ~"#{#{color}-md}";
p { color: ~"#{#{color}-md}"; }
}
}
}
.setColor(~"red"); // Escape to prevent "red" turning "#FF0000"
//.setColor(~"blue"); etc..
Turns into:
body.red {
background-color: #334433;
}
body.red #container {
background-color: #223322;
}
body.red #container p {
color: #223322;
}
Note: When the answer was originally written, selector interpolation did not exist. See the previous revision for the solution if you're working with an old LESS compiler (before LESS 1.3.1a). Support for the old method will be dropped in LESS 1.4.0.
If those values really follow a predictable format like that, seems like a perfect case for a parametric mixin:
Less:
#red: #232;
#green: #565;
#blue: #898;
.theme (#color) {
background-color: #color - #111;
#container {
background-color: #color;
p { color: #color + #111; }
}
}
body.red {
.theme(#red);
}
Compiled CSS:
body.red{background-color:#112211;}
body.red #container{background-color:#223322;}
body.red #container p{color:#334433;}
I know this question is pretty old, but for those that come to this post my answer maybe can help
I`m not really sure for what you want to use this, but one of my suggestion is based on #ScottS answer. On my real world, I need to create a web app, where it would show several brands and each brand have their own text color, background and so on... so I started to chase a way to accomplish this in LESS, what I could easily do on SASS and the result is below:
LESS
// Code from Seven Phase Max
// ............................................................
// .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) {.-each(extract(#array, #i))}
// Brands
#dodge : "dodge";
#ford : "ford";
#chev : "chev";
// Colors
#dodge-color : "#fff";
#ford-color : "#000";
#chev-color : "#ff0";
// Setting variables and escaping than
#brands: ~"dodge" ~"ford" ~"chev";
// Define our variable
.define(#var) {
#brand-color: '#{var}-color';
}
// Starting the mixin
.color() {
// Generating the loop to each brand
.for(#brands); .-each(#name) {
// After loop happens, it checks what brand is being called
.define(#name);
// When the brand is found, match the selector and color
.brand-#{name} & {
color: ##brand-color;
}
}
}
.carColor {
.color();
}
Te result will be:
CSS
.brand-dodge .carColor {
color: "#fff";
}
.brand-ford .carColor {
color: "#000";
}
.brand-chev .carColor {
color: "#ff0";
}
This is very tricky and I had to use several elements to get what I needed, first used a set of mixins provided by Seven Phase Max and you can find it here and than, the #ScottS answer was the piece that was missing fro my puzzle... hope this helps you and others that need to create a set of Variables to be part of another variable and create a more dynamic less file.
You can copy my entire code and test at http://lesstester.com/
Try this
#red-lt: #121;
#red-md: #232;
#red-dk: #343;
#green-lt: #454;
#green-md: #565;
#green-dk: #676;
#blue-lt: #787;
#blue-md: #898;
#blue-dk: #909;
#color: 'red-lt';
div{
background: ##color;
border: 1px solid lighten(##color,20%);
}
To my knowledge, variable variable names are not supported in LESS. You could however restructure your declarations in a more semantic manner:
/* declare palette */
#red-lt: #121;
#red-md: #232;
#red-dk: #343;
#green-lt: #454;
#green-md: #565;
#green-dk: #676;
#blue-lt: #787;
#blue-md: #898;
#blue-dk: #909;
/* declare variables based on palette colors */
#lt: #red-lt;
#md: #red-md;
#dk: #red-dk;
/* ...and only use them for main declarations */
body { background-color: #dk;
#container { background-color: #md;
p { color: #dk; }
}
}
This should let you switch between palettes quite painlessly by avoiding explicit color references.

Resources