viernes, 30 de mayo de 2014

Less, @imports (inline) y BOM

Trabajando con Less me he encontrado con un pequeño problema que quiero compartir en el blog.

El caso es que tengo varios ficheros .less así como también varios ficheros .css. Aunque podría utilizar los Bundle de ASP.NET.MVC para unirlos a todos en un sólo fichero (el CSS resultante de preprocesar los ficheros .less más los .css estáticos), me gustaría poco a poco ir utilizando más instrucciones Less para ir conociendo mejor la herramienta.

Incluir otros ficheros .less dentro de un fichero .less es muy sencillo, simplemente debemos importarlo y el fichero será preprocesado. Por ejemplo:

Principal.less

.principal {

  background-color: red;

}

@import "Secundario.less";

Secundario.less

.secundario {

  background-color: yellow;

}

Principal.css

.principal {

  background-color: red;

}

.secundario {

  background-color: yellow;

}

Sin embargo, si queremos incluir un fichero .css dentro de un .less tendremos que afinar un poco más en la instrucción @imports. Imaginemos que tenemos dos fichero .css cuyo contenido queremos incluir en Principal.less.

Estatico1.css

.estatico1 {

    background-color: blue;

}

Estatico2.css

.estatico2 {

    background-color: brown;

}

Principal.less

@import "Estatico1.css";
@import "Estatico2.css";

.principal {

  background-color: red;

}

@import "Secundario.less";

El resultado de Principal.css es el siguiente:

@import "Estatico1.css";

@import "Estatico2.css";

.principal {

  background-color: red;

}

.secundario {

  background-color: yellow;

}

Claramente no era el resultado esperado, nosotros queríamos incluir los ficheros Estatico1.css y Estatico2.css en la salida, no agregar la instrucción @import en CSS. En cualquier caso esto no es un problema, la documentación es clara al respecto:

“If the file has a .css extension it will be treated as CSS and the @import statement left as-is”

Con un pequeño cambio podemos incluir su contenido en la salida:

Principal.less

@import (inline) "Estatico1.css";

@import (inline) "Estatico2.css";

.principal {

  background-color: red;

}

@import "Secundario.less";

Y su salida:

.estatico1 {

  background-color: blue;

}

.estatico2 {

  background-color: brown;

}

.principal {

  background-color: red;

}

.secundario {

  background-color: yellow;

}

En este punto parece estar todo resuelto, pero… ¡Cuidado con el BOM!

Si por algún extraño motivo la codificación del texto del segundo o siguiente fichero CSS a incluir “inline” es UTF-8 con marca de BOM, entonces tendrás un problema. Fíjate que digo el segundo o siguiente, el primero da igual. Para verlo en directo guardaré el fichero Estatico2.css como UTF-8 con BOM y después veremos que pasa:

image

Aunque aparentemente el resultado final es el mismo, vemos que hay un problema en cliente:

image

Ese puntito rojo es malvado, es el BOM del fichero Estatico2.css que hace que de ahí para abajo no se aplica ninguna regla CSS :(

¿Cómo solucionar esto?

En mi caso he optado por no utilizar la instrucción @import (inline) porque no podemos garantizar que todos los ficheros importados tengan una codificación distinta de UTF-8 con BOM. Hoy por hoy descargamos ficheros .css de múltiples lugares (Nuget, Github, Bower, etc.) y no me podemos (al menos a mí no me apetece) estar vigilando su codificación. Además, teniendo los Bundle de ASP.NET MVC el tema está resuelto porque (y no me preguntes por qué pero lo agradezco), cuando ASP.NET genera el bundle SÍ elimina esa marca de BOM :)

Además, tener UTF-8 con BOM no es tan excepcional como parece, sobre todo si trabajamos con Visual Studio que agrega mágicamente el BOM a cualquier fichero UTF-8 editado http://vlasovstudio.com/fix-file-encoding/

Cabe mencionar que esto me ha pasado utilizando Web Essentials 2013 2.1
“Web Essentials uses the node-less compiler and it always uses the latest version”.

Un saludo!

No hay comentarios:

Publicar un comentario