Haciendo temas fácilmente con mixins de SASS

Haciendo temas fácilmente con mixins de SASS

Mientras desarrollaba el modo modo oscuro en una App de React, me encontré escapándole al anidado de Sass una y otra vez parar armar los estilos oscuros. Y justo ahí, nació este mixin.

Veamos el código

@mixin enModoOscuro {
    $selector: #{&};
    @at-root body.modo-oscuro #{$selector} {
        @content
    }
}

Es importante mencionar que esto va a funcionar en cualquier tipo de proyecto que use Sass. Y se que los Styled Components pueden completar el hacer temas fácilmente también, pero me gusta mucho Scss y tener a mis componentes con sus propios archivos de estilo.

Análisis

Cuando el modo oscuro está habilitado, <body> recibe la clase modo-oscuro. Y para anteponer body.modo-oscuro al selector, el mixin funciona así:

  • $selector: parsea nuestro selector actual haciendo uso de **& (selector de padre)** y #{}, luego lo almacena en la variable.
  • @at-root: mueve el siguiente selector a la raíz del documento, escapando el anidado actual.
    • body.modo-oscuro: la clase que va a ser responsable por nuestros estilos de modo oscuro.
      • #{selector}: vuelve a agregar nuestro selector anterior.
        • @content: todo lo que agreguemos entre las llaves, {} en nuestro **include** va acá.

Uso

.solo-una-caja {
    background: white; // ☀
    color: black; // ☀
    width: 100px;
    height: 100px;
    // Dark Theme styles
    @include enModoOscuro {
        background: black; // 🌙
        color: white; // 🌙
    }
}

Después de compilar el código a CSS se va a ver así:

.solo-una-caja {
    background: white;
    color: black;
    width: 100px;
    height: 100px;
}
body.modo-oscuro.solo-una-caja {
    background: black;
    color: white;
}

🧬 Evolucionando el mixin: Múltiples temas

¿Por qué conformarnos con modo oscuro? Creemos muchos temas con ¡un solo mixin para gobernarlos a todos!

@mixin enTema($tema: "default") {
    $selector: #{&};
    @at-root body.tema-#{$tema} #{$selector} {
        @content
    }
}

Uso

Ahora podemos pasarle un argumento a nuestro mixin y agregar estilos dinámicamente a los temas que creemos.

.navegacion {
    background: white;
    color: black;
    width: 100%;
    height: 52px;
    // Estilos de Temas
    @include enTema("rojo") {
        background: red; // 🟥
    }
    @include enTema("verde") {
        background: green; // 🟩
    }
    @include enTema("azul") {
        background: blue; // 🟦
    }
    @include enTema("halloween") {
        background: purple; // 👻
    }
}

Después de compilar el código a CSS se va a ver así:

.navegacion {
    background: white;
    color: black;
    width: 100%;
    height: 52px;
}

body.tema-rojo .navegacion {
    background: red;
}

body.tema-azul .navegacion {
    background: blue;
}

body.tema-verde .navegacion {
    background: green;
}

body.tema-halloween .navegacion {
    background: purple;
}

💡Algunas ideas

Para mantener el post conciso y simple, dejo un par de ideas que pueden agregar a su proyecto para mejorar lo visto hasta acá.

  • Variables de CSS
  • Una variable como $temas con valores predefinidos para chequear que el argumento que se pasa al mixin enTema sea válido.
  • Modo oscuro "Automático" con la regla de CSS filter: invert().

Conclusión

Usando la directiva de SASS @at-root en nuestros mixins vamos a ahorrar mucho tiempo, creando selectores específicos para nuestros temas con gran facilidad, apoyándonos en la poderosa especificidad de CSS.

Si el post fue de ayuda o crees ves algo que pueda mejorar ¡dejame un comentario más abajo!

¡Hasta la próxima 👋!

English version!