Conseguir que JavaScript hable con CSS y Sass | Programar Plus

JavaScript y CSS han convivido durante más de 20 años. Y, sin embargo, ha sido muy difícil compartir datos entre ellos. Ha habido grandes intentos, seguro. Pero tengo algo simple e intuitivo en mente, algo que no implica un cambio estructural, sino más bien poner en uso propiedades personalizadas de CSS e incluso variables Sass.

Propiedades personalizadas de CSS y JavaScript

Las propiedades personalizadas no deberían ser tan sorprendentes aquí. Una cosa que siempre han podido hacer desde que los navegadores comenzaron a admitirlos es trabajar junto con JavaScript para establecer y manipular los valores.

Específicamente, sin embargo, podemos usar JavaScript con propiedades personalizadas de varias maneras. Podemos establecer el valor de una propiedad personalizada usando setProperty:

document.documentElement.style.setProperty("--padding", 124 + "px"); // 124px

También podemos recuperar variables CSS usando getComputedStyle en JavaScript. La lógica detrás de esto es bastante simple: las propiedades personalizadas son parte del estilo, por lo tanto, son parte del estilo calculado.

getComputedStyle(document.documentElement).getPropertyValue('--padding') // 124px

Mismo tipo de trato con getPropertyValue. Eso nos permitió obtener el valor de la propiedad personalizada de un estilo en línea del marcado HTML.

document.documentElement.style.getPropertyValue("--padding'"); // 124px

Tenga en cuenta que las propiedades personalizadas tienen un alcance. Esto significa que necesitamos obtener estilos calculados a partir de un elemento en particular. Como definimos previamente nuestra variable en :root los obtenemos en el elemento HTML.

Variables de Sass y JavaScript

Sass es un lenguaje de preprocesamiento, lo que significa que se convierte en CSS antes de que forme parte de un sitio web. Por esa razón, no es posible acceder a ellos desde JavaScript de la misma manera que las propiedades personalizadas de CSS, a las que se puede acceder en el DOM como estilos computados.

Necesitamos modificar nuestro proceso de construcción para cambiar esto. Dudo que no exista una gran necesidad de esto en la mayoría de los casos, ya que los cargadores a menudo ya forman parte de un proceso de compilación. Pero si ese no es el caso en su proyecto, necesitamos tres módulos que sean capaces de importar y traducir módulos Sass.

Así es como se ve en una configuración de paquete web:

module.exports = {
 // ...
 module: {
  rules: [
   {
    test: /.scss$/,
    use: ["style-loader", "css-loader", "sass-loader"]
   },
   // ...
  ]
 }
};

Para hacer que las variables Sass (o, específicamente, SCSS en este caso) estén disponibles para JavaScript, necesitamos “exportarlas”.

// variables.scss
$primary-color: #fe4e5e;
$background-color: #fefefe;
$padding: 124px;

:export {
  primaryColor: $primary-color;
  backgroundColor: $background-color;
  padding: $padding;
}

El :export block es el paquete web de salsa mágica que utiliza para importar las variables. Lo bueno de este enfoque es que podemos cambiar el nombre de las variables usando la sintaxis de camelCase y elegir lo que exponemos.

Luego importamos el archivo Sass (variables.scss) en JavaScript, dándonos acceso a las variables definidas en el archivo.

import variables from './variables.scss';

/*
 {
  primaryColor: "#fe4e5e"
  backgroundColor: "#fefefe"
  padding: "124px"
 }
*/

document.getElementById("app").style.padding = variables.padding;

Existen algunas restricciones en el :export sintaxis que vale la pena mencionar:

  • Debe estar en el nivel superior, pero puede estar en cualquier lugar del archivo.
  • Si hay más de uno en un archivo, las claves y los valores se combinan y exportan juntos.
  • Si un particular exportedKey está duplicado, el último (en el orden de origen) tiene prioridad.
  • Un exportedValue puede contener cualquier carácter que sea válido en los valores de declaración CSS (incluidos los espacios).
  • Un exportedValue no es necesario citarlo porque ya se trata como una cadena literal.

Hay muchas formas en las que tener acceso a las variables Sass en JavaScript puede resultar útil. Tiendo a utilizar este enfoque para compartir puntos de ruptura. Aquí está mi breakpoints.scs archivo, que luego importo en JavaScript para poder usar el matchMedia() método para tener puntos de interrupción consistentes.

// Sass variables that define breakpoint values
$breakpoints: (
  mobile: 375px,
  tablet: 768px,
  // etc.
);

// Sass variables for writing out media queries
$media: (
  mobile: '(max-width: #{map-get($breakpoints, mobile)})',
  tablet: '(max-width: #{map-get($breakpoints, tablet)})',
  // etc.
);

// The export module that makes Sass variables accessible in JavaScript
:export {
  breakpointMobile: unquote(map-get($media, mobile));
  breakpointTablet: unquote(map-get($media, tablet));
  // etc.
}

Las animaciones son otro caso de uso. La duración de una animación generalmente se almacena en CSS, pero las animaciones más complejas deben realizarse con la ayuda de JavaScript.

// animation.scss
$global-animation-duration: 300ms;
$global-animation-easing: ease-in-out;

:export {
  animationDuration: strip-unit($global-animation-duration);
  animationEasing: $global-animation-easing;
}

Tenga en cuenta que utilizo un personalizado strip-unit función al exportar la variable. Esto me permite analizar fácilmente las cosas en el lado de JavaScript.

// main.js
document.getElementById('image').animate([
  { transform: 'scale(1)', opacity: 1, offset: 0 },
  { transform: 'scale(.6)', opacity: .6, offset: 1 }
], {
  duration: Number(variables.animationDuration),
  easing: variables.animationEasing,
});

Me alegra poder intercambiar datos entre CSS, Sass y JavaScript tan fácilmente. Compartir variables como esta hace que el código sea simple y DRY.

Hay varias formas de lograr el mismo tipo de cosas, por supuesto. Les James compartió un enfoque interesante en 2017 que permite que Sass y JavaScript interactúen a través de JSON. Puede que sea parcial, pero encuentro que el enfoque que cubrimos aquí es el más simple e intuitivo. No requiere cambios locos en la forma en que ya usa y escribe CSS y JavaScript.

¿Existen otros enfoques que podría estar utilizando en algún lugar? Compártelos aquí en los comentarios: me encantaría ver cómo lo resuelves.