Dieses Tutorial zeigt Ihnen, wie Sie in Svelte einen Theme-Selektor erstellen, der mehrere Theme-Optionen für Ihre Website ermöglicht. Es enthält auch ein automatisches Design, das sich an die Geräteeinstellungen des Benutzers anpasst.
Obwohl es in Svelte implementiert ist, basieren die meisten Funktionen auf Standard-HTML und CSS, was die Replikation in anderen Frameworks erleichtert.
Der Quellcode für das Projekt finden Sie hier: https://github.com/ivarnm/theme_selector
Live-Demo: https://theme-selector-inm.vercel.app/
Wenn Sie noch kein Svelte-Projekt haben, können Sie eines erstellen, indem Sie dem Leitfaden „Erste Schritte“ von Svelte folgen: https://svelte.dev/docs/introduction
Wir werden CSS-Variablen verwenden, um unsere Farbthemen zu definieren. Erstellen Sie zunächst eine Datei src/styles/global.css und fügen Sie das folgende CSS hinzu:
:root { --neutral-0: white; --neutral-10: #fffcf1; --neutral-30: #d2d2d2; --neutral-40: #b7b7b7; --neutral-60: #666666; --neutral-70: #333333; --neutral-100: black; --primary-60: #696d90; --primary-70: #3D405B; --primary-80: #303349; --secondary-70: #5a7b6b; --secondary-80: #456153; } .dark-theme { --neutral-0: black; --neutral-10: #1a1a1a; --neutral-30: #3d3d3d; --neutral-40: #595959; --neutral-60: #999999; --neutral-70: #cccccc; --neutral-100: white; --primary-60: #979ec7; --primary-70: #a7aed6; --primary-80: #b8bfe9; --secondary-70: #79BEA5; --secondary-80: #89cfb5; } .warm-theme { --neutral-0: #fff7e0; --neutral-10: #ffedcc; --neutral-30: #ffdbb7; --neutral-40: #ffb89d; --neutral-60: #ff9473; --neutral-70: #ff5733; --neutral-100: #4d2600; --primary-60: #f28e2b; --primary-70: #d65a31; --primary-80: #c44536; --secondary-70: #e59572; --secondary-80: #cf6448; } html { font-family: 'Inter', sans-serif; background-color: var(--neutral-10); } body { margin: 0 auto; max-width: 870px; color: var(--neutral-70); }
Dies definiert eine Farbpalette für das helle Thema im Stammelement und fügt ein dunkles und warmes Thema hinzu. Welche Farben und Motive Sie wünschen, liegt natürlich bei Ihnen. Dies sind nur einige Beispiele. Sie sehen auch, wie wir diese Variablen verwenden können, um die Hintergrundfarbe der Seite und die Farbeigenschaft des Körpers festzulegen.
Fügen Sie als Nächstes eine src/routes/layout.svelte-Datei hinzu und fügen Sie den folgenden Code hinzu, um die CSS-Datei global zu importieren:
<script> import "../styles/global.css"; </script>
Ich bevorzuge es, meine Themenauswahl in einem Dropdown-Menü zu haben, daher erstelle ich eine wiederverwendbare DropdownMenu-Komponente, die wir verwenden können. Wenn Sie dasselbe tun möchten, können Sie eine Datei src/lib/components/DropdownMenu.svelte erstellen und Folgendes hinzufügen:
<script lang="ts"> let menuOpen = false; const toggleMenu = () => { menuOpen = !menuOpen; }; const handleDropdownFocusLoss = (event: FocusEvent) => { const focusedElement = event.relatedTarget instanceof HTMLElement ? event.relatedTarget : null; const menuElement = event.currentTarget instanceof HTMLElement ? event.currentTarget : null; // Check if the new focus is inside the menu if (focusedElement && menuElement && menuElement.contains(focusedElement)) { return; } menuOpen = false; }; </script> <div class="container"> <div class="menu" on:focusout={handleDropdownFocusLoss}> <button class="icon-btn" on:click={toggleMenu}> <slot name="icon"></slot> </button> {#if menuOpen} <div class="dropdown"> <slot name="dropdown"></slot> </div> {/if} </div> </div> <style> .menu { position: relative; } .icon-btn { background-color: transparent; border: none; cursor: pointer; padding: 6px; margin: 0; border-radius: 50%; overflow: hidden; width: 49px; height: 49px; display: flex; align-items: center; justify-content: center; } .icon-btn:hover { outline: none; background-color: var(--neutral-30); } .dropdown { position: absolute; top: 60px; right: 0; background-color: var(--neutral-30); border: 1px solid var(--neutral-40); color: var(--neutral-100); padding: 5px; z-index: 100; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column; gap: 10px; width: 200px; } .dropdown :global(button) { padding: 10px 15px; font-size: 20px; display: flex; align-items: center; gap: 10px; width: 100%; } .dropdown :global(button:hover) { background-color: var(--neutral-40); } </style>
Jetzt ist es an der Zeit, die Komponente zu erstellen, die die Themenauswahl übernimmt. Erstellen Sie die Datei
src/lib/components/ThemeSelector.svelte und fügen Sie Folgendes hinzu:
<script lang="ts"> import { onMount } from 'svelte'; import { writable } from 'svelte/store'; import DropdownMenu from '$lib/components/DropdownMenu.svelte'; // If you want to use the theme variable in other components, you can move it to a dedicated ts/js file and import it here instead let theme = writable<string>("system"); // Define your themes and their names. const THEMES = [ { value: 'system', label: 'Automatic' }, { value: 'light', label: 'Light' }, { value: 'dark', label: 'Dark' }, { value: 'warm', label: 'Warm' }, ]; onMount(() => { // Prevents the code from running on the server if (typeof window == 'undefined') return; let storedTheme = localStorage.getItem('theme'); // Get the user's system theme preference let systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; if (storedTheme && THEMES.some(themeOption => themeOption.value === storedTheme)) { theme.set(storedTheme); } else { theme.set('system'); applyTheme(systemTheme); } // Update the automatic theme when the system theme changes if the theme is set to automatic window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { systemTheme = e.matches ? 'dark' : 'light'; if (storedTheme === 'system') { applyTheme(systemTheme); } }); theme.subscribe(value => { if (value === 'system') { applyTheme(systemTheme); } else { applyTheme(value); } localStorage.setItem('theme', value); storedTheme = value; }); }); function applyTheme(theme: string) { document.documentElement.className = ""; if(theme === 'system') return; // Add the theme class (e.g dark-theme) to the document element to apply the theme document.documentElement.classList.add(`${theme}-theme`); } </script> <DropdownMenu> <svg slot="icon" width="37" height="37" viewBox="0 0 37 37" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M29 18.5C29 24.299 24.299 29 18.5 29C12.701 29 8 24.299 8 18.5C8 12.701 12.701 8 18.5 8C24.299 8 29 12.701 29 18.5Z" stroke="currentColor" stroke-width="2"/> <path d="M9 28L6.17157 30.8284" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> <path d="M1 18.5H5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> <path d="M9 9L6.17157 6.17157" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> <path d="M18.5 5L18.5 1" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> <path d="M28 9L30.8284 6.17157" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> <path d="M32 18.5H36" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> <path d="M28 28L30.8284 30.8284" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> <path d="M18.5 36L18.5 32" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> <circle cx="14.5" cy="18.5" r="6.5" stroke="currentColor" stroke-width="2"/> <line x1="8.03459" y1="22.0512" x2="17.227" y2="12.8588" stroke="currentColor" stroke-width="2"/> <line x1="11.0346" y1="25.0512" x2="20.227" y2="15.8588" stroke="currentColor" stroke-width="2"/> </svg> <div slot="dropdown"> {#each THEMES as themeOption} <button class="theme-button" class:selected={$theme === themeOption.value} on:click={() => $theme = themeOption.value} > <svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="12" cy="12" r="7" fill="{$theme === themeOption.value ? 'var(--primary-60)' : 'transparent'}"/> </svg> <span>{themeOption.label}</span> </button> {/each} </div> </DropdownMenu> <style> :global(svg) { color: var(--neutral-70); } .theme-button.selected { font-weight: bold; } button { margin: 0; padding: 0; border: none; border-radius: 4px; background-color: transparent; color: inherit; cursor: pointer; } </style>
Wenn die Komponente im Browser geladen wird, prüfen wir, ob der Benutzer zuvor ein Thema ausgewählt hat. Wenn nicht, wird standardmäßig das automatische Design verwendet. Das automatische Design stellt das Design entweder auf hell oder dunkel ein, indem die Medienabfrage „Preferes-Color-Schema“ verwendet wird, um zu erkennen, ob der Benutzer in seinem Betriebssystem helle oder dunkle Farbthemen angefordert hat.
Beim Festlegen eines Themas, zum Beispiel warm, wird die Klasse warm-theme zum Stammelement der Seite hinzugefügt, wodurch die CSS-Farbvariablen mit denen überschrieben werden, die wir haben zuvor im .warm-theme-Selektor in unserer global.css-Datei definiert.
Jetzt können wir die ThemeSelector-Komponente zu unserer Layoutdatei hinzufügen. Ändern Sie den Inhalt der Datei src/routes/layout.svelte wie folgt:
<script> import '../styles/global.css'; import ThemeSelector from '$lib/components/ThemeSelector.svelte'; </script> <div> <header> <ThemeSelector /> </header> <main> <slot /> </main> </div> <style> header { display: flex; justify-content: flex-end; } main { margin: 50px 0; } </style>
Dadurch wird das Dropdown-Menü zur Themenauswahl oben rechts auf allen Seiten hinzugefügt.
In der Datei src/routes/page.svelte können wir einige Felder hinzufügen, um die Farbthemen anzuzeigen:
<h1>Theme selector</h1> <div class="box-container"> <div class="box neutral-0">--neutral-0</div> <div class="box neutral-10">--neutral-10</div> <div class="box neutral-30">--neutral-30</div> <div class="box neutral-40">--neutral-40</div> <div class="box neutral-60">--neutral-60</div> <div class="box neutral-70">--neutral-70</div> <div class="box neutral-100">--neutral-100</div> <div class="box primary-60">--primary-60</div> <div class="box primary-70">--primary-70</div> <div class="box primary-80">--primary-80</div> <div class="box secondary-70">--secondary-70</div> <div class="box secondary-80">--secondary-80</div> </div> <style> .box-container { display: flex; gap: 30px; flex-wrap: wrap; } .box { width: 150px; height: 150px; display: flex; align-items: center; justify-content: center; } .neutral-0 { background-color: var(--neutral-0); color: var(--neutral-100); } .neutral-10 { background-color: var(--neutral-10); color: var(--neutral-100); border: 5px solid var(--neutral-30); box-sizing: border-box; } .neutral-30 { background-color: var(--neutral-30); color: var(--neutral-100); } .neutral-40 { background-color: var(--neutral-40); color: var(--neutral-100); } .neutral-60 { background-color: var(--neutral-60); color: var(--neutral-0); } .neutral-70 { background-color: var(--neutral-70); color: var(--neutral-0); } .neutral-100 { background-color: var(--neutral-100); color: var(--neutral-0); } .primary-60 { background-color: var(--primary-60); color: var(--neutral-0); } .primary-70 { background-color: var(--primary-70); color: var(--neutral-0); } .primary-80 { background-color: var(--primary-80); color: var(--neutral-0); } .secondary-70 { background-color: var(--secondary-70); color: var(--neutral-0); } .secondary-80 { background-color: var(--secondary-80); color: var(--neutral-0); } </style>
Und hier ist das Endergebnis
Das obige ist der detaillierte Inhalt vonCSS-Themenauswahl mit automatischem Modus [Tutorial]. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!