I am trying to create a function to switch themes. When I transpile my Less to CSS, the CSS file shows the literal string interpolation rather than the variable value. The variables file looks something like:
#beach-font-color: #3d3d3d;
#ocean-font-color: #d3d3d3;
#theme: "beach";
#symbol: "#";
#currentTheme-font-color: ~"#{symbol}#{theme}-font-color";
In the stylesheet:
body { color: #currentTheme-font-color; }
The generated css produces:
body { color: #beach-font-color; }
instead of:
body { color: #3d3d3d; }
One thing I thought might be required is:
#font: ~"#{symbol}#{theme}-font-color";
#currentTheme-font-color: ~"#{font}";
But this just produces the same results.
Why does the Less compiler use the string literal instead of the variable value?
How would I be able to get the value of the variable, going along these lines?
(I cannot skip this to not provide an alt. answer since such "namespace emulation via variable name concatenation" is my most favourite bloody wrong Less pattern (unfortunately it is also the most widely spread one :().
Instead of emulating namespaces via using looong global variable names (doh#1 in most of programming languages and paradigms global variables are considered harmful since 1970's... :) and then assembling those variable names via the ugly concatenation syntax (doh#2, ~"#{#{#foo}}-#{bar}-seriously}?"), one can use normal namespaces with much more clean syntax:
.theme(beach) {
#font-color: #3d3d3d;
// other beach variables
}
.theme(ocean) {
#font-color: #d3d3d3;
// other ocean variables
}
#theme: beach;
.theme(#theme);
body {color: #font-color}
This is just one of possible variations (for more examples see:
Dynamic Variable Names with Less -> gist
How to thematize in lesscss
etc.)
Related
My less file is dependent on many variables such as:
#fontRegular: "AvenirNextCondensed-Regular";
And classes make use of those variables, as follows:
.thisClass {
font-family: #fontRegular;
}
As you can expect, I need to retheme on-the-fly.
The theme itself redefines those variable, as follows):
#fontRegular: "HelveticaNeue";
How can I require less to reparse everything (I mean my less file) and how can I change the variables first?
Simply invoke less from you javascript (in this case, it's from my controller) as follows:
less.modifyVars(
$scope.config.fontStyleHelveticaNeue? {
'#fontRegular': "HelveticaNeue",
'#fontUltraLight': "HelveticaNeue-UltraLight",
'#fontDemiBold': "HelveticaNeue-CondensedBold"
}
: {
'#fontRegular': "AvenirNextCondensed-Regular",
'#fontUltraLight': "AvenirNextCondensed-UltraLight",
'#fontDemiBold': "AvenirNextCondensed-DemiBold"
}
);
Where on the example above, all #-prefixed words are my less variables I update (actually, there are two set there).
Less will rebuild all the css automatically.
I have a LESS loop in which I determine color values to use in CSS rules.
I get them through some quite complex vars evaluation, which forces me to use strings (If I remove the " I get a parse error).
So what I get is a variable containing a color value in form of string.
#color: "#{col_#{animal}}"
// this is in a loop, and #animal contains the name of a var ('dog', 'cat', ...)
// #col_dog, #col_cat contain a color
// #col_dog: #F9E2A0
// #col_cat: #094DD0
so if I try to assign this #color variable to a rule
.border { border-color: #color }
in CSS I get
.border {border-color: "#F9E2A0"}
Which obviously is ignored.
Is there a way to get rid of the "string" form, or a way to do the vars evaluation I need without using strings?
Thanks!
It's easy just use ##
I've been struggling with this myself for some time now. The solution is simple. Just use ## instead of # for the color. The color will then get parsed properly, and become an color object. For this to work I store the variable name 'color_cat' in a variable called #color first. The I use the variable variables technique ## to resolve the variable.
In your case this code works:
#color_dog: red;
#color_cat: yellow;
.animal-border(#animal){
#color: "color_#{animal}";
.#{animal}.border{
border-color: ##color;
}
}
.animal-border(dog);
.animal-border(cat);
Results:
.dog.border {
border-color: #ff0000;
}
.cat.border {
border-color: #ffff00;
}
Some errors associated with this problem. This one occurs when using the darken or lighten methods:
error evaluating function darken: Object # has no method 'toHSL'
Or this occurs when trying to supply the string value "#FF0000" to the color method:
error evaluating function color: argument must be a color keyword or 3/6 digit hex e.g. #FFF
Some related posts on SO:
Define variable name with variable in LESS operation
less undefined method error
Lighten color from parent in Less
Defining Variable Variables using LESS CSS
According to the docs http://lesscss.org/functions/#misc-functions-color
Parses a color, so a string representing a color becomes a color.
This should be doing what you want:
.border { border-color: color(#color) }
I'm in a bit of a pickle. I just picked up WinLess (the compiler I'm using) about two days ago and I've just vaguely learned the basis of LESS. Anyways, I'm having a problem with this bit of code:
// Font
#verdana: font-family:"verdana";
#sans: font-family:"sans-serif";
When I do compile this I get this message:
ParseError: Unrecognized input in on line 4, column 3:
3 // Font
4 #verdana: font-family:"verdana";
5 #sans: font-famlit:"sans-serif";
Can anyone give me a hand? Thanks!
For LESS 1.7+
They have now added rulesets that work like this:
#verdana: {font-family:"verdana"};
.myClass {
#verdana();
}
Note the syntax: you pass a bracketed {} set of properties, and access it with the parenthesis () after the variable name, much like a mixin. As you can see, it also functions a lot like a mixin (similar to lucian's answer), but it has the added value that it can be passed as an argument, so this is possible:
LESS
#verdana: {font-family:"verdana"};
.myMix(#font) {
#font();
}
.test {
.myMix(#verdana);
}
CSS Output
.test {
font-family: "verdana";
}
You can declare it like this: .myfont{ font-family:"some family, some generic family"} and then use it like this: div{ .myfont; }
i only know it in this way :
#variable_name: 'individual_font_name', Verdana, sans-serif;
a font variable with a name, a font name like "My_Verdana" and the main font and the second as example for a failure of the main-font.
hope this helps, greetings.
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’;
UPDATE:
This question has been modified to reflect the very helpful comments and answer below. I've accepted the answer, but the full functionality is not working to-date.
Contents of .ctags (in ~/)
-R
--exclude=.git
--exclude=log
--verbose=yes
--langdef=scss
--langmap=scss:.scss
--regex-scss=/^[ \t]*([^\t {][^{]{1,100})(\t| )*\{/| \1/d,definition/
--regex-scss=/^[#]mixin ([^ (]+).*/\1/m,mixing/
When I place my cursor under the target, vim says E426 tag not found: tag_name
Consider the following pattern:
footer{
.wrapper{
.general-info{
.footer-links{
a{#include ticker($bg, $white);}
}
}
}
}
In a separate file (modules.scss) in the directory, I have the definition for ticker:
#mixin ticker($color, $bg-color) {
color: $color;
background-color: $bg-color;
}
When I place my cursor under the target, vim still says E426 tag not found: tag_name
ctags does not index the ticker mixin. However I can use ctags to find methods from SCSS gem directly (e.g. darken).
adding a \ before the last { gives no warning when using ctags.
I don't know if the tags produced give the desired result since I don't know the language.
The result would be:
--langdef=scss
--langmap=scss:.scss
--regex-scss=/^[ \t]*([^\t {][^{]{1,100})(\t| )*\{/| \1/d,definition/
Update: like I mentioned above, I don't know the language, so it is hard to check the actual definition of the tags.
I looked online and the following code is listed as scss in some webpage.
Suppose the tags you want to get are the words following mixing.
#mixin table-scaffolding {
th {
text-align: center;
font-weight: bold;
}
td, th { padding: 2px; }
}
#mixin left($dist) {
float: left;
margin-left: $dist;
}
#data {
#include left(10px);
#include table-scaffolding;
}
then with the following:
--langdef=scss
--langmap=scss:.scss
--regex-scss=/^[ \t]*([^\t {][^{]{1,100})(\t| )*\{/| \1/d,definition/
--regex-scss=/^[#]mixin ([^ (]+).*/\1/m,mixin/
--regex-scss=/^[#]function ([^ (]+).*/\1/f,function/
you get the two new tags left and table-scaffolding.
So if I am in the word left inside data hit ctrl+] it jumps to the line where data is defined.
You have to be careful for the other keyword because it has a - in the word. So if you are on table and press ctrl+] you will get the same error tag not found. For this to work you have to add the following in your .vimrc
set iskeyword+=-
You should be able to generalize the above for other tags you need, or even build a general regular expression to handle all the tags, as you initially meant.
If you post a specific example of how the file you are trying to work with looks like, and what are the tags you are trying to obtain I am sure I or other people would be able to help figure out a expression for that.