Less, un preprocesador CSS

Adolfo Sanz De Diego

Septiembre 2016

1 El autor

1.1 Adolfo Sanz De Diego

1.2 Algunos proyectos

1.3 ¿Donde encontrarme?

2 Introducción

2.1 ¿Qué es?

2.2 Ventajas

2.3 Características

3 Usando Less

3.1 Instalación

$ npm install -g less

3.2 Línea de comandos

$ lessc styles.less > styles.css

3.3 Desde el navegador

<link rel="stylesheet/less" type="text/css" href="styles.less" />

<script src="less.js" type="text/javascript"></script>

4 Variables

4.1 ¿Por qué?

a,
.link {
  color: #428bca;
}
.widget {
  color: #fff;
  background: #428bca;
}
@color: #428bca

a,
.link {
  color: @color;
}
.widget {
  color: #fff;
  background: @color;
}

4.2 Selectores

@mySelector: banner;

.@{mySelector} {
  font-weight: bold;
  line-height: 40px;
  margin: 0 auto;
}
.banner {
  font-weight: bold;
  line-height: 40px;
  margin: 0 auto;
}

4.3 URLs

@images: "../img";

body {
  color: #444;
  background: url("@{images}/white-sand.png");
}

4.4 Propiedades

@property: color;

.widget {
  @{property}: #0ee;
  background-@{property}: #999;
}
.widget {
  color: #0ee;
  background-color: #999;
}

4.5 Nombres de las variables

@fnord:  "I am fnord.";
@var:    "fnord";
content: @@var;
content: "I am fnord.";

4.6 Carga perezosa

.lazy-eval {
  width: @var;
}

@var: @a;
@a: 9%;
.lazy-eval {
  width: 9%;
}

4.7 Ámbitos

@var: 0;
.class {
  @var: 1;
  .brass {
    @var: 2;
    three: @var;
    @var: 3;
  }
  one: @var;
}
.class {
  one: 1;
}
.class .brass {
  three: 3;
}

5 Extend

5.1 Caso de uso

.animal {
  background-color: black;
  color: white;
}
<a class="animal bear">Bear</a>
.animal {
  background-color: black;
  color: white;
}
.bear {
  background-color: brown;
}
<a class="bear">Bear</a>
.animal {
  background-color: black;
  color: white;
}
.bear {
  &:extend(.animal);
  background-color: brown;
}

5.2 Reduce el tamaño del CSS

.my-inline-block() {
    display: inline-block;
  font-size: 0;
}
.thing1 {
  .my-inline-block;
}
.thing2 {
  .my-inline-block;
}
.thing1 {
  display: inline-block;
  font-size: 0;
}
.thing2 {
  display: inline-block;
  font-size: 0;
}
.my-inline-block {
  display: inline-block;
  font-size: 0;
}
.thing1 {
  &:extend(.my-inline-block);
}
.thing2 {
  &:extend(.my-inline-block);
}
.my-inline-block,
.thing1,
.thing2 {
  display: inline-block;
  font-size: 0;
}

6 Mixins

6.1 ¿Qué son?

.bordered {
  border-top: dotted 1px black;
  border-bottom: solid 2px black;
}
#menu a {
  color: #111;
  .bordered;
}

.post a {
  color: red;
  .bordered;
}

6.2 Selectores

.a, #b {
  color: red;
}
.mixin-class {
  .a();
}
.mixin-id {
  #b();
}

6.3 No exportar Mixins

.my-mixin {
  color: black;
}
.my-other-mixin() {
  background: white;
}
.class {
  .my-mixin;
  .my-other-mixin;
}
.my-mixin {
  color: black;
}
.class {
  color: black;
  background: white;
}

6.4 Pseudo-clases

.my-hover-mixin() {
  &:hover {
    border: 1px solid red;
  }
}
button {
  .my-hover-mixin();
}
button:hover {
  border: 1px solid red;
}

6.5 Namespaces

#outer {
  .inner {
    color: red;
  }
}
#outer > .inner;
#outer > .inner();
#outer .inner;
#outer .inner();
#outer.inner;
#outer.inner();

6.6 !Important keyword

.foo () {
  background: #f5f5f5;
  color: #fff;
}
.unimportant {
  .foo();
}
.important {
  .foo() !important;
}
.unimportant {
  background: #f5f5f5;
  color: #fff;
}
.important {
  background: #f5f5f5 !important;
  color: #fff !important;
}

7 Mixins paramétricos

7.1 Parámetros

Los Mixins también puede tomar parámetros:

.border-radius(@radius) {
  -webkit-border-radius: @radius;
     -moz-border-radius: @radius;
          border-radius: @radius;
}

#header {
  .border-radius(4px);
}
#header {
  -webkit-border-radius: 4px;
     -moz-border-radius: 4px;
          border-radius: 4px;
}

7.2 Valor por defecto

.border-radius(@radius: 5px) {
  -webkit-border-radius: @radius;
     -moz-border-radius: @radius;
          border-radius: @radius;
}

#header {
  .border-radius;
}
#header {
  -webkit-border-radius: 5px;
     -moz-border-radius: 5px;
          border-radius: 5px;
}

7.3 Parámetros múltiples

.mixin(@color) {
  color: @color;
}
.mixin(@color; @padding:2) {
  padding: @padding;
}
.mixin(@color; @padding; @margin: 2) {
  margin: @margin;
}
.some .selector div {
  .mixin(#008000);
}
.some .selector div {
  color-1: #008000;
  padding-2: 2;
}

7.4 Parámetros con nombres

.mixin(  @color: black;
        @margin: 10px;
       @padding: 20px) {
  ...
}
.class1 {
  .mixin( @margin: 20px;
           @color: #33acfe);
}
.class2 {
  .mixin( #efca44;
         @padding: 40px);
}
.class1 {
  color: #33acfe;
  margin: 20px;
  padding: 20px;
}
.class2 {
  color: #efca44;
  margin: 10px;
  padding: 40px;
}

7.5 @arguments

.box-shadow(
  @x: 0;
  @y: 0;
  @blur: 1px;
  @color: #000) {

  -webkit-box-shadow: @arguments;
     -moz-box-shadow: @arguments;
          box-shadow: @arguments;
}
.big-block {
  .box-shadow(2px; 5px);
}
.big-block {
  -webkit-box-shadow:
     2px 5px 1px #000;
  -moz-box-shadow:
     2px 5px 1px #000;
  box-shadow:
     2px 5px 1px #000;
}

7.6 ...

// matches 0-N arguments
.mixin(...) {

// matches exactly 0 arguments
.mixin() {

// matches 0-1 arguments
.mixin(@a: 1) {

// matches 0-N arguments
.mixin(@a: 1; ...) {

// matches 1-N arguments
.mixin(@a; ...) {

7.7 @rest

.mixin(@a; @rest...) {

   /* @rest recoge todos
   los parámetros
   después de @a */

   /* @arguments recoge todos
   los parámetros
   (incluido @a) */
}

7.8 Pattern matching

.mixin(dark; @color) {
  color: darken(@color, 10%);
}
.mixin(light; @color) {
  color: lighten(@color, 10%);
}
.mixin(@_; @color) { /* all */
  display: block;
}

@switch: light;

.class {
  .mixin(@switch; #888);
}
.class {
  color: #a2a2a2;
  display: block;
}

7.9 Mixins como Funciones

.mixin() {
  @width:  100%;
  @height: 200px;
}

.caller {
  .mixin();
  width:  @width;
  height: @height;
}
.caller {
  width:  100%;
  height: 200px;
}
.average(@x, @y) {
  @average: ((@x + @y) / 2);
}

div {

  // "call" the mixin
  .average(16px, 50px);

  // use its "return" value
  padding: @average;
}
div {
  padding: 33px;
}

8 Mixins Condicionales

8.1 Sintaxis

.mixin (@a)
  when (lightness(@a) >= 50%) {
    background-color: black;
}
.mixin (@a)
  when (lightness(@a) < 50%) {
    background-color: white;
}
.mixin (@a) {
  color: @a;
}
.class1 { .mixin(#ddd) }
.class2 { .mixin(#555) }
.class1 {
  background-color: black;
  color: #ddd;
}
.class2 {
  background-color: white;
  color: #555;
}

8.2 Operadores

@media: mobile;

.mixin (@a)
  when (@media = mobile) { ... }

.mixin (@a)
  when (@media = desktop) { ... }

.max (@a; @b)
  when (@a > @b) { width: @a }

.max (@a; @b)
  when (@a < @b) { width: @b }

8.3 AND

.mixin (@a)
  when (isnumber(@a))
   and (@a > 0) { ... }

8.4 COMA (,)

.mixin (@a)
  when (@a > 10),
       (@a < -10) { ... }

8.5 NOT

.mixin (@b)
  when not (@b > 0) { ... }

8.6 Comprobar tipos

8.7 Comprobar unidades

8.8 Loops

.loop(@counter)
  when (@counter > 0) {

    // next iteration
    .loop((@counter - 1));

    // code for each iteration
    width: (10px * @counter);
}

div {
  .loop(5); // launch the loop
}
div {
  width: 10px;
  width: 20px;
  width: 30px;
  width: 40px;
  width: 50px;
}
.generate-columns(4);

.generate-columns(@n, @i: 1)
  when (@i =< @n) {

  .column-@{i} {
    width: (@i * 100% / @n);
  }
  .generate-columns(@n, (@i + 1));
}
.column-1 {
  width: 25%;
}
.column-2 {
  width: 50%;
}
.column-3 {
  width: 75%;
}
.column-4 {
  width: 100%;
}

9 Merge

9.1 ¿Qué es?

9.2 Coma

.mixin() {
  box-shadow+: inset 0 0 10px #555;
}
.myclass {
  .mixin();
  box-shadow+: 0 0 20px black;
}
.myclass {
  box-shadow:
    inset 0 0 10px #555,
    0 0 20px black;
}

9.3 Espacio

.mixin() {
  transform+_: scale(2);
}
.myclass {
  .mixin();
  transform+_: rotate(15deg);
}
.myclass {
  transform: scale(2) rotate(15deg);
}

9.4 Explicito

10 Selector Padre

10.1 El operador &

a {
  color: blue;
  &:hover {
    color: green;
  }
}
a {
  color: blue;
}

a:hover {
  color: green;
}

10.2 Clases repetitivas

.button {
  &-ok {
    background-image:
      url("ok.png");
  }
  &-cancel {
    background-image:
      url("cancel.png");
  }
  &-custom {
    background-image:
      url("custom.png");
  }
}
.button-ok {
  background-image: url("ok.png");
}
.button-cancel {
  background-image: url("cancel.png");
}
.button-custom {
  background-image: url("custom.png");
}

10.3 Multiples &

.link {
  & + & {
    color: red;
  }
  & & {
    color: green;
  }
  && {
    color: blue;
  }
  &, &ish {
    color: cyan;
  }
}
.link + .link {
  color: red;
}
.link .link {
  color: green;
}
.link.link {
  color: blue;
}
.link, .linkish {
  color: cyan;
}
.grand {
  .parent {
    & > & {
      color: red;
    }
    & & {
      color: green;
    }
    && {
      color: blue;
    }
    &, &ish {
      color: cyan;
    }
  }
}
.grand .parent > .grand .parent {
  color: red;
}
.grand .parent .grand .parent {
  color: green;
}
.grand .parent.grand .parent {
  color: blue;
}
.grand .parent, .grand .parentish {
  color: cyan;
}

10.4 Cambiar el orden

.header {
  .menu {
    border-radius: 5px;
    .no-borderradius & {
      background-image:
        url('img.png');
    }
  }
}
.header .menu {
  border-radius: 5px;
}
.no-borderradius .header .menu {
  background-image:
    url('img.png');
}

10.5 Explosión combinatoria

a, ul, li {
  border-top: 2px dotted #366;
  & + & {
    border-top: 0;
  }
}
a, ul, li {
  border-top: 2px dotted #366;
}

a + a, a + ul, a + li,
ul + a, ul + ul, ul + li,
li + a, li + ul, li + li {
  border-top: 0;
}

11 Funciones

11.1 Resumen

@base: #f04615;
@list: 200, 500, 1200;

.class {
  width: extract(@list, 3);
  color: saturate(@base, 5%);
  background-color:
    lighten(@base, 25%);
}

11.2 Misc Functions

11.3 String Functions

11.4 List Functions

11.5 Math Functions

11.6 Type Functions

11.7 Color Definition Functions

11.8 Color Channel Functions

11.9 Color Operation Functions

11.10 Color Blending Functions

12 Acerca de

12.1 Licencia

12.2 Fuentes

12.3 Bibliografía