如何构建高级的浅色和深色主题切换

通过这个实例我们主要是掌握如下知识点

  • 灵活使用 CSS 变量
  • 使用 JS 获取 CSS 变量
  • 灵活使用 CSS 的transformtransition属性

效果图

在这里插入图片描述
在这里插入图片描述

实现页面布局

从效果图我们首先可以实现页面的大致布局,具体的代码如下:

<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;
}

实现上述的代码后效果如下:
在这里插入图片描述

为按钮绑定事件

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

为切换按钮绑定事件后,我们就可以在深色主题和浅色主题之间进行切换。但是我们的页面没有动画效果。

为按钮添加放大缩小的动画

.theme-switch-btn类添加如下代码:

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

太阳和月亮图标添加对应样式

太阳和月亮图标在切换主题的时候会有旋转的动画,所以我们先把太阳和月亮进行绝对定位。

.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;
}

重新设置太阳和月亮的透明度以及动画

.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);
}

完成上述代码后,我们的主题切换动画效果基本已经实现,但是太阳和月亮都是左右进行切换,效果并不是很好,所以我们可以添加 JS 来辅助修改切换的动画。

使用getComputedStyle获取 CSS 变量并重新设置值

首先需要修改太阳和月亮容器的对应样式

.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);
});

完整代码

完整代码示例下载

猜你喜欢

转载自blog.csdn.net/qq_33003143/article/details/132178730
今日推荐