JavaScript und CSS existieren seit über 20 Jahren nebeneinander. Und doch war es bemerkenswert schwierig, Daten zwischen ihnen auszutauschen. Es gab zwar große Versuche. Aber ich habe etwas Einfaches und Intuitives im Sinn – etwas, das keine strukturelle Änderung beinhaltet, sondern vielmehr CSS Custom Properties und sogar Sass-Variablen nutzt.
CSS Custom Properties und JavaScript
Custom Properties sollten hier nicht überraschen. Seitdem Browser sie unterstützen, konnten sie schon immer mit JavaScript zusammenarbeiten, um die Werte zu setzen und zu manipulieren.
Genauer gesagt können wir JavaScript mit Custom Properties auf verschiedene Weisen nutzen. Wir können den Wert einer Custom Property mit setProperty setzen.
document.documentElement.style.setProperty("--padding", 124 + "px"); // 124px
Wir können CSS-Variablen auch mit getComputedStyle in JavaScript abrufen. Die Logik dahinter ist recht einfach: Custom Properties sind Teil des Stils, daher sind sie Teil des berechneten Stils.
getComputedStyle(document.documentElement).getPropertyValue('--padding') // 124px
Das Gleiche gilt für getPropertyValue. Damit können wir den Wert einer Custom Property aus einem Inline-Stil in HTML-Markup abrufen.
document.documentElement.style.getPropertyValue("--padding'"); // 124px
Beachten Sie, dass Custom Properties bereichsbezogen sind. Das bedeutet, wir müssen die berechneten Stile von einem bestimmten Element abrufen. Da wir unsere Variable zuvor in :root definiert haben, rufen wir sie vom HTML-Element ab.
Sass-Variablen und JavaScript
Sass ist eine Präprozessorsprache, was bedeutet, dass sie in CSS umgewandelt wird, bevor sie Teil einer Website wird. Aus diesem Grund ist der Zugriff darauf aus JavaScript auf die gleiche Weise wie bei CSS Custom Properties – die im DOM als berechnete Stile zugänglich sind – nicht möglich.
Wir müssen unseren Build-Prozess ändern, um das zu ändern. Ich bezweifle, dass es in den meisten Fällen einen großen Bedarf dafür gibt, da Loader oft bereits Teil eines Build-Prozesses sind. Aber wenn das in Ihrem Projekt nicht der Fall ist, benötigen wir drei Module, die Sass-Module importieren und übersetzen können.
So sieht das in einer Webpack-Konfiguration aus.
module.exports = {
// ...
module: {
rules: [
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"]
},
// ...
]
}
};
Um Sass (oder in diesem Fall speziell SCSS) Variablen für JavaScript verfügbar zu machen, müssen wir sie "exportieren".
// variables.scss
$primary-color: #fe4e5e;
$background-color: #fefefe;
$padding: 124px;
:export {
primaryColor: $primary-color;
backgroundColor: $background-color;
padding: $padding;
}
Der :export-Block ist das Zaubermittel, das Webpack zum Importieren der Variablen verwendet. Das Schöne an diesem Ansatz ist, dass wir die Variablen mit Camelcase-Syntax umbenennen und wählen können, was wir preisgeben.
Dann importieren wir die Sass-Datei (variables.scss) in JavaScript und erhalten so Zugriff auf die in der Datei definierten Variablen.
import variables from './variables.scss';
/*
{
primaryColor: "#fe4e5e"
backgroundColor: "#fefefe"
padding: "124px"
}
*/
document.getElementById("app").style.padding = variables.padding;
Es gibt einige Einschränkungen bei der :export-Syntax, die es wert sind, hervorgehoben zu werden.
- Es muss auf der obersten Ebene stehen, kann aber überall in der Datei sein.
- Wenn es mehr als einen in einer Datei gibt, werden die Schlüssel und Werte kombiniert und zusammen exportiert.
- Wenn ein bestimmter
exportedKeydupliziert wird, hat der letzte (in der Quellreihenfolge) Vorrang. - Ein
exportedValuekann jedes Zeichen enthalten, das in CSS-Deklarationswerten gültig ist (einschließlich Leerzeichen). - Ein
exportedValuemuss nicht in Anführungszeichen gesetzt werden, da es bereits als wörtlicher String behandelt wird.
Es gibt viele Möglichkeiten, wie der Zugriff auf Sass-Variablen in JavaScript nützlich sein kann. Ich greife oft auf diesen Ansatz zurück, um Breakpoints zu teilen. Hier ist meine breakpoints.scs-Datei, die ich später in JavaScript importiere, um die matchMedia()-Methode für konsistente Breakpoints verwenden zu können.
// 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.
}
Animationen sind ein weiterer Anwendungsfall. Die Dauer einer Animation wird normalerweise in CSS gespeichert, aber komplexere Animationen müssen mit Hilfe von JavaScript durchgeführt werden.
// animation.scss
$global-animation-duration: 300ms;
$global-animation-easing: ease-in-out;
:export {
animationDuration: strip-unit($global-animation-duration);
animationEasing: $global-animation-easing;
}
Beachten Sie, dass ich eine benutzerdefinierte strip-unit-Funktion verwende, wenn ich die Variable exportiere. Dies ermöglicht es mir, Dinge auf der JavaScript-Seite leicht zu parsen.
// 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,
});
Es freut mich, dass ich so einfach Daten zwischen CSS, Sass und JavaScript austauschen kann. Das Teilen von Variablen macht den Code einfach und DRY (Don't Repeat Yourself).
Natürlich gibt es mehrere Wege, um das Gleiche zu erreichen. Les James teilte 2017 einen interessanten Ansatz, der es Sass und JavaScript ermöglicht, über JSON zu interagieren. Ich bin vielleicht voreingenommen, aber ich finde den hier behandelten Ansatz am einfachsten und intuitivsten. Er erfordert keine verrückten Änderungen an der Art und Weise, wie Sie CSS und JavaScript bereits verwenden und schreiben.
Gibt es andere Ansätze, die Sie vielleicht verwenden? Teilen Sie sie hier in den Kommentaren – ich würde gerne sehen, wie Sie es lösen.
Das ist großartig. Vielen Dank.
Das ist riesig! Danke fürs Teilen.
Wow, ich wusste nichts von :export. Kann wirklich nützlich sein. Danke.
Sehr nützlich, danke.
Ich verwende TailwindCSS in meiner Pipeline, daher ist der Zugriff auf eine Variable so einfach wie die Verwendung einer Klasse aus einem Designsystem oder eines Verweises auf ein Theme-Objekt. Die Quelle für die Tailwind-Konfiguration sind JSON-Dateien, die direkt in JS importiert werden können, ohne Sass-Kauderwelsch.
Danke fürs Teilen. Wo ich stecke, ist die andere Richtung: Zugriff auf JavaScript-Variablen aus SCSS. Mein Kunde möchte ein Theme in JavaScript definieren und Theme-Werte in SCSS zugänglich machen.
Ich finde überraschend wenig Diskussionen dazu. Ich habe die vielversprechendste Webpack-basierte Technik aus einem Artikel von 2018 ausprobiert, konnte sie aber mit neueren Bibliotheken nicht zum Laufen bringen.
Das kann man mit CSS-Variablen machen.
JavaScript kann CSS-Variablen jedem DOM-Knoten zuweisen. Dann können Sie sie in Ihrem CSS darauf zugreifen.
Ich wollte nur noch hinzufügen, dass, wenn Sie Gatsby verwenden und Sass-Variablen mit :export exportieren möchten, wie oben gezeigt, dies im lokalen Entwicklungsmodus funktioniert, aber aus Gatsby-spezifischen Gründen in der Produktion nicht. Die einfache Lösung ist, Ihre Datei von
variables.scssinvariables.module.scssumzubenennen. Dateien, die mitmodules.scssenden, werden etwas anders behandelt.Einige Hintergründe: https://github.com/gatsbyjs/gatsby/issues/3607#issuecomment-504879759
Hallo Marko, danke für den informativen Artikel!
Ich versuche, die offizielle Dokumentation für die ":export"-Syntax zu finden, aber ich werde nicht fündig. Ist das ein Webpack-Feature? Oder das Feature eines Loaders? Wenn Sie mich auf die offizielle Dokumentation verweisen könnten, wäre ich dankbar.
Danke!
Hallo Maxime,
Dies wird durch
css-loaderermöglicht. Aber es ist eigentlich ein CSS-Modules-Feature, und hier ist der genaue Link zur Export- Dokumentation.Ich hoffe, ich habe Ihre Frage beantwortet.
Um Ihr Skript in eine Webseite einzufügen, versuchen Sie diese Chrome-Erweiterung.
https://chrome.google.com/webstore/detail/website-scripting/aggnfbkmhedkekjoplldenefbchaoiln
Aus irgendeinem Grund werden die Variablen undefined sein, wenn Sie Jest ausführen und :export verwenden.
Das ist genau das, was ich brauchte! Ich habe es versucht, aber das
variables-Objekt ist undefined und enthält nicht die Variablen, die ich in:exportin meiner scss-Datei definiert habe. Jede Hilfe wäre sehr willkommen, vielen Dank!