How should I reset a less variable using its own value - less

I want to create a rgba from a color less variable and assign the result to the same variable, but I can't do this by the following code.
#navbar-default-bg: rgba(red(#navbar-default-bg), green(#navbar-default-bg), blue(#navbar-default-bg), 0.9);

The above code would result in the following error being thrown on compilation:
NameError: Recursive variable definition for #navbar-default-bg
Recursive variable definitions won't work in Less because of the way Less does lazy loading of the variables. This would mean that the last definition for that variable (within the same scope) will be the one that is used. In your example it would result in an error because the variable cannot reference itself (to get its originally declared value).
Quoting Less Website:
When defining a variable twice, the last definition of the variable is used, searching from the current scope upwards. This is similar to css itself where the last property inside a definition is used to determine the value.
The best way to create a rgba color value from a given rgb color is to use the built-in fade function (like shown below). But note that, the value cannot be assigned back to the same variable.
#navbar-default-bg: rgb(255, 0, 0);
#sample{
color: fade(#navbar-default-bg, 90%);
}
The above Less code when compiled would produce the following CSS output:
#sample {
color: rgba(255, 0, 0, 0.9);
}
Of-course, you could do something like mentioned in this answer to sort of achieve a reset effect but my personal opinion is that it is way too much complexity and effort for something that can probably be achieved in a different way.
Here is a sample implementation of the method mentioned in that answer adapted to suit this question. (Code is added below just in-case the link becomes inactive.)
.init() {
.inc-impl(rgb(255, 0, 0), 0.1); // set initial value
}
.init();
.inc-impl(#new, #i) {
.redefine() {
#color: #new;
#alpha: #i;
}
}
.someSelector(#name) {
.redefine(); // this sets the value of counter for this call only
.inc-impl(rgba(red(#color), green(#color), blue(#color), #alpha), (#alpha + 0.1)); // this sets the value of counter for the next call
#className: ~"#{name}";
.#{className}
{
color: #color;
}
}
.someSelector("nameOfClass");
.someSelector("nameOfClass1");
.someSelector("nameOfClass2");

Related

Input changins in V-for does not make update placeholder and input

I'm creating a passengers form, In this form it gets adult and child counts and children ages. At the beginning childCount equals 0 and inputs of childAges are invisible. When i increase child count, they are visible one by one. So far it is ok. However while increasing childAge, input and placeholder value do not change. By the way at the the background value is changing.
I want to be updated value in input while changing. I am sharing code via jsfiddle
Please, not only fix my code, please share how it works.
Thank you.
enter code here
Due to limitations in JavaScript, Vue cannot detect the following
changes to an array:
When you directly set an item with the index, e.g.
vm.items[indexOfItem] = newValue. When you modify the length of the
array, e.g. vm.items.length = newLength.
Reference.
increaseChildAge: function(index) {
this.$set(this.childAges, index, this.childAges[index] + 1);
},
decreaseChildAge: function(index) {
if (this.childAges[index] > 0) {
this.$set(this.childAges, index, this.childAges[index] - 1);
}
}

Less: how to grab an entire ruleset from within a map

I have a nested ruleset (map) like the one below.
#typography: {
#h1: {
font: roboto;
font-weight: 300;
font-size: 9.6rem;
line-height: 9.6rem;
text-transform:none;
}
}
I know how to retrieve and output a single key such as [font], but is there any way of returning and outputting the whole of inner ruleset?
.myclass {
font: roboto;
font-weight: 300;
font-size: 9.6rem;
line-height: 9.6rem;
text-transform:none;
}
"Can't work this way currently (v3.9)".
I'm afraid it's not going to work the way (specifically the map itself) it is.
Intuitively it would be something like:
#usage {
#typography[#h1]();
}
But currently this feature (cascading () and [] operators) is not implemented.
A first-guess workaround like "assign a ruleset of interest to a temporary variable and then 'call' it" also fails:
#usage {
#temp: #typography[#h1];
#temp(); // error: not callable value
}
(This one actually to be counted as a bug - I created a dedicated ticket).
This all brings us to the next section:
"Consider using mixin-based maps".
Notice that while "variable-based maps" (aka DRs) seem to be a more wide-spread pattern by now, there are five different methods to define a map in Less (and infinite number of these methods permutations to define an N-dimensional (aka "nested") map).
Each method has its pros and cons, and so far it's not clear which one to be chosen as the "go-to" one (in a long run there's tendency to unify them as tidy as possible but so far it's far from that).
Now look at the structure you're trying to represent w/o sticking to "variable -> #variable" stereotype. Does not it look like a regular CSS ruleset:
.typography {
.h1 {
font: roboto;
font-weight: 300;
font-size: 9.6rem;
line-height: 9.6rem;
text-transform: none;
}
}
?
And this way you've already got a "mixin-based map" you can use pretty much the same way you'd use a "variable-based map". (Actually the current documentation for "Maps" also suggest both methods w/o enforcing either one as "the primary").
The only modification you'll need for this "CSS" structure is to make its inner or outer (or both) rulesets to be a parameteric mixin (by adding ()) so that the rules won't appear in the compiled CSS by default.
E.g. like this:
.typography {
.h1() {
...
Or like this:
.typography() {
.h1 {
...
(Also if you prefer for these identifiers you can use # instead of .).
Now getting back to your use-case (The Solution):
.typography {
.h1() {
font: roboto;
font-weight: 300;
font-size: 9.6rem;
line-height: 9.6rem;
text-transform: none;
}
}
#usage-1 {
// "expand" the set of rules:
.typography.h1(); // OK
}
#usage-2 {
// use individual value from the map:
r: .typography.h1[font]; // OK
}
#usage-3 {
// iterate through:
each(.typography.h1(), <...>); // OK
}
// etc.
Not a surprise counting that expanding a set of rules is what the mixins were invented for in the first place.
The only fundamental difference (beside current limitations/issues on how they can be used) between "variable-based" and "mixin-based" maps to keep in mind is that "variables (and properties) override" and "rulesets (and thus mixins) cascade". This may affect some particular details when you'll need your CSS data to be customized/modified by "external code" (e.g. as in "theming/subtheming" etc.) - but that's another big story so I won't get into it here, although see the next section for some tips.
"Mixins and variables interop".
And one more important thing to understand about mixins (in context of the use-case).
If we'll think of variables as an abstract programming thing, i.e. "an identifier (symbolic name) associated with a value" we quickly see that a mixin is just that: a variable.
A "mixin" (its name) is really nothing but an identifier to refer to a value, i.e. -> variable.
It's just the identifier characters (# or . in front) plus a limitation on what kind of values it can hold is what makes it to be referred to by a different title, i.e. "mixin" instead of a "variable" (as in "Less #variable").
In other words, when it comes to "I have some data and I need something (i.e. "a variable") to hold/represent it", it's important to not automatically fall into the "a variable (in a generic sense) -> #variable" trap.
So getting back to the Q, another trick to have in mind is to know that mixin and variable values (specifically if it's a "ruleset" value) can be (almost) freely assigned/reassigned to each other. I.e. basically, you can create a variable to refer to a mixin-based map and create a mixin to refer to a variable-based map.
This may be valuable to overcome current issues/limitations (mostly in usage) of both methods (or if you just prefer more of #, . or # "code-look" where maps are used).
Here're a few tips:
// ................
// "Universal" map:
.typography {
.h1() {
font: roboto;
font-weight: 300;
font-size: 9.6rem;
line-height: 9.6rem;
text-transform: none;
}
#h1: {.typography.h1}; // assign mixin to variable
.h2() {#h1()} // assign variable to mixin
.h3() {.typography.h1} // assign mixin to mixin
#h2: #h1; // assign variable to variable
}
#typography: {.typography}; // assign mixin to variable
.graphytypo {.typography} // assign mixin to mixin
// etc.
// ................
// Usage:
#usage-1 {
// use individual values from the map (all roboto):
1: .typography.h1[font];
2: .typography[#h1][font];
3: .typography.h2[font];
4: .typography.h3[font];
5: .typography[#h2][font];
6: #typography[#h1][font]; // <- like your original map
7: .graphytypo.h3[font];
// etc.
}
#usage-2 {
// expand a set of .h1 rules (all the same):
.typography.h1();
.typography.h2();
.graphytypo.h3();
// etc.
}

Can whole declaration be stored as #variable value in Less?

All my Less variables are editable within a CMS-module and are assigned to the Less compiler. It works, if I only use the values like color, font-size, etc.:
body {
background-color: #bgColor;
}
I've created another field for custom Less, which I would like to add at the end of my Less file, like:
body {
background-color: #bgColor;
}
#customLess /* desired OUTPUT: body { color: white; }*/
Unfortunately this leads to an ParseError.
I'd like to avoid to merge the existing Less and custom Less. I'm not looking for mixins, I guess.
Is it possible to put whole declarations in a #variable?
It is very much possible to put whole declarations (including the selector, property + value pair) inside a variable. Those are called as detached rulesets.
While calling them, braces (()) must be added. If not, the call will fail and result in compilation error. Below is an extract from the official website.
Parentheses after a detached ruleset call are mandatory. The call #detached-ruleset; would NOT work.
#customLess: {
body{
color: white;
}
};
#bgColor: red;
body {
background-color: #bgColor;
}
#customLess();

Is there a way to read a var passed and replace its value

Is there a way to read a variable passed and replace its value.
less
.mar(#B) when (default()) {
margin:~'#{B}px';
}
.mar(#A,#B){
margin-#{A}:~'#{B}px';
}
usage
.foo1{
.mar(3);
}
.foo2{
.mar(t,3);
}
the t value passed would be replaced by the word top and so worth for other letters, b for bottom, etc...
I could pass the entire word eg:top but i'm trying to shorten the amount of text I type after the initial mixin.
You can make four overloads of the mixin:
.mar(t, #B){
margin-top: ~'#{B}px';
}
.mar(b, #B){
margin-bottom: ~'#{B}px';
}
However, abbreviating code this way is not very readable. Don't do this.

LESS CSS: selector substitution?

This is an existing general css rule (original file):
.caption-top {
color: red;
}
This is schematic, because in real life case, I need the .caption-top selector to become something else, depending on the context. But I would like to use a variable instead of changing the all occurrences of the selector. For example, in one context, it should become .field-name-field-caption-top. So I did this (wrapper file):
#caption-top: .field-name-field-caption-top;
#caption-top {
color: red;
}
This generates a LESS parse error. Is there another method to establish a rule to substitute a selector? So that, for the above example, the rule will finally look like this:
.field-name-field-caption-top {
color: red;
}
Additional info
The whole point is to not touch the original css file, because it comes from outside and will be overwritten, but instead, to wrap it and tell Less how to replace existing classes with classes used in a particular theme. If it is not possible to achieve, then acceptable solution will be to change the original file in an automatic way, like e.g. replace all occurrences of ".caption" with "#caption" (which I suggested in the above code sample) or make an import at the beginning etc. Then use a wrapper Less file (aware of the theme implementation) to specify what classes whould be replaced with what.
You can use escaping to achieve this:
#selector: '.myclass';
(~'#{selector}') {
color: red;
}
However you cannot do this:
(~'#{selector}') .another {
color: red;
}
To achieve the above you will need to alter the variable
#selector: '.myclass .another';
You need to produce a function of two arguments that generates the desired CSS:
.generator(#fieldName, #fieldCaption) {
.#{fieldName}-#{fieldCaption}-top {
color: red;
}
}
.generator(foo, bar);
(Feel free to try this in the online less compiler)
This piece of code produces the desired CSS for elements with name "foo" and caption "bar". You just need to make more calls to the .generator function with different arguments to obtain what you need.
If this does not correspond to what you need, please provide one additional example of your desired CSS output.
It looks like mixins are what you need:
.caption-top {
color: red;
}
.field-name-field-caption-top {
.caption-top
}
You can define a class that, used or not, you can then reference again and again inside other selectors. You can even combine them with new styles, thereby extending what the original block of CSS would have done:
.field-name-field-caption-bottom {
font-size: 3em;
.caption-top
}
Give it a go in the compiler!