Empecé desarrollando aplicaciones web, hasta que di el salto a la docencia.
Actualmente soy Asesor Técnico Docente en el servicio TIC de la D.G de Infraestructuras y Servicios de la Consejería de Educación, Juventud y Deporte de la Comunidad de Madrid.
Además colaboro como formador especializado en tecnologías de desarrollo.
Hackathon Lovers http://hackathonlovers.com: un grupo creado para emprendedores y desarrolladores amantes de los hackathones.
Password Manager Generator http://pasmangen.github.io: un gestor de contraseñas online.
MarkdownSlides https://github.com/asanzdiego/markdownslides: un script para crear slides a partir de ficheros MD.
Mi nick: asanzdiego
Less es un pre-procesador de CSS.
Añade características como variables, mixins, funciones, etc.
El CSS es así más fácil de mantener, personalizable y extensible.
Less tiene una sintaxis parecida a CSS.
Less se puede ejecutar desde NodeJS, desde un navegador, o desde Rhino.
Además existen muchas herramientas que permiten compilar los archivos y ver los cambios en caliente.
Es el preprocesador que usa Bootstrap 3.0.
$ npm install -g less
$ lessc styles.less > styles.css
Es la forma más fácil para empezar, pero no es recomendable usarlo así en producción.
Descargar: https://github.com/less/less.js/archive/master.zip
Enlazar tu archivo less que quieras precompilar, y luego el js de less:
<link rel="stylesheet/less" type="text/css" href="styles.less" />
<script src="less.js" type="text/javascript"></script>
a,
.link {
color: #428bca;
}
.widget {
color: #fff;
background: #428bca;
}
@color: #428bca
a,
.link {
color: @color;
}
.widget {
color: #fff;
background: @color;
}
@mySelector: banner;
.@{mySelector} {
font-weight: bold;
line-height: 40px;
margin: 0 auto;
}
.banner {
font-weight: bold;
line-height: 40px;
margin: 0 auto;
}
@images: "../img";
body {
color: #444;
background: url("@{images}/white-sand.png");
}
@property: color;
.widget {
@{property}: #0ee;
background-@{property}: #999;
}
.widget {
color: #0ee;
background-color: #999;
}
@fnord: "I am fnord.";
@var: "fnord";
content: @@var;
content: "I am fnord.";
Las variables no tienen que ser declaradas antes de ser utilizados.
Eso es válido:
.lazy-eval {
width: @var;
}
@var: @a;
@a: 9%;
.lazy-eval {
width: 9%;
}
@var: 0;
.class {
@var: 1;
.brass {
@var: 2;
three: @var;
@var: 3;
}
one: @var;
}
.class {
one: 1;
}
.class .brass {
three: 3;
}
.animal {
background-color: black;
color: white;
}
Y queremos tener un subtipo de animal que sobrescriba la propiedad background-color.
Podemos hacer lo siguiente:
<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;
}
.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;
}
Los Mixins son una forma de reutilizar propiedades ya definidas:
Imaginemos la clase .bordered:
.bordered {
border-top: dotted 1px black;
border-bottom: solid 2px black;
}
#menu a {
color: #111;
.bordered;
}
.post a {
color: red;
.bordered;
}
.a, #b {
color: red;
}
.mixin-class {
.a();
}
.mixin-id {
#b();
}
.my-mixin {
color: black;
}
.my-other-mixin() {
background: white;
}
.class {
.my-mixin;
.my-other-mixin;
}
.my-mixin {
color: black;
}
.class {
color: black;
background: white;
}
.my-hover-mixin() {
&:hover {
border: 1px solid red;
}
}
button {
.my-hover-mixin();
}
button:hover {
border: 1px solid red;
}
#outer {
.inner {
color: red;
}
}
#outer > .inner;
#outer > .inner();
#outer .inner;
#outer .inner();
#outer.inner;
#outer.inner();
.foo () {
background: #f5f5f5;
color: #fff;
}
.unimportant {
.foo();
}
.important {
.foo() !important;
}
.unimportant {
background: #f5f5f5;
color: #fff;
}
.important {
background: #f5f5f5 !important;
color: #fff !important;
}
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;
}
.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;
}
Los parámetros se pueden separar por coma (,) o por punto y coma (;).
Se recomienda el punto y coma (;).
La coma (,) tiene doble sentido: se puede interpretar como un separador de parámetros Mixin o como separador de los elementos de una lista.
Si el compilador encuentra al menos un punto y coma (;) asume que los argumentos se separan por punto y coma y los comas pertenecen a listas.
Se puede tener varios mixins con el mismo nombre y el mismo número de parámetros, pues Less utilizará todos los posibles:
.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;
}
.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;
}
.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;
}
// 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; ...) {
.mixin(@a; @rest...) {
/* @rest recoge todos
los parámetros
después de @a */
/* @arguments recoge todos
los parámetros
(incluido @a) */
}
.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;
}
.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;
}
.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;
}
@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 }
.mixin (@a)
when (isnumber(@a))
and (@a > 0) { ... }
.mixin (@a)
when (@a > 10),
(@a < -10) { ... }
.mixin (@b)
when not (@b > 0) { ... }
Tenemos las siguientes funciones para comprobar tipos:
Tenemos las siguientes funciones para comprobar unidades:
.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%;
}
.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;
}
.mixin() {
transform+_: scale(2);
}
.myclass {
.mixin();
transform+_: rotate(15deg);
}
.myclass {
transform: scale(2) rotate(15deg);
}
a {
color: blue;
&:hover {
color: green;
}
}
a {
color: blue;
}
a:hover {
color: green;
}
.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");
}
.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;
}
.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');
}
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;
}
@base: #f04615;
@list: 200, 500, 1200;
.class {
width: extract(@list, 3);
color: saturate(@base, 5%);
background-color:
lighten(@base, 25%);
}
http://lesscss.org/functions/#misc-functions
http://lesscss.org/functions/#string-functions:
http://lesscss.org/functions/#list-functions
http://lesscss.org/functions/#math-functions
http://lesscss.org/functions/#math-functions
http://lesscss.org/functions/#type-functions
http://lesscss.org/functions/#color-definitions
http://lesscss.org/functions/#color-channel
http://lesscss.org/functions/#color-operations
http://lesscss.org/functions/#color-blending