How to Build Advanced Light and Dark Theme Toggles

Through this example, we mainly master the following knowledge points

  • Flexible use of CSS variables
  • Use JS to get CSS variables
  • Flexible use of CSS transformand transitionproperties

renderings

insert image description here
insert image description here

Implement page layout

From the effect diagram, we can first realize the general layout of the page. The specific code is as follows:

<h2 class="main-title">主题切换</h2>
<button class="theme-switch-btn">
  <svg class="icon" viewBox="0 0 1024 1024" width="24" height="24">
    <path></path>
  </svg>
  切换主题
</button>
<div class="sun-moon-container">
  <!-- 太阳 -->
  <svg class="sun" viewBox="0 0 1024 1024" width="24" height="24">
    <path></path>
  </svg>

  <!-- 月亮 -->
  <svg class="moon" viewBox="0 0 1024 1024" width="24" height="24">
    <path></path>
  </svg>
</div>
body {
    
    
  --accent-color: orangered;
  --background-color: white;
  --text-color: black;
  --button-text-color: var(--background-color);
  --transition-delay: 1s;

  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: 100vh;
  margin: 0;

  background-color: var(--background-color);
  color: var(--text-color);
}
body.dark {
    
    
  --accent-color: #d0d066;
  --background-color: #333;
  --text-color: white;
}

.main-title {
    
    
  margin: 0;
  margin-bottom: 25px;
}

.theme-switch-btn {
    
    
  background-color: var(--accent-color);
  color: var(--button-text-color);

  display: flex;
  flex-flow: row wrap;
  justify-content: center;
  align-items: center;
  padding: 8px 24px;
  border-radius: 6px;
  border: none;
  outline: none;
  cursor: pointer;
  font-size: 16px;
}

After implementing the above code, the effect is as follows:
insert image description here

Bind events to buttons

document.querySelector(".theme-switch-btn").addEventListener("click", () => {
    
    
  document.body.classList.toggle("dark");
});

Once we have bound an event for the toggle button, we can toggle between dark and light themes. But our page is not animated.

Add zoom-in and zoom-out animations to buttons

.theme-switch-btnAdd the following code to the class:

transition: var(--transition-delay);
transform: scale(1);

The sun and moon icons add corresponding styles

The sun and moon icons will have a rotating animation when switching themes, so we first position the sun and moon absolutely.

.sun-moon-container {
    
    
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  pointer-events: none;
  height: 200vmin;
  top: 0;
}
.sun,
.moon {
    
    
  position: absolute;
}
.sun {
    
    
  top: 5%;
}

.dark .sun {
    
    
  opacity: 0;
}

.moon {
    
    
  bottom: 5%;
  opacity: 1;
}

.dark .moon {
    
    
  opacity: 1;
}

Reset the transparency and animation of the sun and moon

.sun-moon-container {
    
    
  --rotation: 0;

  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  pointer-events: none;
  height: 200vmin;
  top: 0;
  transform: rotate(var(--rotation));
  transition: transform var(--transition-delay);
}

.dark .sun-moon-container {
    
    
  --rotation: 180deg;
}

.sun,
.moon {
    
    
  position: absolute;
  transition: opacity, fill, var(--transition-delay);
  width: 30px;
  height: 30px;
  fill: var(--accent-color);
}
.moon {
    
    
  bottom: 5%;
  opacity: 1;
  transform: rotate(180deg);
}

After completing the above code, our theme switching animation effect has basically been realized, but the sun and the moon switch from left to right, the effect is not very good, so we can add JS to assist in modifying the switching animation.

getComputedStyleGet a CSS variable and reset the value using

First, you need to modify the corresponding styles of the sun and moon containers

.sun-moon-container {
    
    
  --rotation: 0;

  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  pointer-events: none;
  height: 200vmin;
  top: 0;
  transform: rotate(calc(var(--rotation) * 1deg));
  transition: transform var(--transition-delay);
}

/* 当初始化为黑暗主题时有一个初始值 */
.dark .sun-moon-container {
    
    
  --rotation: 0;
}
const sunMonnContainer = document.querySelector(".sun-moon-container");

document.querySelector(".theme-switch-btn").addEventListener("click", () => {
    
    
  document.body.classList.toggle("dark");

  const currentTotation = parseInt(
    getComputedStyle(sunMonnContainer).getPropertyValue("--rotation")
  );

  // 在旋转后的角度上在加上180度作为下次动画的旋转角度
  sunMonnContainer.style.setProperty("--rotation", currentTotation + 180);
});

full code

Complete code sample download

Guess you like

Origin blog.csdn.net/qq_33003143/article/details/132178730