Themenwechsel mit Blazor oder Dark/Light Theme

Wieder einmal ist es eine Frage eines Blazor Kurs Teilnehmers, die mich ins stutzen bringt. Wie schaltet man in einer Website das Theme um?

Zerlegen wir das Problem. Design findet sich in CSS Styles, was jeder vernünftige Web Entwickler per CSS Datei bündelt. Vorne weg die reinen Bootstrap Klassen und hinten raus die customization. In Blazor 8 wird das in der App.razor erledigt.

   1:  <head>
   2:      <meta charset="utf-8" />
   3:      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   4:      <base href="/" />
   5:      <link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
   6:      <link rel="stylesheet" href="BlazozTheme.styles.css" />
   7:      <link rel="stylesheet" href="app.css" />
   8:      <link rel="icon" type="image/png" href="favicon.png" />
   9:      <HeadOutlet @rendermode="InteractiveAuto" />

Wir legen also nun verschiedene Varianten der app.css an. Der Einfachheit halber nur mit unterschiedlichen Background Farben.

Tatsächlich reicht es die Url in href zu ändern um den Browser, egal ob WASM oder Server, dazu zu verleiten, die Datei zu laden und die Styles sofort zu nutzen. Rein zum Test einfach im DOM der F12 Browser Tools probiert und funktioniert. Ist also technisch kein spezielles Problem von Blazor.

Ich sehe nun zwei Ansätze. Per Headcontent Component die ganze Link Zeile einfügen/austauschen der Url mit Binding und als zweite Variante JavaScript und JSInterop.

HeadContent

Um das CSS Layout für die ganze Site zu ändern, wird sich die Datei Mainlayout.Razor anbieten. HeadContent und der Platzhalter HeadOutlet sind sozusagen das Pärchen.

   1:  <PageTitle>Home</PageTitle>
   2:  <HeadContent  >
   3:      <link rel="stylesheet" href="@css" />
   4:  </HeadContent>

Für SPA und Blazor typisch wird die URL einfach per Binding Variable zugewiesen. Irgendein Button Click oder DropDown Event reicht.

JavaScript Variante

Hier lege ich mir eine statische JavaScript Datei in wwwroot an und verlinke die in App.razor oder gehe den Umweg über JS Module. Das Ergebnis ist das selbe.

   1:  window.themeChange = function (cssUrl) {
   2:      let linkElement = document.
querySelector('head link[rel="stylesheet"]:last-of-type');
   3:      if (cssUrl === linkElement.getAttribute("href")) {
   4:              return;
   5:          }
   6:      linkElement.setAttribute("href", cssUrl);
   7:      console.log(linkElement);

Zeile 7 dient nur der Befriedigung meines Misstrauens. Tut das Ding auch was?

Alles weitere ist ein Spaziergang. IJSruntime injizieren per @inject und eine Zeile Code in der c# Auswahl Logik

 JSRuntime.InvokeVoidAsync("themeChange", "app4.css");

 

Was nehm ich nun?

Wir betrachten hier die Server Side Blazor Variante.

Die Lösung mit JavaScript benötigt nun mal JavaScript Code der hier marginal Overhead erzeugt. Man könnte das in eine Component kapseln. Am Ende ein paar Bytes mehr, die über die Leitung gehen.
Viel spannender ist was auf der Signalr, respektive dem Websocket Protokoll passiert. Grün ist die JavaScript Variante und Orange zeigt die Nachrichten der HeadContent Vairante.

Theming

200 Bytes vs 700. Hier liegt der Vorteil bei der JavaScript Variante.

Kommentare sind geschlossen