Hinzufügen von Stylesheets (CSS) und JavaScript (JS) zum Drupal 8 Theme
Diese Dokumentation richtet sich an Themes. Informationen zu Modulen finden Sie im Abschnitt „Hinzufügen von Stylesheets (CSS) und JavaScript (JS) zu einem Drupal 8 Modul“.
In Drupal 8 werden Stylesheets (CSS) und JavaScript (JS) über dasselbe System für Module (Code) und Themes geladen: die Asset-Bibliotheken.
Zur Klarstellung sind diese Anweisungen nur für Themes gedacht und gelten nicht für Module.
Drupal folgt dem hohen Prinzip: Ressourcen (CSS oder JS) werden nur geladen, wenn Sie Drupal mitteilen, dass sie geladen werden sollen. Drupal lädt nicht alle Ressourcen auf jeder Seite, da dies die Performance beeinträchtigt.
Unterschiede zu Drupal 7
Es gibt sechs wichtige Unterschiede im Vergleich zu Drupal 7 für Enthusiasten:
- Die Datei THEME.info.yml ersetzt die Datei THEME.info (mit denselben Daten).
- Die Eigenschaft stylesheets (für CSS) in THEME.info wurde entfernt und durch *.libraries.yml ersetzt, wobei * der Name des Themes oder Moduls ist.
- Die Eigenschaft scripts (für JS) in THEME.info wurde entfernt und ebenfalls durch *.libraries.yml ersetzt.
- Nur das CSS und JS, das auf der Seite benötigt wird, wird geladen. Beispielsweise wird jQuery nicht mehr automatisch geladen, außer es wird explizit in *.libraries.yml angegeben. Wenn Ihr Theme jQuery oder andere Ressourcen auf allen Seiten benötigt, fügen Sie diese in *.libraries.yml hinzu und binden Sie die Bibliothek in THEME.info.yml ein.
- In Drupal 7 mussten Bibliotheken mit hook_library_info() definiert werden. Das wurde durch die Datei *.libraries.yml ersetzt.
- In Drupal 8 wurden drupal_add_css(), drupal_add_js() und drupal_add_library() zugunsten von #attached entfernt.
Vorgehensweise
So laden Sie CSS- oder JS-Ressourcen:
- Speichern Sie CSS- oder JS-Dateien unter Beachtung der Namen- und Dateistruktur-Konventionen.
- Definieren Sie eine „Bibliothek“, die diese CSS- und JS-Dateien in Ihrem Theme registriert.
- Binden Sie die Bibliothek auf allen Seiten, in bestimmten Twig-Templates oder gezielt auf bestimmten Seiten über Preprocess-Funktionen ein.
Bibliothek definieren
Definieren Sie alle Ihre Asset-Bibliotheken in der Datei *.libraries.yml im Verzeichnis Ihres Themes. Wenn Ihr Theme „fluffiness“ heißt, muss die Datei fluffiness.libraries.yml heißen. Jede „Bibliothek“ ist ein Eintrag, der CSS- und JS-Dateien (Assets) detailliert, zum Beispiel:
# fluffiness.libraries.yml cuddly-slider: version: 1.x css: theme: css/cuddly-slider.css: {} js: js/cuddly-slider.js: {}
In diesem Beispiel befinden sich die JavaScript-Datei cuddly-slider.js und die CSS-Datei cuddly-slider.css in den Verzeichnissen js und css Ihres Themes.
Beachten Sie, dass dieses Beispiel nur eine CSS- und eine JS-Datei sowie jQuery zeigt. Es gibt jedoch viel mehr Optionen zur Definition von Bibliotheken, die Sie im Abschnitt „Bibliotheken definieren: Optionen und Details“ finden.
jQuery in Ihre Bibliothek einbinden
Drupal 8 lädt jQuery nicht mehr automatisch auf allen Seiten. Wenn beispielsweise cuddly-slider jQuery benötigt, müssen Sie die Abhängigkeit zur Basiskomponente, die jQuery enthält (bereitgestellt vom Drupal-Core, nicht vom Modul oder Theme), deklarieren. Die Abhängigkeit wird als core/jquery
angegeben. Wenn eine andere Bibliothek cuddly-slider benötigt, deklariert sie fluffiness/cuddly-slider
als Abhängigkeit. Sie können nicht einzelne Dateien als Abhängigkeit deklarieren, sondern nur ganze Bibliotheken.
Um jQuery für cuddly-slider verfügbar zu machen, erweitern wir das obige Beispiel:
# fluffiness.libraries.yml cuddly-slider: version: 1.x css: theme: css/cuddly-slider.css: {} js: js/cuddly-slider.js: {} dependencies: - core/jquery
Abhängigkeiten deklarieren
Um eine Abhängigkeit zu deklarieren, geben Sie die benötigte Bibliothek in der Form resource/library an. Für Core-Bibliotheken ist „resource“ „core“, für andere der Name des Moduls oder Themes. Wenn z. B. new_library von jQuery aus dem Core sowie von my_library aus dem Theme my_theme und my_library aus dem Modul my_module abhängt, deklarieren Sie die Abhängigkeiten so:
# fluffiness.libraries.yml new_library: js: js/new_library.js: {} dependencies: - core/jquery - my_module/my_library - my_theme/my_library
Modul- und Themennamen sorgen für Namensräume, sodass Bibliotheken mit gleichem Namen unterschieden werden können.
Bibliothek auf allen Seiten einbinden
In den meisten Themes wird die Asset-Bibliothek global-styling für CSS-Dateien verwendet, die auf jeder Seite, auf der das Theme aktiv ist, geladen werden sollen. Ebenso kann man JS über die Bibliothek global-scripts laden:
# fluffiness.libraries.yml global-styling: version: 1.x css: theme: css/layout.css: {} css/style.css: {} css/colors.css: {} global-scripts: version: 1.x js: js/navmenu.js: {}
Um diese Bibliotheken überall im Theme verfügbar zu machen, müssen global-styling und global-scripts in der info.yml Ihres Themes (z. B. fluffiness.info.yml) eingebunden werden:
# fluffiness.info.yml name: Fluffiness type: theme description: 'Ein kuscheliges Theme, das extra Flauschigkeit bietet.' core: 8.x libraries: - fluffiness/global-styling - fluffiness/global-scripts base theme: classy regions: header: Header content: Inhalt sidebar_first: 'Sidebar first' footer: Footer
Bibliothek im Twig-Template einbinden
Sie können eine Asset-Bibliothek im Twig-Template mit der Funktion attach_library()
einbinden, zum Beispiel in jeder *.html.twig-Datei so:
{{ attach_library('fluffiness/cuddly-slider') }}Ein wenig flauschige Markup {{ message }}
Bibliothek nur auf bestimmten Seiten einbinden
Manchmal wollen Sie, dass Ihre Bibliothek nur auf bestimmten Seiten aktiv ist, z. B. nur bei der Anzeige eines bestimmten Blocks oder eines bestimmten Knotentyps.
Das Theme kann dies über eine Funktion THEME_preprocess_HOOK()
in der .theme-Datei umsetzen, wobei THEME
durch den Maschinen-Namen Ihres Themes und HOOK
durch den thematischen Hook-Namen ersetzt wird.
Beispiel: Wenn Sie JavaScript auf der Wartungsseite einbinden wollen, ist der Hook „maintenance_page“, und Ihre Funktion sieht so aus:
function fluffiness_preprocess_maintenance_page(&$variables) { $variables['#attached']['library'][] = 'fluffiness/cuddly-slider'; }
Sie können ähnliche Funktionen für andere Theme-Hooks schreiben und natürlich Logik hinzufügen, z. B. prüfen, welcher Block im Block-Hook vorverarbeitet wird oder welcher Knotentyp im Node-Hook usw.
Wichtiger Hinweis! In solchen Fällen müssen Sie passende Cache-Metadaten angeben! Das obige Beispiel ist ohne Bedingungen, daher braucht es keine Cache-Metadaten. Ein häufiges Szenario ist, eine Bibliothek abhängig von der aktuellen Route einzubinden:
function fluffiness_preprocess_page(&$variables) { $variables['page']['#cache']['contexts'][] = 'route'; $route = "entity.node.preview"; if (\Drupal::routeMatch()->getRouteName() === $route) { $variables['#attached']['library'][] = 'fluffiness/node-preview'; } }
Bibliotheken definieren: Optionen und Details
Eigenschaften zu eingebundenem CSS/JS hinzufügen
Eigenschaften werden in geschweifte Klammern nach jeder Datei in THEMENAME.libraries.yml geschrieben.
CSS-Eigenschaften
attributes | Optionale Attribute. Bekannter Anwendungsfall: Bootstrap CDN. |
{ attributes: { crossorigin: anonymous } } |
browsers | Ressource bedingt nach Browser laden. Nutzt Conditional Comments, die ab IE10 nicht mehr unterstützt werden. |
{ browsers: { IE: 'lte IE 9', '!IE': false } } |
group | Assets werden in Gruppen zusammengefasst. Standard: SMACSS-Gruppe, zu der das Asset gehört. |
Wird selten verwendet |
media | Medientyp. |
{ media: print } |
minified | Ist das Asset bereits minifiziert. Standard: false |
{ type: external, minified: true } |
preprocess | Sollen Assets aggregiert werden. Standard: true |
{ preprocess: false } |
type | Quelle des Assets. Standard: Datei |
{ type: external, minified: true } |
weight | Ordnet die Reihenfolge relativ zu anderen Assets in derselben SMACSS-Gruppe. Standard: 0. Werte von -50 bis +50. |
{ weight: 1 } |
JS-Eigenschaften
attributes | Zusätzliche Skript-Attribute. |
{ type: external, attributes: { async: true } } |
browsers | Ressource bedingt nach Browser laden. Nutzt Conditional Comments, die ab IE10 nicht mehr unterstützt werden. |
{ browsers: { IE: 'lte IE 9', '!IE': false } } |
preprocess | Sollen Assets aggregiert werden. Standard: true |
{ preprocess: false } |
type | Quelle des Assets. Standard: Datei |
{ type: external, minified: true } |
weight | Besser Abhängigkeiten verwenden. Regelt die Reihenfolge relativ zu anderen Assets. Sollte negativ sein. |
{ weight: -1 } |
Bibliotheken überschreiben und erweitern
Um Bibliotheken, die in *.libraries.yml definiert sind, zu überschreiben, bearbeiten Sie die *.info.yml Datei. Sie können Bibliotheken überschreiben oder erweitern. Überschreibungen, die Sie in *.info.yml hinzufügen, werden von Unterthemes geerbt.
Die Eigenschaft stylesheets-remove, die in *.info.yml verwendet wird, ist veraltet und wird in Drupal 9.0.x entfernt. Die Eigenschaft stylesheets-override wurde bereits entfernt.
libraries-override
Logik für das Erstellen von Überschreibungen:
- Verwenden Sie den Original-Namespace des Moduls (oder Core) für den Bibliotheksnamen.
- Verwenden Sie den Pfad des letzten Überschreibungsdatei als Schlüssel.
- Dieser Pfad muss der vollständige Dateipfad sein.
Beispiel:
libraries-override: contextual/drupal.contextual-links: css: component: /core/themes/stable/css/contextual/contextual.module.css: false
Hier ist contextual/drupal.contextual-links der Namespace der Originalbibliothek und /core/themes/stable/css/contextual/contextual.module.css ist der vollständige Pfad der Datei, die überschrieben oder deaktiviert wird (false).
Beachten Sie, dass nur der letzte Teil der Pfad zum Dateisystem ist, der Rest sind Namespace-Ebenen. Die Schlüssel css: und component: spiegeln die Struktur der Bibliothek wider.
Beachten Sie, dass Abhängigkeiten, die vom Dateisystempfad abhängen, bei Änderungen der Dateistruktur brechen können. Deshalb gibt es die Problematik, Abhängigkeiten vom kompletten Pfad durch Bundler zu entfernen siehe hier.
Weitere Beispiele zum Entfernen oder Ersetzen von CSS/JS oder ganzen Bibliotheken, die Ihr Theme von Modulen oder anderen Themes erbt:
libraries-override: # Ganze Bibliothek ersetzen. core/drupal.collapse: mytheme/collapse # Einzelnes Asset ersetzen. subtheme/library: css: theme: css/layout.css: css/my-layout.css # Override Asset aus stable ersetzen. contextual/drupal.contextual-toolbar: css: component: core/themes/stable/css/contextual/contextual.toolbar.css: css/contextual.toolbar.css # JS Asset eines Core-Moduls ersetzen. toolbar/toolbar: js: js/views/BodyVisualView.js: js/views/BodyVisualView.js # Asset entfernen. drupal/dialog: css: theme: dialog.theme.css: false # Ganze Bibliothek entfernen. core/modernizr: false # Sehr spezifische Assets einer Bibliothek eines Contrib-Moduls ersetzen. # Hinweis: Die Bibliotheken des Moduls, die überschrieben werden können, finden Sie in der *.libraries.yml Datei des Moduls, z. B. /modules/contrib/webform/webform.libraries.yml webform/webform.element.location.places: css: component: css/webform.element.location.places.css: css/my-themes-replacement-file.css js: js/webform.element.location.places.js: js/my-themes-replacement-file.js
libraries-extend
libraries-extend erlaubt es Themes, Bibliotheken zu verändern, indem zusätzliche abhängige Ressourcen hinzugefügt werden, wenn die Bibliothek geladen wird. Es definiert Erweiterungen durch eine oder mehrere andere Bibliotheken.
Dies ist ideal, um bestimmte Komponenten im Theme unterschiedlich zu stylen, ohne globales CSS zu laden. So können Sie das Aussehen eines Components anpassen, ohne CSS auf jeder Seite zu laden.
# Erweitere drupal.user: füge Assets von Classys User-Bibliotheken hinzu. libraries-extend: core/drupal.user: - classy/user1 - classy/user2
Weitere Javascript-Einstellungen
Lade-Reihenfolge der Assets
Wie erwartet entspricht die Reihenfolge der Dateien der Reihenfolge ihres Ladens. Standardmäßig werden alle JS-Ressourcen im Footer geladen. JS für kritische UI-Elemente, die nicht angezeigt werden können, ohne dass ihr JS ausgeführt wird, kann bei Bedarf im Header geladen werden, z. B. so:
js-header: header: true js: header.js: {} js-footer: js: footer.js: {}
Das Property header: true
kennzeichnet die JS-Ressourcen dieser Bibliothek als Teil des „kritischen Pfades“ und zwingt sie, im Header geladen zu werden. Direkt oder indirekt deklarierte Abhängigkeiten werden automatisch ebenfalls im Header geladen. So sorgt man dafür, dass diese Ressourcen und ihre Abhängigkeiten zuerst geladen werden.
Custom JavaScript anhängen
Manchmal wollen Sie JavaScript auf der Seite einfügen, das von PHP-Werten abhängt.
Erstellen Sie in dem Fall eine JS-Datei, definieren und binden Sie eine Bibliothek wie gehabt ein, fügen Sie aber auch JS-Einstellungen hinzu, die Ihre JS-Datei mit drupalSettings
auslesen kann (Nachfolger von Drupal 7s Drupal.settings). Um drupalSettings verfügbar zu machen, müssen Sie die Abhängigkeit darauf ebenfalls deklarieren.
Das sieht dann so aus:
cuddly-slider: version: 1.x js: js/cuddly-slider.js: {} dependencies: - core/jquery - core/drupalSettings
Und im Preprocess-Hook:
function fluffiness_page_attachments_alter(&$page) { $page['#attached']['library'][] = 'fluffiness/cuddly-slider'; $page['#attached']['drupalSettings']['fluffiness']['cuddlySlider']['foo'] = 'bar'; }
Dabei ist 'bar' ein berechneter Wert. (Cache-Metadaten sind hier ebenfalls erforderlich!)
Dann kann cuddly-slider.js auf settings.fluffiness.cuddlySlider.foo
zugreifen, was 'bar' sein wird:
(function ($, Drupal, drupalSettings) { 'use strict'; Drupal.behaviors.mybehavior = { attach: function (context, settings) { console.log(settings.fluffiness.cuddlySlider.foo); } }; })(jQuery, Drupal, drupalSettings);
Attribute zu Script-Tags hinzufügen
Um Attribute zu einem Script-Tag hinzuzufügen, fügen Sie im JSON nach der Script-URL den Schlüssel attributes hinzu. Innerhalb des attributes-Objekts geben Sie als Schlüssel den Attributnamen an, als Wert den Attributwert. Ist der Wert true, wird das Attribut ohne Wert ausgegeben.
Beispiel:
https://maps.googleapis.com/maps/api/js?key=myownapikey&signed_in=true&libraries=drawing&callback=initMap: type: external attributes: defer: true async: true data-test: map-link
Dies erzeugt folgendes Markup:
Inline JavaScript
Inline JavaScript wird stark nicht empfohlen. Es ist besser, das JavaScript in Dateien auszulagern, damit es clientseitig gecached werden kann und der Code leichter sichtbar und editierbar ist.
Inline JavaScript, das Markup generiert
Das wird generell nicht empfohlen und ist meist nicht nötig. Typische Beispiele sind Werbung, Social-Sharing-Buttons, Social-Widget-Listen. Diese verwenden Inline-JavaScript, da sie externen Content einbinden und nicht das Layout oder die Interaktivität der Seite direkt steuern.
Solche Scripte können in benutzerdefinierte Blöcke oder direkt in Twig-Templates eingefügt werden.
Beispiel:
Tweets by @wimleers
Inline JavaScript, das die ganze Seite beeinflusst
Der Einsatz von Inline-JavaScript wird stark nicht empfohlen. Beispiele sind Analytics (z. B. Google Analytics) und Web-Font-Services. Solches Inline-JavaScript kann zwei Kategorien angehören: Frontend/Styling oder Logik.
Im Fall von Frontend/Styling (z. B. Webfonts) gehört das JS zum Theme. Platzieren Sie das JS direkt in der Datei html.html.twig. So können Sie das Laden optimieren und z. B. FOUT (Flash Of Unstyled Text) verhindern, indem Fonts im HTML-<head>
vor CSS geladen werden. (Siehe Artikel „Async Typekit & Micro-FOUT“.)
In anderen Fällen gehört das JavaScript zum Modul. Siehe dazu „Hinzufügen von Stylesheets (CSS) und JavaScript (JS) zu einem Drupal 8 Modul“.
Inline JavaScript in Integration-Modulen
Inline-JavaScript sollte vermieden werden. Prüfen Sie die obigen Beispiele, bevor Sie Inline-JS verwenden.
Zwei wichtige Punkte bei Feldern, die vom Nutzer eingebettetes Inline-JS akzeptieren:
1. Das Feld, Formular oder Seite, das dieses Inline-JS annimmt, muss die richtige Berechtigung haben.
Beispiel: MODULE.routing.yml
MODULE.settings: path: /admin/config/services/MODULE defaults: _title: 'MODULE Einstellungen' _form: \Drupal\MODULE\Form\MODULESettings requirements: _permission: 'administer site configuration'
2. Der Wert, falls er in einer Konfigurations-Objekt gespeichert ist, muss dem Render-System die CacheableMetadata mitteilen, damit bei Änderungen der Cache geleert wird.
Beispiel: MODULES.module
Markup::create($settings->get('js_code')), '#cache' => [ 'contexts' => ['user'], 'tags' => ['user:' . $user->id()], ], ]; // Cache-Metadaten für Konfiguration hinzufügen. /** @var Drupal\Core\Render\Renderer $renderer */ $renderer = \Drupal::service('renderer'); $renderer->addCacheableDependency($page_bottom['MODULE'], $settings); }
CDN / externe Bibliotheken
Sie möchten eventuell JavaScript von einem CDN (Content Delivery Network) laden, z. B. Webfonts, die meist nur über externe URLs verfügbar sind. Dies kann durch Deklaration einer externen Bibliothek (mit type: external
) erreicht werden. Es ist hilfreich, weitere Informationen zur externen Bibliothek anzugeben.
(Hinweis: Es ist im Allgemeinen keine gute Idee, Bibliotheken über CDN zu laden, da dies zusätzliche Fehlerquellen und Performance- sowie Sicherheitsprobleme verursachen kann. Außerdem erhöht es die Anzahl der TCP/IP-Verbindungen und verhindert Browser-Caching. Drittanbieter-Bibliotheken sollten nicht als Teil Ihres Repos auf Drupal.org liegen – siehe Richtlinien für Drittanbieter-Bibliotheken auf Drupal.org.)
angular.angularjs: remote: https://github.com/angular version: 1.4.4 license: name: MIT url: https://github.com/angular/angular.js/blob/master/LICENSE gpl-compatible: true js: https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js: { type: external, minified: true }
Wenn Sie möchten, dass die externe Datei mit demselben Protokoll wie die Webseite geladen wird, verwenden Sie eine protokoll-relative URL:
js: //ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js: { type: external, minified: true }
Oder für CSS, z. B. Font Awesome:
font-awesome: remote: https://fortawesome.github.io/Font-Awesome/ version: 4.5.0 license: name: MIT url: https://fortawesome.github.io/Font-Awesome/license/ gpl-compatible: true css: theme: https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css: { type: external, minified: true }
Beispiel für Bootstrap CDN CSS mit benutzerdefinierten Attributen
bootstrap-cdn: remote: getbootstrap.com version: 4.0 license: name: MIT url: https://github.com/twbs/bootstrap/blob/master/LICENSE css: theme: 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css': type: external minified: true attributes: crossorigin: anonymous integrity: "sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
Weitere Informationen
?>Drupal’s online documentation is © 2000-2020 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.