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>
  • Вопрос задан
  • 329 просмотров
Решения вопроса 1
mizutsune
@mizutsune
Frontend Developer
Смену иконки можно реализовать без дополнительного 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;
}


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

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

Войти через центр авторизации
Похожие вопросы