So I am trying to override some "global" variables based on a variable passed in from the php-less compiler.
I'm not sure if I am doing something wrong, or if it is just not possible due to the scope?
EDIT: I'm trying to get the background of the body to be red in this case.
external.less
// From external less stylesheet that I can't/don't want to modify
#myColour: blue;
body {
background: #myColour; // always blue
}
my.less
#import "external.less"
// My styles
.setResponsive(#responsive) when (#responsive = on) {
#myColour: green;
}
.setResponsive(#responsive) when (#responsive = off) {
#myColour: red;
}
#responsiveState: off; // actually being set from compiler
.setResponsive(#responsiveState);
div {
.setResponsive(#responsiveState);
background: #myColour; // red
}
http://codepen.io/anon/pen/gbOymJ
You are using the Mixins as Functions:
Variable defined directly in callers scope can not be overriden.
In your situation both #myColour: blue; and .setResponsive(#responsiveState); are in the same scope (the main scope). So what you are trying is not possible.
You should re-declare all the variables at the end of your code (using the same mechanism your are using to set #responsiveState )
Related
On the trail of this question by Codesections, I'm trying to add a phaser to a variable using traits. Something like this:
my &doing-good is Block will enter {
.add_phaser: "ENTER",
{
if Backtrace.new.grep: { .subname ~~ /bad/ } {
fail("Not authorized to call this");
}
}
};
This fails with is trait on &-sigil variable not yet implemented. Sorry.
I arrived to this because there seems no way to declare that as a block; by default is a Callable, and add_method does not work on Callables, apparently. Any other way of doing this?
Lets say I have a LESS file like this...
#myVariable: 5px;
.myRule {
myProperty1: #myVariable;
myProperty2: myOtherValue1;
}
I'll get this outcome when I compile this with LESS.
.myRule {
myProperty1: 5px;
myProperty2: myOtherValue1;
}
However, instead of having #myVariable defined inside this LESS file, I want to reference it from somewhere else. My referenced file, may or may not contain this variable. Currently, if the variable is missing, I'll get a result like this.
.myRule {
myProperty1: ;
myProperty2: myOtherValue1;
}
Is there any LESS functionality that would allow me to remove the property completely if the variable was not provided so that my output was like this.
.myRule {
myProperty2: myOtherValue1;
}
I've looked through the language features of LESS and couldn't find anything that does this. Maybe I'm missing something?
This would be the syntax that I'm imagining, but I'm pretty sure this doesn't exist.
.myRule {
when(exists(#myVariable)) {
myProperty1: #myVariable;
}
myProperty2: myOtherValue1;
}
Set Default and Override
//Load in a master variable file for all LESS
//containing all "possible" variables that may be used
//but set to some default values that "hide" the properties
//if the variable does not exist (such as "false" here)
#myVariable: false;
//Load in your specific variable references from elsewhere
//Individual variable may/may not be defined in this file
//but if one is defiend, this value overrides the previous value
#myVariable: 5px;
//Define a mixin to activate the setting of the property
//only if the value is not the original default hiding value
.setIfValue(myVariable) when not (#myVariable = false) {
myProperty1: #myVariable;
}
//Use the mixin to conditionally set the value into other mixins
.myRule {
.setIfValue(myVariable);
myProperty2: myOtherValue1;
}
Default Output
.myRule {
myProperty2: myOtherValue1;
}
Overridden Output
.myRule {
myProperty1: 5px;
myProperty2: myOtherValue1;
}
I think you made the syntax too complex. It should be something like this:
.myRule {
& when (#myVariable = false) {
myProperty1: #myVariable;
}
myProperty2: myOtherValue1;
}
This feature (apparently) is called CSS Guards.
It seems like you can check if a variable has a specific value, but not whether this allows you to check for defined or not.
So, I guess the other file should always define this variable as a prerequisite, but it can set it to 'false' (or any kind of default) to indicate that this property should not be used at all.
I have a LESS Mixin called in different stylesheets (i.e. one for each breakpoint controlled by media queries). In each stylesheet it is called with different parameter value such as:
"mobile.less":
.mixin(1);
"tablet.less":
.mixin(2);
.....
The mixin is defined (for example) as:
.mixin(#parameter) when (#parameter = 1)
{
body
{
font-style:italic;
}
.......
}
.mixin(#parameter) when (#parameter = 2)
{
.......
}
I'm developing a demo website so I wish that users could change this values on-the-fly changing value that is passed as parameter using a form field.
I tried the following method:
less.modifyVars({'#parameter' : <value from form field>});
But it would work only if #parameter is a "global" variable, not a passed parameter through the call...... Is there a method to change also passed parameters?
Thank you.
Original Answer
Yes, just make the variable outside the scope of the mixins but still use it in the guard expression. Something like:
#parameter: 1;
.mixin() when (#parameter = 1) {
body {
font-style:italic;
}
}
.mixin() when (#parameter = 2) {
body {
font-style:normal;
}
}
.mixin();
This generates the 1 code. If the variable gets set to 2, it generates the 2 code, etc.
Discussion of "re-process on the fly called mixins"
With reference to your comment, to my knowledge there is no way to directly re-process the local variable of a mixin call without doing something to the mixin definition itself to allow for it. So in your example, if "mobile.less" has a .mixin(1); call, how can you reprocess it to be, say, .mixin(4) based on user input. If you have not set up the call with a variable to begin with, then there is not way to "modify" the 1 in the original call. However, setting up with a variable call to begin with is really just a longer version of the answer I give above. Consider that this code essentially does the same as the above, only with more coding involved:
LESS Mixins Defined
.mixin(#parameter) when (#parameter = 1) {
body {
font-style:italic;
}
}
.mixin(#parameter) when (#parameter = 2) {
body {
font-style:normal;
}
}
Calls it in Files
//mobile.less
#parameter: 1;
.mixin(#parameter);
//tablet.less
#parameter: 2;
.mixin(#parameter);
Notice that we are still working with a "global" #parameter variable that is just being passed in as a "local" variable of the same name to the mixins. So all we gain here is more code (the addition of the local variable) to do the same thing.
Now assuming you are really after modifying the final output css behavior through the user input, then you may be able to "override" by a later call. This assumes that all the same properties, selectors are set by the various mixin calls, just to different values. So let us assume .mixin(1) is still in "mobile.less", you could set up a "reset.less" file that is called on user input to override by the css cascade.
LESS Mixin Definition Added
.mixin(#parameter) when (#parameter = 0) {
//purposefully empty, used as default for reset.less
}
Calls in your current "mobile.less" etc. remain as they are. You can have a global value of #parameter: 0; set in your global "variables.less" file, and then "reset.less" is this:
//reset.less
.mixin(#parameter);
That way "reset.less" outputs nothing by default (using the mixin definition just done above). This "reset.less" file is put last in the html processing so that it follows any "mobile.less" stylesheets, etc. Then, when the user changes #parameter, the "reset.less" is updated with the new values, and it does output css, which, by virtue of the css cascade, overrides the values of "mobile.less" etc.
How do i set a parametric mixin output to a variable?
Say i have this custom mixin with these parameters:
.gradient(#555, #333, #777);
I want this to be put into a variable so i can refer to this specific gradient throughout my code.
Wrapping it like this:
#mixin elGradient() {
#include .gradient(#555, #333, #777);
}
for inclusion like this:
.element {
#include elGradient;
}
Yields a parse error.
.elGradient() {
.gradient(#555, #333, #777);
}
.element {
.elGradient();
}
This is the simplest way. Alternatively it would make sense to get use of the extend feature if you really need to include same properties again and again:
.elGradientBase {.gradient(#555, #333, #777)}
.elGradient() {
&:extend(.elGradientBase all);
}
.element-1 {
.elGradient();
}
.element-2 {
.elGradient();
}
// etc.
I have just recently gotten into LessCSS and I am running into what I feel is major limitation and I was wondering if there was a way to do this?? I want to say I read somewhere that Sass allows for user defined functions but will LessCSS do the same?
What I'm wanting to do:
#fs: 16;
// either return the value
.s(#t,#s,#u) {
// return #t/#s*#u;
}
#elem {
margin-top: .s(30,#fs,1em);
width: .s(900,#fs,1em);
.child {
width: .s(100,900,100%);
}
}
// or have a property argument
.s(#t,#s,#u,#p) {
#{p}: #t/#s*#u;
}
#elem {
.s(30,#fs,1em,margin-top);
.s(900,#fs,1em,width);
.child {
.s(100,900,100%,width);
}
}
The only way I can figure it out, but it is very limited because I have to have multiple mixins:
.s(#t,#s,#u,#p) when (#p = margin-top) { margin-top: #t/#s*#u; }
// margin[-top|-right|-bottom|-left]
// padding[-top|-right|-bottom|-left]
.s(#t,#s,#u,#p) when (#p = width) { width: #t/#s*#u; }
.s(#t,#s,#u,#p) when (#p = height) { height: #t/#s*#u; }
I know I can always modify the less.js file to add a spacing function like the built-in round() or ceil() function. But, that kills the option of compiling the .less files for production using LessPHP, Crunch, SimpLess.
As far as I know, there's no property argument: you must write it down.
That is, a function will return a calculated value or instruction(s) (property/ies and calculated values).
There aren't thousands of properties in CSS, it's not a CMS with hundreds of classes and functions, so your list won't be as long as you can imagine. You should use other CSS preprocessors or a backend language to generate your CSS if you want to do such complicated things. Or better keep it simple.
That said, lessphp allows for user functions:
lessphp has a simple extension interface where you can implement user functions that will be exposed in LESS code during the compile. They can be a little tricky though because you need to work with the lessphp type system.
Notice that you also can easily add custom functions to the default Less compiler, which enable you to use the client side less.js compiler for testing and the command line lessc compiler for production.
For Less 1.x
Download and unzip the source from github at: https://github.com/less/less.js/releases/latest
Run npm install
Open the lib/functions.js file
Add your custom function (returncenter() in this example) inside the tree.functions object, for instance as follows:
tree.functions = {
returncenter: function() {
return new(tree.Anonymous)('center');
},
//original function below
}
Run grunt dist
After the preceding step you can include dist/less-1.x.x/js in your HTML or compile your Less code with the dist/lessc compiler.
For Less 2.x
Download and unzip the source from github at: https://github.com/less/less.js/archive/master.zip
Run npm install
Create a file caleld lib/less/functions/custom.js and write down the following content into it:
var Anonymous = require("../tree/anonymous"),
functionRegistry = require("./function-registry");
functionRegistry.addMultiple({
returncenter: function() {
return new(Anonymous)('center');
}
});
Open the lib/less/function/index.js file and append require("./custom"); to the list of register functions, just before return functions;
Run grunt dist
Now you can use the following Less code:
selector {
property: returncenter();
}
The preceding Less code will compile into the following CSS code:
selector {
property: center;
}