Herencia en SASS
Este artículo explica la herencia en SASS.
Explicaremos la herencia en SASS con ejemplos prácticos.
YouTube Video
Herencia en SASS
La herencia en SASS (@extend) es un mecanismo que te permite aplicar los estilos de un selector a otro sin duplicación. Dado que los mismos estilos se 'combinan' y se generan para múltiples elementos en el marcado, el CSS resultante tiende a ser menos redundante; sin embargo, si se usa incorrectamente, puede derivar en combinaciones indeseadas de selectores.
Básicos: Cómo usar @extend
A continuación se muestra un ejemplo básico donde .btn--primary hereda los estilos de .btn. @extend es una directiva que extiende el selector objetivo.
1// Base button styles
2.btn {
3 padding: 0.5rem 1rem;
4 border-radius: 4px;
5 border: 1px solid #ccc;
6 background: white;
7 color: #333;
8}
9
10/* Primary button extends the base .btn */
11.btn--primary {
12 @extend .btn;
13 background: #007bff;
14 color: white;
15}- Al usar
@extend,.btn--primaryhereda los estilos base de.btny sobreescribe solo las partes necesarias.
CSS generado
1.btn, .btn--primary {
2 padding: 0.5rem 1rem;
3 border-radius: 4px;
4 border: 1px solid #ccc;
5 background: white;
6 color: #333;
7}
8
9.btn--primary {
10 background: #007bff;
11 color: white;
12}Mejor práctica: Uso de placeholders (%placeholder)
Los selectores de marcador de posición (%name) son selectores que no se generan en el CSS. Se utilizan ampliamente, especialmente cuando se desea compartir estilos comunes de forma segura exclusivamente para la herencia entre varios componentes.
1// %placeholder will not be output directly
2%card-base {
3 padding: 1rem;
4 border-radius: 6px;
5 box-shadow: 0 1px 3px rgba(0,0,0,0.08);
6 background: #fff;
7}
8
9/* Components extend the placeholder */
10.card {
11 @extend %card-base;
12 border: 1px solid #eee;
13}
14
15.panel {
16 @extend %card-base;
17 border: 1px solid #ddd;
18}.cardy.panelheredan ambos de%card-base, lo que les permite compartir estilos comunes y añadir diferencias según sea necesario.
CSS generado
1.card, .panel {
2 padding: 1rem;
3 border-radius: 6px;
4 box-shadow: 0 1px 3px rgba(0,0,0,0.08);
5 background: #fff;
6}
7
8.card {
9 border: 1px solid #eee;
10}
11
12.panel {
13 border: 1px solid #ddd;
14}Herencia múltiple (varios @extend)
Se pueden heredar múltiples placeholders o clases al mismo tiempo. Aunque mejora la reutilización de estilos, es importante hacer un seguimiento de qué reglas se combinan con qué selectores.
1%btn-base {
2 display: inline-block;
3 padding: 0.5rem 1rem;
4 border-radius: 3px;
5}
6
7%btn-large {
8 padding: 0.75rem 1.5rem;
9 font-size: 1.125rem;
10}
11
12/* Composite button that extends both placeholders */
13.btn--lg {
14 @extend %btn-base;
15 @extend %btn-large;
16 background: #222;
17 color: #fff;
18}- Este es un ejemplo donde un botón hereda dos placeholders, uno para la 'base' y otro para el 'tamaño'.
.btn--lghereda tanto%btn-basecomo%btn-large, combinando la estructura básica con un tamaño mayor.
CSS generado
1.btn--lg {
2 display: inline-block;
3 /* %btn-large overrides the padding from %btn-base */
4 padding: 0.75rem 1.5rem;
5 border-radius: 3px;
6 font-size: 1.125rem;
7 background: #222;
8 color: #fff;
9}Comportamiento de @extend (mecanismo de combinación) y precauciones sobre la 'explosión de selectores'
@extend combina y genera todos los selectores coincidentes, lo que a veces puede producir combinaciones no deseadas de selectores.
El siguiente ejemplo muestra cómo la salida puede aumentar cuando la misma clase base se extiende en varios lugares.
1/* Many components extend .utility */
2/* A generic utility class */
3.utility {
4 margin-bottom: 1rem;
5}
6
7/* Nested selectors that extend .utility */
8.header {
9 @extend .utility;
10 .title {
11 font-weight: bold;
12 }
13}
14
15.footer {
16 @extend .utility;
17 .note {
18 color: #888;
19 }
20}
21
22.article {
23 @extend .utility;
24 .content {
25 line-height: 1.6;
26 }
27}
28
29.sidebar {
30 @extend .utility;
31 .section {
32 padding: 1rem;
33 }
34}- Cuando varios componentes heredan
.utility, los selectores se combinan en uno solo y, en proyectos a gran escala, esto puede hacer que el CSS aumente excesivamente.
CSS generado
1.utility,
2.header,
3.footer,
4.article,
5.sidebar {
6 margin-bottom: 1rem;
7}
8
9.header .title {
10 font-weight: bold;
11}
12
13.footer .note {
14 color: #888;
15}
16
17.article .content {
18 line-height: 1.6;
19}
20
21.sidebar .section {
22 padding: 1rem;
23}@extend y .clase vs selectores de elemento (etiquetas) — Prioridad y efectos secundarios
@extend puede aplicarse no solo a clases sino también a selectores de elementos. Sin embargo, extender elementos incrementa el alcance afectado, aumentando el riesgo de que las reglas se apliquen inadvertidamente en lugares no previstos.
A continuación se muestra un ejemplo de extensión de un selector de elemento y el efecto que puede tener.
1/* Extending an element selector (not recommended) */
2h1 {
3 font-size: 2rem;
4 margin-bottom: 0.5rem;
5}
6
7/* If you extend h1, the resulting selector will include your class with h1 */
8.title {
9 @extend h1;
10 color: #333;
11}
12
13/* Output becomes:
14h1, .title { font-size: 2rem; margin-bottom: 0.5rem; }
15*/- En este ejemplo, heredar el selector de elemento
h1provoca que.titlese combine con los mismos estilos deh1. - Aunque puede parecer conveniente en casos de pequeña escala, a medida que el proyecto crece, las reglas para
h1podrían combinarse inesperadamente con.title, haciendo los estilos más complejos y reduciendo la mantenibilidad. Por lo tanto, diseñar los estilos principalmente en torno a clases y marcadores de posición facilita su mantenimiento.
CSS generado
1h1,
2.title {
3 font-size: 2rem;
4 margin-bottom: 0.5rem;
5}
6
7.title {
8 color: #333;
9}Casos de uso para @extend y !optional
Si especificas !optional con @extend, puedes suprimir los errores cuando el objetivo de la herencia no existe. Esto es especialmente útil en código tipo biblioteca o en casos donde los marcadores de posición se definen condicionalmente.
El siguiente es un ejemplo de cómo intentar heredar de forma segura una clase que puede no existir, usando !optional.
1/* Try to extend a class that might not exist */
2.component {
3 @extend .maybe-existing !optional;
4 padding: 1rem;
5}- Si
.maybe-existingno existe, no sucede nada y se omite. Puedes usar esto cuando quieras intentar una extensión de manera segura.
CSS generado
1.component {
2 padding: 1rem;
3}Comparación de @extend y mixins (@mixin / @include)
@extend y @mixin a veces tienen propósitos similares, pero sus salidas y casos de uso difieren.
-
@extend- El CSS generado reduce la redundancia al combinar selectores.
- Debido a que los selectores se combinan tras la generación, pueden ocurrir combinaciones no deseadas.
- No se pueden pasar parámetros (aunque esto se puede compensar combinando placeholders).
-
@mixin/@include- Cada llamada duplica los estilos (causando una salida redundante).
- Puedes pasar parámetros e incluir lógica como condicionales o ciclos.
- La salida es más predecible, pero el tamaño del archivo aumenta.
A continuación se muestra una comparación usando ambos @mixin y @extend para implementar los mismos estilos de botón.
1/* Mixin approach */
2@mixin btn-styles($bg, $color) {
3 display: inline-block;
4 padding: 0.5rem 1rem;
5 background: $bg;
6 color: $color;
7 border-radius: 4px;
8}
9
10/* Use mixin */
11.btn {
12 @include btn-styles(white, #333);
13}
14
15.btn--primary {
16 @include btn-styles(#007bff, white);
17}
18
19/* Extend approach (shared placeholder) */
20%btn-base {
21 display: inline-block;
22 padding: 0.5rem 1rem;
23 border-radius: 4px;
24}
25
26.btn2 {
27 @extend %btn-base;
28 background: white;
29 color: #333;
30}
31
32.btn2--primary {
33 @extend %btn-base;
34 background: #007bff;
35 color: white;
36}@mixinte permite insertar estilos de manera flexible, mientras que@extendconsolida la salida eficientemente, por lo que puedes usar cada uno según el caso de uso.
CSS generado
Salida de @mixin
1.btn {
2 display: inline-block;
3 padding: 0.5rem 1rem;
4 background: white;
5 color: #333;
6 border-radius: 4px;
7}
8
9.btn--primary {
10 display: inline-block;
11 padding: 0.5rem 1rem;
12 background: #007bff;
13 color: white;
14 border-radius: 4px;
15}Salida de @extend
1.btn2,
2.btn2--primary {
3 display: inline-block;
4 padding: 0.5rem 1rem;
5 border-radius: 4px;
6}
7
8.btn2 {
9 background: white;
10 color: #333;
11}
12
13.btn2--primary {
14 background: #007bff;
15 color: white;
16}Directrices prácticas
La herencia en SASS es una característica poderosa para aumentar la reutilización de estilos. Sin embargo, un uso incorrecto puede hacer que la combinación de estilos sea compleja y disminuya la mantenibilidad. A continuación se presentan algunos puntos clave para usar la herencia de forma segura y eficiente.
- Usa marcadores de posición para estilos puramente comunes de componentes como la estructura y el diseño. Además, si se requiere parametrización dinámica, puedes usar
@mixin. - Debes evitar heredar directamente elementos HTML como
h1. Pueden producirse combinaciones de selectores no previstas, lo que puede dar lugar a la generación de CSS inesperado. - Usar convenciones de nombres como BEM o prefijos claros para indicar el propósito de cada placeholder ayuda a mantener la seguridad.
- Es más seguro usar
@extenddentro del mismo archivo. Especialmente en proyectos grandes, se recomienda diseñar la herencia dentro del alcance de cada componente para facilitar el seguimiento de las relaciones de herencia.
Resumen
La función @extend en SASS es una forma conveniente de reutilizar estilos comunes de manera eficiente y garantizar la coherencia del diseño. Sin embargo, como las combinaciones de selectores pueden volverse fácilmente complejas, es necesario utilizar esta función con cuidado y en un alcance limitado. Agrupando los estilos compartidos con selectores de marcador de posición (%placeholder) y usando @mixin para las partes que requieran parámetros dinámicos, puedes mantener un diseño sencillo y fácil de mantener.
Puedes seguir el artículo anterior utilizando Visual Studio Code en nuestro canal de YouTube. Por favor, también revisa nuestro canal de YouTube.