How to create dynamic classes in less - css

I've been looking for the answers, but either it's not what I am really looking for, or I am not searching up properly. I want to dynamically generate the class name. Since, I use margin-top quite frequently, I have multiple classes defined with a set of rules, and I want to achieve with LESS.
I don't think is possible to create dynamic generated classes, as far as I did my research. Here is my code:
.margin-top-(#value)px {
margin-top: #value;
}
Desired Output
.margin-top-20px {
margin-top: 20px;
}
.margin-top-100px {
margin-top: 100px;
}
Just an example of what I am expecting.

Try to use mixin to achieve this.
//define the mixin
.margin-top(#value) {
.margin-top-#{value}{
margin-top:#value;
}
}
//use the mixin like this
.margin-top(20px);
U can try it here: http://winless.org/online-less-compiler

Related

Add logic to CSS

I would like to use logic in my CSS. Styles need to be applied only if a product ID is higher than a specific number, e.g:
if (data-product-id > 25) {
padding: 50px;
}
Is this possible with CSS?
No, it isn't. Attribute selectors are based on simple string matching. There is no provision for less than / greater than numerical comparisons.
The closest you could get with CSS itself would be something like:
[data-product-id="25"],
[data-product-id="26"],
[data-product-id="27"],
/* etc */
This sort of thing is better handled with JS or server-side code which adds classes to elements.
You can apply some limited logic of the like you were asking about in CSS, but I advise against it. Nevertheless, the answer below is an answer, it's better to implement your logic in Javascript.
Assuming that you have a class called data-product for all your data products, you can create this rule:
.data-product {
padding: 50px;
}
.data-product[data-product-id="1"],
.data-product[data-product-id="2"],
.data-product[data-product-id="3"],
.data-product[data-product-id="4"],
.data-product[data-product-id="5"],
.data-product[data-product-id="6"],
.data-product[data-product-id="7"],
.data-product[data-product-id="8"],
.data-product[data-product-id="9"],
.data-product[data-product-id="10"],
.data-product[data-product-id="11"],
.data-product[data-product-id="12"],
.data-product[data-product-id="13"],
.data-product[data-product-id="14"],
.data-product[data-product-id="15"],
.data-product[data-product-id="16"],
.data-product[data-product-id="17"],
.data-product[data-product-id="18"],
.data-product[data-product-id="19"],
.data-product[data-product-id="20"],
.data-product[data-product-id="21"],
.data-product[data-product-id="22"],
.data-product[data-product-id="23"],
.data-product[data-product-id="24"],
.data-product[data-product-id="25"] {
padding: 25px;
}

SASS Customize Class Names with Variables

Is there any way to customize the variables in SASS?
For example:
.m-b-{$number} {
margin-bottom: $number;
}
If I give class="m-b-50" to an element, it should take margin-bottom 50. I just want to know if it is possible with SASS.
Yes it is possible with the help of variable interpolation or variable substitution which uses #{} for variable substitution in SASS and mixins which is a block of code just like function.
Interpolation is the process of evaluating an expression or a string containing one or more variables, yielding a result in which the variables are replaced with their corresponding values.
Simple example of interpolation and set values to the css property in SASS:
$number:60;
$n: 20px;
.m-b-#{$number}{
margin-bottom: #{$number}px;
margin-top: $n;
}
To create customize class names, will use mixins:
#mixin margin-class($side, $number) {
$firstLetter: str-slice($side, 0, 1);
.m-#{$firstLetter}-#{$number}{
margin-#{$side}: #{$number}px;
}
}
$margins: (10, 20);
$sides: ("top", "right", "bottom", "left");
#mixin generate-margin(){
#each $margin in $margins{
#each $side in $sides{
#include margin-class($side, $margin);
}
}
}
#include generate-margin();
Here, generate-margin() will get executed which will call margin-class() for each $margins and $sides, and will generate the below CSS classes:
.m-t-10 {
margin-top: 10px;
}
.m-r-10 {
margin-right: 10px;
}
.m-b-10 {
margin-bottom: 10px;
}
.m-l-10 {
margin-left: 10px;
}
.m-t-20 {
margin-top: 20px;
}
.m-r-20 {
margin-right: 20px;
}
.m-b-20 {
margin-bottom: 20px;
}
.m-l-20 {
margin-left: 20px;
}
That's the one way when you want only for specific values, but if you want to create margin class for 0-20, you can loop thru 0 to 20 as shown below:
#mixin generate-margin(){
#for $margin from 1 through 20{
#each $side in $sides{
#include margin-class($side, $margin);
}
}
}
For anyone else facing this issue, here is how one can achieve this:-
#for $i from 1 through 10 {
.mb-#{$i} {
margin-bottom: #{$i}rem;
}
}
The answer is: no it is not possible. SASS is just a language to pre-generate CSS for you. There is no on-demand, dynamic creation of classes triggered by the contents of your HTML markup. When it comes time for the browser to render your HTML and apply your specified classes, it is still just using CSS. I.e. if you assign class="m-b-50" to an element, the class .m-b-50 must already be explicitly defined somewhere. As noted in the other answers, SASS can make it easier to generate a bunch of pre-defined classes but you must know which values you want to support up front.
Now, you could generate classes for some very large, all-inclusive range like -1000 to 1000 to effectively support all values you might ever try to use and it would seem to do what you wanted, but you would be forcing your users to download a larger CSS file with, most likely, a large percentage of it being unused CSS which is wasteful and can be inconsiderate in a world of paid & limited data plans.

Concatenate String for class name in LESS

I am converting LESS to CSS, there I want to run the LESS function below:
.myPL( #val ) {
.pL #val{
padding-left:#val;
}
}
Function Call:
.myPL( 20px );
Expected result:
.pL20px{padding-left:20px}
But actual result is Syntax Error.
Please help me to concatenate the strings in class name in LESS.
What you are looking for is called selector interpolation ... you can find it here: http://lesscss.org/#-selector-interpolation
Your mixin would need to look like this for it to work:
.myPL( #val ) {
.pL#{val} {
padding-left: #val;
}
}
What you are trying to achieve does not work in LESS:
You could do:
.myPL( #val ) {
padding-left: #val;
}
Why on earth would you manually define each possible variant of padding left with the classname itself? That's not what LESS was designed for, and doesn't really make much sense with the context you've given.
The idea of mixins is to make them reusable, but I can't understand why you'd call a classname in the middle of that mixin. Use LESS mixins properly, and do the following:
.pl(#val) {
padding-left: #val;
}

CSS class nesting

I havent done CSS in awhile (~5-7yrs).
So i need a little assistance in a possible solution to my quandry.
Ideal design:
table.ctable
{ class:collapsible collapsed; }
Now i know that its syntactically not correct but was wondering if there was a way to create some base-class CSS and then have those class(es) derive into a parent. I know its not OOP, but figured there would be a way around the current structure to accomidate this type of inclusion.
You couls use a SASS mixin:
#mixin left($dist) {
float: left;
margin-left: $dist;
}
#data {
#include left(10px);
}
or a LessCSS mixin:
.left(#dist) {
float: left;
margin-left: #dist;
}
#data {
.left(10px);
}
No, unfortunately you can't inherit rules from another class. The closest you can get is JavaScript getting elements by class name and applying extra classes to them, but then you have the jump between the page loading the JS running.

LESS issues (scope and explicit node name)

Is there any way to bypass LESS scoping? It's becoming annoying. Basically, I have a .text-box which defines background, border, etc. Then, in a sub-section there's a one-off change to add a margin-top: .text-box { margin-top: 10px }. Now I can't use .text-box within that section and get my original box styles; instead, all I get is the margin-top. How can I get the definition higher in the heirarchy? I suppose I could make it a function, and call that function in both places, but being that I'm using LESS, I want to do less and KISS. In PHP, you'd get to the global namespace by using / prefix, or in C++ using :: prefix.
Additionally, it doesn't seem like any definitions with the node name work for prototyping. Meaning, I can't declare it ul.products, and then use ul.categories { ul.products }. I have to omit the node name in order to re-use it. Meaning: .categories { .products }. Is this an oversight/impossibility?
Thanks
ok so let's say you've got your mixin defined, for example:
.text-box {
background: #eee;
border: 1px solid #ccc;
color: #333;
margin-top: 5px;
}
now you want to add property or modify it in some subsection, then simply do this:
div.content {
div.sub_section {
.text-box;
margin-top: 10px; // this will override 5px defined in the mixin.
}
}
...which is putting your mixin in place, and adding some property you need to add (which will override any property from the mixin itself BUT make sure the overriding property is defined AFTER the mixin is called.
it's not ideal solution, as it creates two declarations in the output css file (there will be one from mixin followed by the one you defined in .sub_section), but otherwise I don't know a solution to this problem other than defining a parametric mixin..
--
your second issue - I think that less doesn't support scope-limited definitions on purpose... if you really need to know that certain mixin is to be used by a specific tag, I would deal with it like so:
.ul_products { ... }
.ul_categories { .ul_products; ... }
ul.categories { .ul_categories; }
you can also define a bundle and call stuff from there:
#ul {
.products { ... }
.categories { ... }
}
ul.categories { #ul > categories; }
i hope i got it right.. ?

Resources