DÍA 14

Introducción a PostCSS

Sé lo que estás pensando: “Oh no, ahora que había aprendido Sass aparece otra herramienta más que tengo que aprender, esto nunca termina…” Pero tranquilo, no vine hasta Octuweb para decirte que tenés que cambiar tu forma de trabajar. Este artículo fue la excusa perfecta que encontré para investigar y curiosear sobre PostCSS. Te cuento lo que averigüé.


Recuerdo exactamente la primera vez que escuché (leí) sobre PostCSS. Fue en [este tweet] de Mark Otto (creador de Bootstrap) en el que anunciaba que Bootstrap 4 iba a cambiar LESS por Sass. Siendo usuario de Sass lo recibí como una gran noticia. En ese mismo tweet Mark decía que la versión 5 de Bootstrap “probablemente” fuera en PostCSS. ¿PostCSS? ¿A qué se refería? ¿Era un chiste? Jamás había escuchado el término, así que hice lo que supongo que todos hacemos cuando conocemos una nueva palabra: buscarla en Google.

En ese momento no me pareció para nada interesante, leí un poco la [página de Github] del proyecto y luego la cerré, sin más.

Tiempo después de ese episodio fui encontrando cada vez en más lugares y más frecuentemente la mención de PostCSS, y mi curiosidad fue en aumento, aunque nunca podía hacerme del tiempo para investigarlo más a fondo. Como ya dije, este artículo fue la excusa perfecta.

Qué es

Quizás sea más fácil definir PostCSS por lo que no es. Por su nombre, es fácil pensar que PostCSS no es un “preprocesador”, como nuestros queridos LESS, Sass o Stylus. Pero a pesar de su nombre, PostCSS tampoco es un “postprocesador”. La definición exacta la encontramos en la página del proyecto en Github:

PostCSS es una herramienta para transformar estilos mediante plugins de JavaScript

PostCSS es entonces un módulo de Node.js que analiza tu CSS y lo transforma en un árbol de sintaxis abstracta (AST). Ese AST puede ser modificado o interpretado mediante funciones o plugins JavaScript. Luego, PostCSS convierte nuevamente ese AST en texto, con el cual puede generarse un archivo.

Es decir PostCSS no altera tu CSS de ninguna manera, a menos que vos se lo indiques. Habiéndolo definido de esta manera, y sin mucha originalidad, podríamos decir entonces que PostCSS no es un preprocesador ni un postprocesador, sino simplemente un “procesador”, a secas.

Para qué sirve

Esta especificidad de PostCSS es una de las razones por las cuales se ha vuelto una herramienta tan popular. Básicamente con PostCSS podés hacer lo que quieras. ¿Sos aventurero y querés reemplazar tu preprocesador por él? Adelante. ¿No concebís tu vida sin Sass y no querés reemplazarlo? Podés usar los dos tranquilamente. ¿Tenés ganas de escribir “CSS del futuro” que todavía está en los borradores de la W3C? Es tu momento.

Esta es la clave de PostCSS. No es nada en particular. Es lo que vos quieras que sea.

Cómo usarlo

PostCSS está disponible para la mayoría de los “tasks runners” a los que estamos acostumbrados: Grunt, Gulp, Broccoli, etc. Si ya estás usando alguno de ellos, la instalación no puede ser más sencilla. Los ejemplos que veremos en este artículo estarán escritos con la sintaxis de Gulp. Asumiendo que ya tenés tu proyecto configurado, lo único que tenés que hacer para instalar PostCSS es tipear:

npm install --save-dev gulp-postcss

Plugins

Dijimos que PostCSS no hace nada con tus estilos a menos que se lo indiques. Una herramienta que no hace nada no sería tan popular si todos tuviéramos que escribir hasta las funcionalidades más básicas. Es por eso que la otra razón por la cual esta herramienta se ha vuelto tan popular es su ecosistema de plugins. Realmente la variedad que hay es increíble, y recordemos que cualquiera puede escribir su propio plugin y aportar a la comunidad. Una de las principales reglas a la hora de hacer un plugin para PostCSS es:

Hacé solamente una cosa, y hacela bien

Es por eso que, además de los plugins, podemos utilizar también “paquetes” (packs) de plugins, que agrupan plugins más pequeños alrededor de cierta temática. Pero vayamos por partes. No puedo seguir hablando de PostCSS sin hablar de Autoprefixer.

Autoprefixer

Autoprefixer no es solamente el plugin por excelencia de PostCSS, sino incluso su antecesor. La función de autoprefixer es agregar los “vendor prefixes” para aquellas reglas de tu CSS que lo necesiten. No sólo agregará, sino que también removerá aquellos “vendor prefixes” que ya no sean necesarios. De manera similar a como instalamos PostCSS, este plugin se instala tipeando:

npm install --save-dev autoprefixer
Nota: el parámetro “–save-dev” es utilizado para guardar en tu package.json cada uno de los paquetes node que instales. De esta forma si compartís el proyecto, cualquiera podrá utilizar el comando “npm install” para instalar exactamente los mismos paquetes que necesita el proyecto.

Una vez instalado autoprefixer, necesitamos decirle a Gulp que queremos utilizarlo, via PostCSS. La forma más simple de realizar esto es la siguiente:

var gulp = require('gulp');

gulp.task('autoprefixer', function() {

  var postcss = require('gulp-postcss');
  var autoprefixer = require('autoprefixer');

  return gulp.src('./src/*.css')
    .pipe(
      postcss([
        autoprefixer
      ])
    ).pipe(
      gulp.dest('./dest')
    );

});

Básicamente cada vez que escribamos “gulp autoprefixer” en la línea de comandos, Gulp buscará todos los archivos de extensión CSS que encuentre en la carpeta “src” y los enviará por su “tubería” (pipe) a PostCSS. PostCSS accionará el plugin (o los plugins) que definamos, en este caso autoprefixer, y una vez finalizada la tarea volverá a la tubería de Gulp, quien finalmente escribirá los archivos procesados en la carpeta “dest”. Supongamos entonces que nuestro archivo “src/style.css” tiene el siguiente contenido:

.rounded {
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
    border-radius: 3px;
}

.flex {
    display: flex;
}

PostCSS, o más bien el plugin autoprefixer de PostCSS, transformará nuestro CSS y entregará via Gulp un archivo “dest/style.css” que se verá de la siguiente manera:

.rounded {
    border-radius: 3px;
}

.flex {
    display: -webkit-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
}

Autoprefixer removió los prefijos que no eran necesarios y agregó los que sí lo son.

Paquetes de plugins

Como decíamos antes los plugins de PostCSS son bien modulares y realizan tareas bien específicas. Dependiendo de lo que queramos hacer, a veces es más conveniente utilizar un paquete de plugins. Un paquete no es más que un grupo de plugins que nos permitirá instalar cómodamente varios grupos de plugins relacionados. Por ejemplo, uno de los más conocidos es cssnext. Su lema: “Usa hoy la sintaxis CSS del mañana”. Este paquete agrupa plugins como: autoprefixer, postcss-custom-properties, postcss-calc, postcss-custom-media, postcss-media-minmax, postcss-custom-selector, entre otros.

Otro paquete interesante es PreCSS, que, como podrás adivinar por su nombre, agrupa plugins con el objetivo de poder utilizar una sintaxis tipo Sass en tu CSS. Podrás utilizar variables, imports, mixins, extends, etc, sin necesidad de tu preprocesador.

En la página de Github vas a poder encontrar la lista de plugins completa . Recientemente también se estrenó PostCSS.parts un catálogo de plugins de PostCSS.

¿Y ahora qué?

Y ahora depende de lo que quieras hacer. Creo que lo importante es saber y entender de qué va todo esto de PostCSS. Yo por ejemplo no me veo reemplazando mi amado Sass por el paquete PreCSS, pero por supuesto que utilizo PostCSS con su plugin autoprefixer, y leyendo la lista de plugins se encuentra funcionalidades que pueden ser muy útiles.

Por ejemplo, postcss-round-subpixels sirve para redondear aquellas declaraciones que tengan valores con sub-píxeles (por ejemplo: 10.747347539275px) a su valor absoluto más cercano. Este tipo de valores se generan muchas veces cuando usamos funciones matemáticas con Sass, por ejemplo, y la forma en que los navegadores los tratan es muy inconsistente. Ejemplo extraído de la página del proyecto:

El siguiente contenido:

.down {
    height:123.456px;
    width:321.123px;
}
.up {
    height:987.654px;
    width:1234.567px;
}
.dont-touch {
    height:12.345rem;
    width:98.7654%;
}

Será procesado de la siguiente manera:

.down {
    height: 123px;
    width:  321px;
}
.up {
    height: 988px;
    width:  1235px;
}
.dont-touch {
    height: 12.345rem;
    width:  98.7654%;
}

Pixrem permite utilizar la unidad “rem” y calculará su valor correspondiente en “px”, para utilizar como fallback. Ejemplo extraído de la página del proyecto:

El siguiente contenido:

.sky {
    margin: 2.5rem 2px 3em 100%;
    color: blue;
}

Será procesado como:

.sky {
    margin: 80px 2px 3em 100%;
    margin: 2.5rem 2px 3em 100%;
    color: blue;
}

postcss-at2x generará el código necesario para utilizar imágenes retina a partir de una única declaración. Ejemplo extraído de la página del proyecto:

El siguiente contenido:

.logo {
    background: red url('/public/images/logo.png') no-repeat 0 0 at-2x;
}

.banner {
    background: url(/public/images/cool.png) at-2x,url(http://example.com/flowers-pattern.jpg) at-2x;
}

Será procesado como:

.logo {
    background: red url('/public/images/logo.png') no-repeat 0 0;
}

.banner {
    background: url(/public/images/cool.png), url(http://example.com/flowers-pattern.jpg);
}

@media (min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5), (min-resolution: 144dpi), (min-resolution: 1.5dppx) {
    .logo {
        background: red url('/public/images/logo@2x.png') no-repeat 0 0;
    }
}

@media (min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5), (min-resolution: 144dpi), (min-resolution: 1.5dppx) {
    .banner {
        background: url(/public/images/cool@2x.png), url(http://example.com/flowers-pattern@2x.jpg);
    }
}

postcss-bem-linter se asegura que los nombres de las clases respeten la convención BEM.

En fin, realmente las posibilidades son casi infinitas. Será cuestión de ir probándolo de a poco y ver cómo se siente… lo que creo que es seguro es que PostCSS llegó para quedarse.