Задать вопрос
AleksMey
@AleksMey
Пытаюсь разобраться

Как в скрипт смены темы добавить смену svg иконки кнопки с солнца на луну?

Помогите добавить смену svg иконки при нажатии на кнопку темы с запоминанием. Сколько не пробовал ничего не выходит. Добавлял отдельную функцию для смены, но функция работает без запоминания какая тема сейчас установлена.

function setDarkTheme()
{
    document.documentElement.classList.remove("light");
    document.documentElement.classList.add("dark");
    localStorage.setItem("theme", "dark");
}

function setLightTheme()
{
    document.documentElement.classList.remove("dark");
    document.documentElement.classList.add("light");
    localStorage.setItem("theme", "light");
}

function setPreferredTheme()
{
    if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
      setDarkTheme();
    } else {
      setLightTheme();
    }
}

function isDarkTheme()
{
  return localStorage.getItem("theme") == "dark";
}

function setChoosenTheme()
{
    let theme = localStorage.getItem("theme");
  
    if (theme == "dark")
    {
        setDarkTheme();
    } else if (theme == "light")
    {
        setLightTheme();
    }
    else
    {
        setPreferredTheme();
    }
}

function toggleDarkMode() {
  if (isDarkTheme()) {
    setLightTheme();
  } else {
    setDarkTheme();
  }
}

window.matchMedia('(prefers-color-scheme: dark)').onchange = (e) => setChoosenTheme();

setChoosenTheme();


<button onClick="toggleDarkMode()" class="btn btn-primary">Сменить тему</button>
  • Вопрос задан
  • 446 просмотров
Подписаться 1 Средний 5 комментариев
Решения вопроса 1
mizutsune
@mizutsune
I will live forever in the flame of your eyes.
Смену иконки можно реализовать без дополнительного JS. Ниже добавил два варианта решения задачи.

Первый пример:

Берем две иконки SVG. Допустим это Луна и Солнце. Далее нужно будет закодировать SVG для использования в CSS и сделать это можно, например, с помощью этого инструмента.

Далее обработанные SVG применим для иконки. Сама иконка будет представлять из себя псевдоэлемент, хотя можно использовать и HTML тег, например span, но всё же не стоит добавлять лишние сущности в разметку, если в этом нет нужды.

Добавляем в кнопку псевдоэлемент для иконки:

.btn::after {
     content: "";
     position: relative;
     display: inline-flex;
     width: 20px;
     height: 20px;
     background-size: contain;
     background-repeat: no-repeat;
}


Далее на основе выбранной темы, будем менять бекграунд иконки. Так как через JS происходит добавление класса к корневому элементу с названием текущей темы - можно воспользоваться этим и через CSS без лишних проблем менять оформление иконке.

Светлая тема:

.light .btn::after{
background-image: url("data:image/svg+xml...//иконка-солнца");
}


Темная тема:

.dark .btn::after {
background-image: url("data:image/svg+xml...//иконка-луны");
}


Хотя этот вариант и кажется простым и доступным, всё же он хранит в себе некоторые недостатки.

1. Нельзя просто взять и изменить цвет иконки при наведении.
2. При желании изменить дефолтный цвет иконки, придётся взять оригинальный SVG - вектор, перекрасить его и заново закодировать, после чего обновить значение в CSS файле.
3. Если иконки большие по обьему, они будут увеличивать размер CSS файла, но тут есть решение этой проблемы. Перед конвертацией SVG в CSS, прогоняем вектор через SVGO. Правда и это порой не сильно помогает.

Второй вариант:

Добавить обе иконки в кнопку, в качестве SVG, задать иконкам разные классы и по дефолту скрыть обе иконки, например:

<svg class="icon__light">
// содержимое SVG
</svg>


<svg class="icon__dark">
// содержимое SVG
</svg>


И через CSS менять видимость иконок.

Пример:

.icon__light,
.icon__dark {
     display: none;
}

.light .icon__light {
     display: block;
}

.dark .icon__dark {
     display: block;
}


У этого подхода тоже имеются свои подводные камни, впрочем, как и у любого способа решить ту или иную задачу, но минусами этого подхода намного проще бороться.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы