Heim > Web-Frontend > CSS-Tutorial > CSS-Themenauswahl mit automatischem Modus [Tutorial]

CSS-Themenauswahl mit automatischem Modus [Tutorial]

Linda Hamilton
Freigeben: 2024-10-08 22:08:30
Original
904 Leute haben es durchsucht

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/

Einrichten des Projekts:

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

Farbvariablen hinzufügen:

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);
}
Nach dem Login kopieren

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>
Nach dem Login kopieren

Erstellen Sie ein Dropdown-Menü:

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>
Nach dem Login kopieren

Erstellen Sie die Themenauswahlkomponente:

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>
Nach dem Login kopieren

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.

Hinzufügen der Themenauswahl:

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>
Nach dem Login kopieren

Dadurch wird das Dropdown-Menü zur Themenauswahl oben rechts auf allen Seiten hinzugefügt.

Fügen Sie einige Beispielinhalte hinzu, um die Themen anzuzeigen:

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>

Nach dem Login kopieren

Und hier ist das Endergebnis

CSS Theme Selector with Automatic Mode [Tutorial]

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!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage