Cómo funciona y cuándo es recomendable usar @extend en Stylus
La directiva @extends
de Stylus permite heredar estilos de un selector en otro. Puede ser útil cuando tenemos un elemento con los mismos estilos que otro ya definido. Al segundo elemento le decimos que extienda del primero, y nos ahorramos volver a escribir las mismas reglas.
Funciona de la siguiente manera:
.Button {
border: 1px solid #888;
border-radius: .2em;
background-color: white;
}
.Button--primary {
@extend .Button
background-color: cyan;
}
Tenemos una clase .Button
que define los estilos para los botones, y una clase .Button--primary
. .Button--primary
, y cualquier otro botón que se pueda crear posteriormente, extienden los estilos de .Button
, pues todos los botones tendrán esos estilos. Lo que hace @extend
es coger la clase en la que lo hemos definido (.Button--primary
) y juntarla con el selector .Button
de la siguiente forma:
.Button,
.Button--primary {
border: 1px solid #888;
border-radius: 0.2em;
background-color: #fff;
}
.Button--primary {
background-color: #0ff;
}
¿@extend
o @extends
?
Algo bastante curioso es que Stylus permite ambas formas, por lo que no os tenéis que preocupar de si es con o sin s.
Extendiendo de placeholder selectors
En lugar de extender de una clase, podemos extender de una variable especial que guarde los valores que se van a heredar:
$button
border: 1px solid #888;
border-radius: .2em;
background-color: white;
.Button {
@extend $button
}
.Button--primary {
@extend $button
background-color: cyan;
}
Esa variable debe comenzar por el símbolo $
. Su sintaxis es como la de cualquier otra regla en Stylus, con la única característica de que no se mostrará en el CSS final.
Diferencias con los mixins
Esto mismo podríamos tratar de hacerlo con mixins:
button()
border: 1px solid #888;
border-radius: .2em;
.Button {
button()
background-color: white;
}
.Button--primary {
button()
background-color: cyan;
}
La diferencia está en el CSS generado:
.Button {
border: 1px solid #888;
border-radius: 0.2em;
background-color: #fff;
}
.Button--primary {
border: 1px solid #888;
border-radius: 0.2em;
background-color: #0ff;
}
Con @extends
evitamos el CSS duplicado, mientras que con mixins generaremos aún más CSS cada vez que lo usemos. Por ello, @extends
nos puede venir bien en determinados casos para evitar repetir CSS. Sin embargo, usando Gzip esto tampoco supone un problema.
Por supuesto, también podríamos escribir los selectores a mano, pero el uso de @extends
nos puede ayudar a identificar qué selectores usan los estilos de otro, como en este caso, que .Button--primary
usa los mismo estilos que .Button
.
Otras formas de lograr el mismo resultado
Aprovechando las características de Stylus podemos simular la salida de @extends
de esta otra forma:
.Button
&,
&--primary
border: 1px solid #888;
border-radius: .2em;
background-color: white;
&--primary
background-color: cyan;
El código anterior genera el mismo resultado que usar @extends
. &
hace referencia a .Button
, por lo que ese código se traduce a
.Button,
.Button--primary
border: 1px solid #888;
border-radius: .2em;
background-color: white;
.Button--primary
background-color: cyan;
También podemos hacer lo mismo combinando esta sintaxis con los placeholder selectors:
$button
border: 1px solid #888;
border-radius: .2em;
background-color: white;
.Button
@extends $button
&--primary
@extends $button
background-color: cyan;
Que no es más que otra forma de escribir el mismo código de antes.
No abuses de @extend
En principio parece ser beneficioso, pero como todo, si se usa mal podemos lograr el efecto contrario. En este artículo de csswizardry.com lo explican mejor de lo que yo podría explicarlo. Recomiendo que lo lean. Dicho artículo habla sobre Sass, pero todo es aplicable a Stylus.
El principal consejo que doy es que revisen la salida de Stylus y hagan pruebas. Y tengan en mente que cuando sirvan ese archivo a los usuarios, lo van a enviar comprimido con Gzip.