Less used, but no less excellent features of LESS

This post is inspired by the comment of the respected Habrauser SerafimArts that LESS does not know much. I would like to dispel these seditious statements and at the same time show how beautiful LESS can be if you prepare it correctly.

Note: some examples from the life in this article are provided for those people who for some reason (up to religious reasons) do not use Autoprefixer.

Note 2: for everything that is written below, the latest version of LESS is used, because there is no reason to not use it at all.



Mergers


They are associations, they are merge ( Merge ). Used if you need to append something with a space or a comma. Transitions, transforms, multiple backgrounds, shadows (sorry for the Russian word: boxing sounds somehow awkward) rejoice. The best examples will be for me.


Combine through a space right in the mixin
.transform (@value) {
    transform+_:@value;
}
.transformed {
    .transform(rotateX(10deg));
    .transform(scale(1.2,1.1))
}

Compiled in
.transformed {
     transform: rotateX(10deg) scale(1.2, 1.1);
}


And now, separated by commas
.transition (@property: all,@duration: 0s,@delay: 0s,@ease: ease-in-out){
    transition+: @arguments;
}
.transitioned {
    .transition(width,1s);
    .transition(opacity,0.5s,0.2s,linear);
}

Will turn into
.transitioned {
     transition: width 1s 0s ease-in-out, opacity 0.5s 0.2s linear;
}


Exactly what is needed. No difficulty using: just call the right mixin as many times as you need. This is something even more convenient than a method with an indefinite number of parameters: a rigid order of arguments will not allow you to get lost. Happiness, and only.

Conditions


Instead of the usual ifs in LESS, there are so-called guards (guards, guards ). Their essence is to call different announcements of one mixin depending on different conditions (there is something in them from generics). An example from life is given in the same commentary that inspired me: I would like to have tranches for transforms with prefixes. So be it (pay attention to the when keyword after the mixin declaration):

//Специальный вариант для трансформа
.transition (@property: all,@duration: 0s,@delay: 0s,@ease: ease-in-out) when (@property=transform) {
    -webkit-transition+: -webkit-transform @duration @delay @ease;
       -moz-transition+:    -moz-transform @duration @delay @ease;
         -o-transition+:      -o-transform @duration @delay @ease;
            transition+:     -ms-transform @duration @delay @ease, 
                                 transform @duration @delay @ease;  //Кажется, -ms-transition официально не существует
}
//И всё остальное.
.transition (@property: all,@duration: 0s,@delay: 0s,@ease: ease-in-out) when not (@property=transform) {
    -webkit-transition+: @arguments;
       -moz-transition+: @arguments;
         -o-transition+: @arguments;
            transition+: @arguments;
}
.transitioned {
    .transition(width,1s);
    .transition(transform,0.5s,0.2s,linear);
}


At the output we get (formatting according to my columns, the preprocessor did the rest)
.transitioned {
    -webkit-transition: width 1s 0s ease-in-out, -webkit-transform 0.5s 0.2s linear;
       -moz-transition: width 1s 0s ease-in-out,    -moz-transform 0.5s 0.2s linear;
         -o-transition: width 1s 0s ease-in-out,      -o-transform 0.5s 0.2s linear;
            transition: width 1s 0s ease-in-out,     -ms-transform 0.5s 0.2s linear, 
                                                         transform 0.5s 0.2s linear;
}


Well isn't that great? Gards support relations =,>, <,> =, <=, logical operators and, or, not, and a few more functions for checking the type of a variable (iscolor, isnumber, etc.), which allows you to vary the choice of mixin in significant limits. A small but important nuance: LESS will take and execute all mixins with the same name that go through the guard. We must not forget this and add all the necessary conditions for the “remaining” cases. And I think that is good. And why this is good, will be seen below.

Cycles


The statement that there are no loops in LESS is absolutely true. But there is recursion! Actually, it is proposed to be used by developers. As a life example, let's create a sprite class generator for a picture (do not skip the code, there are a lot of comments)

// Это базовый миксин для бэкграунда. Он простой, как пять копеек, но это всего лишь пример
.spriter (@x: 0,@y: 0) {
    background: #cccccc url("my-sprite-img.png") @x*20px @y*30px;
}
//Здесь непосредственно генерируется класс
.generate_sprite(@x,@y) {
    .sprite-@{x}-@{y}{
        .spriter(@x,@y);
    }
}
//Следующие две функции управляющие - задают порядок действий при обходе двумерного массива рекурсией. 
//Удобно то, что их можно называть так же, как и основную функцию-генератор. 
//LESS будет вызывать все миксины, которые удовлетворят гардам.
.generate_sprite(@x,@y) when (@y=0) and (@x>0) {
    .generate_sprite(@x - 1,@spritey);
}
.generate_sprite(@x,@y) when (@y>0){
    .generate_sprite(@x,@y - 1);
}
//Числа, которые на один меньше количества столбцов и строк иконок в спрайте
@spritex: 1;
@spritey: 2;
//Запускаем генератор
.generate_sprite(@spritex,@spritey);


At the output, we get six classes for icons
.sprite-1-2 {
  background: #cccccc url("my-sprite-img.png") 20px 60px;
}
.sprite-1-1 {
  background: #cccccc url("my-sprite-img.png") 20px 30px;
}
.sprite-1-0 {
  background: #cccccc url("my-sprite-img.png") 20px 0px;
}
.sprite-0-2 {
  background: #cccccc url("my-sprite-img.png") 0px 60px;
}
.sprite-0-1 {
  background: #cccccc url("my-sprite-img.png") 0px 30px;
}
.sprite-0-0 {
  background: #cccccc url("my-sprite-img.png") 0px 0px;
}


It is here that we have used the fact that all suitable mixins are called. Indeed, thanks to this, we did not have to duplicate the call of the class generator in control structures. Oh, great.
You will probably say that this is a perversion. I think you will be right. Nevertheless, the absence of cycles in the language somewhat increases the complexity in constructing such constructions. Fortunately, they are not needed so often.

Code injection as parameter


As parameters, you can pass full-fledged pieces of less-code, which will behave quite logically. Examples are our everything: showing is easier than explaining
.placeholder(@content) {
    &::-webkit-input-placeholder{
        @content();
    }
    &:-moz-placeholder {
        @content();
    }
    //Пожалуй, для демонстрации хватит
}
.withplaceholder{
    .placeholder({
         //Вау, мой редактор кода даже подсветит это правильно
         color:blue;
         font-style: italic;
   })
}


With a flick of the hand turns into
.withplaceholder::-webkit-input-placeholder {
  color: blue;
  font-style: italic;
}
.withplaceholder:-moz-placeholder {
  color: blue;
  font-style: italic;
}


Moreover, you can insert a call to other mixins into the embedded code and everything will work:
.topleft(@position){
    top:@position;
    left:@position/2;
}
.keyframes(@name,@rules) {
    //Можно я обойдусь без вендорных префиксов?
    @keyframes @name {
        @rules();
    };
}
.keyframes(down,{
    0% {
        .topleft(0);
    };
    100% {
        .topleft(80);
    };
});


And at the exit
@keyframes down {
  0% {
    top: 0;
    left: 0;
  }
  100% {
    top: 80;
    left: 40;
  }
}

We created the entire pack of keyframes (more precisely, I would have created it if I hadn’t missed the vendor prefixes for brevity and readability) with one single command - perfect.

And one more good thing in the end in this section: do not like to write long media queries? I understand you: every time the same thing. Let's cut it. Here is a code
@width_mobile: 320px;
@width_tablet: 640px;
.media_mobile(@rules) {
    @media screen and (max-width: @width_tablet) and (min-width: @width_mobile) {
        @rules();
    };
};
.class_parent{
    width:300px;
    .media_mobile({
        width:200px;
        .class_child{
            width:100px;
        }
    });
}


Will become so
.class_parent {
    width: 300px;
}
@media screen and (max-width: 640px) and (min-width: 320px) {
    .class_parent {
        width: 200px;
    }
    .class_parent .class_child {
        width: 100px;
    }
}

Do not write a long steam engine media query every time - is this not the dream of an adaptive layout designer?

What can be said as a result. LESS is very actively developing. Some of these features were not literally until version 1.7, which was released just six months ago. Personally, this caused me some inconvenience: I often have to work with various types of animations on the front end. However, now I’m almost ready to kiss the developers for this nice and kind preprocessor, which is easy to learn (there were no problems in transferring even the most inexperienced developers to it), it is powerful enough for all (or almost all) life situations and, what importantly, it has convenient readable syntax.

I hope this post raises a little LESS in the eyes of the habrasociety. Thank you all for your attention.

PS If someone can tell me how to make the LESS highlight on the hub, I will be very grateful.

Also popular now: