当前位置: 首页 > article >正文

Tailwind CSS 实战,基于 Kooboo 构建 AI 对话框页面(三):实现暗黑模式主题切换

基于前两篇的内容,为页面添加主题切换功能,实现网站页面的暗黑模式: 

Tailwind css实战,基于Kooboo构建AI对话框页面(一)-CSDN博客

Tailwind css实战,基于Kooboo构建AI对话框页面(二)-CSDN博客


在前两篇内容的基础上,为页面新增暗黑 / 亮色双主题切换功能,完善用户体验。最终效果如下:


一、暗黑模式的需求与价值

  1. 用户体验升级:提供亮色 / 暗黑主题切换,适配不同使用场景(如夜间阅读、视觉偏好),提升产品包容性。
  2. 视觉一致性:通过 CSS 变量统一管理颜色,确保主题切换时界面元素(如聊天气泡、按钮、文本)的样式协调。
  3. 技术挑战:如何实现动态主题切换、持久化存储用户偏好。

二、暗黑模式技术实现(核心代码解析)

1. CSS 变量定义:主题解耦

在 CSS 中,通过:root伪类定义的变量是全局作用域的,它代表了文档的根元素(在 HTML 中就是<html>元素)。这里定义的变量是亮色主题(也就是默认主题)下的颜色值。

<style>/* 亮色主题(默认) */:root {--bg-primary: #ffffff;--bg-secondary: #f8f9fa;--bg-tertiary: #e9ecef;--border-color: #dee2e6;--text-primary: #333333;--text-secondary: #6c757d;--text-tertiary: #e5e7eb;--chat-bubble: #ffffff;--chat-bubble-ai: #f8f9fa;}/* 暗黑主题 */.dark {--bg-primary: #1e293b;--bg-secondary: #0f172a;--bg-tertiary: #334155;--border-color: #4b5563;--text-primary: #f3f4f6;--text-secondary: #9ca3af;--text-tertiary: #1f2937;--chat-bubble: #334155;--chat-bubble-ai: #1e293b;}</style>

作用:通过 :root 和 .dark 类定义全局颜色变量,后续样式直接引用变量(如 bg-[var(--bg-primary)]),实现主题 “一键切换”。

  • Tailwind 整合:利用 var() 函数与 Tailwind 的自定义值([] 语法)结合,如background-color: var(--bg-primary);无需重复编写暗黑模式专属类。
2. 切换按钮 UI(HTML + Tailwind)

从 HTML 结构来看,这是一个用于切换暗黑模式的按钮。id="darkModeToggle"为按钮赋予了唯一标识,方便在 JavaScript 中获取和操作

<!-- 暗黑模式切换按钮 --><button id="darkModeToggle" class="fixed top-4 right-4 z-10 bg-[var(--bg-primary)] text-[var(--text-primary)] p-2 rounded-full shadow-lg hover:bg-[var(--bg-tertiary)] transition-colors"><i class="fa fa-moon-o dark:hidden"></i><i class="fa fa-sun-o hidden dark:inline"></i></button>
  • 交互设计
    • 固定定位(fixed)确保按钮始终可见;
    • dark:hidden 和 dark:inline 实现图标随主题切换(Tailwind 暗黑模式前缀 dark: 自动匹配 .dark 类);
    • hover 效果(hover:bg-[var(--bg-tertiary)])增强交互反馈。
3. 主题切换逻辑(JavaScript)
<script>// 暗黑模式切换逻辑document.addEventListener('DOMContentLoaded', function() {const toggle = document.getElementById('darkModeToggle');const html = document.documentElement;// 检查本地存储中的偏好设置if (localStorage.getItem('darkMode') === 'true' || (localStorage.getItem('darkMode') === null && window.matchMedia('(prefers-color-scheme: dark)').matches)) {html.classList.add('dark');}// 切换事件:更新类名 + 本地存储toggle.addEventListener('click', function() {html.classList.toggle('dark');localStorage.setItem('darkMode', html.classList.contains('dark'));});});</script>

这段 JavaScript 代码的作用是实现暗黑模式的切换逻辑和用户偏好的管理:

  • document.addEventListener('DOMContentLoaded', () => {... }):这是一个事件监听器,当页面的 DOM(文档对象模型)加载完成后,才会执行里面的代码。确保在页面元素都加载好之后再进行操作,避免获取不到元素的情况。
  • const toggle = document.getElementById('darkModeToggle');:通过id获取到页面上的暗黑模式切换按钮元素

核心逻辑

  • 持久化存储:通过 localStorage 记录用户选择,刷新页面后保持主题;
  • 系统主题适配:首次访问时,若用户系统偏好暗黑模式(prefers-color-scheme: dark),自动启用暗黑主题;
  • 性能优化:直接操作 document.documentElement(HTML 根元素)的 classList,确保样式切换无延迟。

三、与前两章内容的整合

  1. 容器样式与 CSS 变量深度绑定
    在 HTML 中通过 bg-[var(--bg-primary)] border-[var(--border-color)] 等写法,将容器的背景色、边框色直接关联到 CSS 变量。。例如:

    <!-- 窗口容器 -->
    <div class="max-w-3xl w-full bg-[var(--bg-primary)]      <!-- 主背景色,亮色/暗黑模式自动切换 -->border border-[var(--border-color)]  <!-- 边框色 -->rounded-lg shadow-xl overflow-hidden"><!-- 消息容器 -->
    <div id="messageContainer" class="h-[60vh] overflow-y-auto p-4 space-y-4 bg-[var(--bg-secondary)]"><!-- 输入区域 -->
    <div class="bg-[var(--bg-primary)] p-4 border-t border-[var(--border-color)]">
    优势:所有容器样式通过变量动态控制,一行 CSS 变量修改即可全局响应主题切换,无需逐个组件调整样式,极大提高了开发效率。
  2. 测试场景

    • 手动切换主题,检查所有 UI 元素(背景、文本、边框、图标)是否正确响应;
    • 刷新页面,查看是否会清除本地存储,验证系统主题适配逻辑;
    • 检查移动端(如小屏幕下按钮定位、交互是否正常)。

四、总结

本章通过 CSS 变量 + 本地存储 + 系统主题适配,实现了 AI 对话框的暗黑模式切换,完成了从 静态页面(一)→ 交互逻辑(二)→ 视觉主题优化(三) 的完整实战链路。代码中:

  • Tailwind 与自定义变量的深度整合,简化了主题样式管理;
  • JavaScript 逻辑 确保用户偏好持久化和系统兼容性;
  • UI 细节(如图标切换) 提升了交互体验。

相关文章:

Tailwind CSS 实战,基于 Kooboo 构建 AI 对话框页面(三):实现暗黑模式主题切换

基于前两篇的内容&#xff0c;为页面添加主题切换功能&#xff0c;实现网站页面的暗黑模式&#xff1a; Tailwind css实战&#xff0c;基于Kooboo构建AI对话框页面&#xff08;一&#xff09;-CSDN博客 Tailwind css实战&#xff0c;基于Kooboo构建AI对话框页面&#xff08;…...

OleDbParameter.Value 与 DataTable.Rows.Item.Value 的性能对比

OleDbParameter.Value 与 DataTable.Rows.Item.Value 的性能对比 您提到的两种赋值操作属于不同场景&#xff0c;它们的性能和稳定性取决于具体使用方式。下面从几个维度进行分析&#xff1a; 1. 操作本质对比 &#xff08;1&#xff09;OleDbParameter.Value 用途&#xf…...

Unity3D ET框架游戏脚本系统解析

前言 ET框架在Unity3D中实现的GamePlay脚本系统是一种革命性的、基于ECS&#xff08;实体-组件-系统&#xff09;架构的设计&#xff0c;它彻底改变了传统的基于MonoBehaviour的游戏逻辑编写方式。其核心思想是追求高性能、高解耦、易热更新&#xff0c;特别适合大型复杂的网络…...

函数的定义、调用、值传递、声明、非安全函数

函数 函数&#xff08;英文“function”&#xff09;把一些经常用到的代码封装起来&#xff0c;这样可以减少一些冗余代码、重复的代码。一个大的程序&#xff0c;它是由很多很多程序块组成的&#xff0c;每个模块实现一个特定的功能。 函数的定义 格式 英文版 return_typ…...

MySQL 8.0 OCP 英文题库解析(十一)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题91~100 试题91…...

机器学习算法-k-means

今天我们用 「超市顾客分组」 的例子来讲解K-means算法&#xff0c;从原理到实现一步步拆解&#xff0c;保证零基础也能懂&#xff01; &#x1f6d2; 例子背景 假设你是超市经理&#xff0c;手上有顾客的以下数据&#xff1a; 顾客ID每月消费金额&#xff08;元&#xff09;…...

ADQ36-2通道2.5G,4通道5G采样PXIE

ADQ36是一款高端12位四通道灵活数据采集板&#xff0c;针对高通道数科学应用进行了优化。ADQ36具有以下特性: 4 / 2模拟输入通道每通道2.5 / 5 GSPS7gb/秒的持续数据传输速率两个外部触发器通用输入/输出&#xff08;GPIO&#xff09;ADQ36数字化仪包括固件FWDAQ ADQ36简介 特…...

LLM:decoder-only 思考

文章目录 前言一、KV-cache1、为什么使用KV-cache2、KV-cache的运作原理 二、Decoder-only VS Encoder-Decoder1、Decoder-only2、Encoder-Decoder 三、Causal LM VS PrefixLM总结 前言 decoder-only模型是目前大模型的主流架构&#xff0c;由于OpenAI勇于挖坑踩坑&#xff0c…...

数字创新智慧园区建设及运维方案

该文档是 “数字创新智慧园区” 建设及运维方案,指出传统产业园区存在管理粗放等问题,“数字创新园区” 通过大数据、AI、物联网、云计算等数字化技术,旨在提升园区产业服务、运营管理水平,增强竞争力,实现绿色节能、高效管理等目标。建设内容包括智能设施、核心支撑平台、…...

【科研绘图系列】R语言绘制森林图(forest plot)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载导入数据数据预处理画图系统信息介绍 本文介绍使用R语言绘制森林图(forest plot)的方法。首先加载必要的R包(grid、forestploter、openxlsx、stringr),导入并预处…...

Springcloud Alibaba自定义负载均衡详解

主要说一下springcloud alibaba 在使用nacos注册中心过程中&#xff0c;请求服务负载均衡的配置方法 引入依赖包 这个依赖包是springcloud在新版本的负载均衡实现&#xff0c;2020版本以上 <dependency><groupId>org.springframework.cloud</groupId><ar…...

深度学习---负样本训练

一、负样本的本质与核心作用 1. 定义与范畴 负样本&#xff08;Negative Sample&#xff09;是与目标样本&#xff08;正样本&#xff09;在语义、特征或任务目标上存在显著差异的样本。其核心价值在于通过对比学习引导模型学习样本间的判别性特征&#xff0c;而非仅记忆正样本…...

SpringAI+DeepSeek大模型应用开发实战

内容来自黑马程序员 这里写目录标题 认识AI和大模型大模型应用开发模型部署方案对比模型部署-云服务模型部署-本地部署调用大模型什么是大模型应用传统应用和大模型应用大模型应用 大模型应用开发技术架构 SpringAI对话机器人快速入门会话日志会话记忆 认识AI和大模型 AI的发…...

【Python Cookbook】文件与 IO(一)

文件与 IO&#xff08;一&#xff09; 1.读写文本数据2.打印输出至文件中3.使用其他分隔符或行终止符打印4.读写字节数据5.文件不存在才能写入 1.读写文本数据 你需要读写各种不同编码的文本数据&#xff0c;比如 ASCII&#xff0c;UTF-8 或 UTF-16 编码等。 使用带有 rt 模式…...

STM32 HAL库函数学习 GPIO篇

1、void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, const GPIO_InitTypeDef *pGPIO_Init) GPIO外设属于是任何芯片的最基础功能 &#xff0c;STM32各个系列的GPIO初始化都是一致的&#xff0c;有不同的是部分系列在IO复用使用了单独一个成员属性Alternate 来表明这个IO的具体复用功…...

如何以 9 种方式将照片从 iPhone 传输到笔记本电脑

您的 iPhone 可能充满了以照片和视频形式捕捉的珍贵回忆。无论您是想备份它们、在更大的屏幕上编辑它们&#xff0c;还是只是释放设备上的空间&#xff0c;您都需要将照片从 iPhone 传输到笔记本电脑。幸运的是&#xff0c;有 9 种方便的方法可供使用&#xff0c;同时满足 Wind…...

根据jvm源码剖析类加载机制

根据jvm源码剖析类加载机制 java Test.class之后的大致流程 java Test.class ----> 对于windows操作系统 ----> java.exe调用jvm.dll文件创建JVM&#xff0c; ----> 在创建JVM中先由C的代码创建Boostarp&#xff08;引导&#xff09;类加载器&#xff0c; ----&g…...

Mixly1.0/2.0/3.0 (windows系统) 安装教程及使用常见问题解决

大家好&#xff01;长期以来&#xff0c;不少用户在使用 Mixly 软件过程中遇到了各类问题。为了帮助大家更顺畅地使用该软件&#xff0c;齐护机器人工程师结合自身丰富经验&#xff0c;精心总结并推出了本期教程。在本教程中&#xff0c;我们将从 Mixly 图形化编程软件的安装步…...

DDS通信中间件——DDS-TSN规范

DDS通信中间件——DDS-TSN规范 做了十年DDS通信中间件产品的程序员和大家分享一下对DDS这套规范的个人理解。预期本系列文章将包括以下内容陆续更新&#xff1a; DDS规范概述DCPS规范解读 & QoS策略XTypes规范解读RTPS规范解读DDS安全规范解读DDS-RPC规范解读&#xff08…...

JWT安全:弱签名测试.【实现越权绕过.】

JWT安全&#xff1a;假密钥【签名随便写实现越权绕过.】 JSON Web 令牌 (JWT)是一种在系统之间发送加密签名 JSON 数据的标准化格式。理论上&#xff0c;它们可以包含任何类型的数据&#xff0c;但最常用于在身份验证、会话处理和访问控制机制中发送有关用户的信息(“声明”)。…...

MATLAB实现井字棋

一、智能决策系统与博弈游戏概述 &#xff08;一&#xff09;智能决策系统核心概念 智能决策系统&#xff08;Intelligent Decision System, IDS&#xff09;是通过数据驱动和算法模型模拟人类决策过程的计算机系统&#xff0c;核心目标是在复杂环境中自动生成最优策略&#…...

Baklib知识中台加速企业服务智能化实践

知识中台架构体系构建 Baklib 通过构建多层级架构体系实现知识中台的底层支撑&#xff0c;其核心包含数据采集层、知识加工层、服务输出层及智能应用层。在数据采集端&#xff0c;系统支持对接CRM、ERP等业务系统&#xff0c;结合NLP技术实现非结构化数据的自动抽取&#xff1…...

在AIX环境下修改oracle 11g rac的IP地址

0、当前环境 由于机房网络变更&#xff0c;客户要修改现在RAC的网络地址&#xff0c;这里记录一下。 主机操作系统&#xff1a;AIX 7.2 数据库版本&#xff1a;11.2.0.4 rac 数据库实例名&#xff1a;orcl1/orcl2 当前hosts文件配置 192.168.56.10 rac1 192.168.56.11 …...

VMware Tools 手动编译安装版

OWASPBWA安装VMware tools 安装时&#xff0c;显示如下提示 官方安装手册参考&#xff1a;https://knowledge.broadcom.com/external/article?legacyId1014294 按照提示&#xff0c;下载linux.iso文件&#xff0c;并连接到虚拟机的CDROM里&#xff0c;状态勾选已连接&#x…...

android平台驱动开发(六)--Makefile和Kconfig简介

Makefile&#xff1a; 1.编译进内核&#xff0c;还是以模块方式加载 模块方式编译成ko,通常是自己添加脚本方式insmod ,android 平台通常默认有modprobe加载&#xff0c;不需要额外添加insmod脚本 lsmod |grep test 可以查看是否安装成功 rmmod test-m.ko 可以删除ko 2.多…...

【手写系列】手写线程池

PS&#xff1a;本文的线程池为演示 Demo&#xff0c;皆在理解线程池的工作原理&#xff0c;并没有解决线程安全问题。 最简单一版的线程池 public class MyThreadPool {// 存放线程&#xff0c;复用已创建的线程List<Thread> threadList new ArrayList<>();publ…...

python学习打卡day40

DAY 40 训练和测试的规范写法 知识点回顾&#xff1a; 彩色和灰度图片测试和训练的规范写法&#xff1a;封装在函数中展平操作&#xff1a;除第一个维度batchsize外全部展平dropout操作&#xff1a;训练阶段随机丢弃神经元&#xff0c;测试阶段eval模式关闭dropout 作业&#…...

redis高并发问题

Redlock原理和存在的问题 Redlock 基于以下假设&#xff1a; 有多个&#xff08;一般建议是 5 个&#xff09;彼此独立的 Redis 实例&#xff08;不是主从复制&#xff0c;也不是集群模式&#xff09;&#xff0c;它们之间没有数据同步。客户端可以与所有 Redis 实例通信。 …...

Live Helper Chat 安装部署

Live Helper Chat(LHC)是一款开源的实时客服聊天系统,适用于网站和应用,帮助企业与访问者即时沟通。它功能丰富、灵活、可自托管,常被用于在线客户支持、销售咨询以及技术支持场景。 🧰 系统要求 安装要求 您提供的链接指向 Live Helper Chat 的官方安装指南页面,详细…...

ARXML解析与可视化工具

随着汽车电子行业的快速发展,AUTOSAR标准在车辆软件架构中发挥着越来越重要的作用。然而,传统的ARXML文件处理工具往往存在高昂的许可费用、封闭的数据格式和复杂的使用门槛等问题。本文介绍一种基于TXT格式输出的ARXML解析方案,为开发团队提供了一个高效的替代解决方案。 …...