Tailwind CSS v4 主题化实践入门(自定义 Theme + 主题模式切换)✨

ok,经过学习Tailwindcss我决定将此专栏建设成为一个Tailwindcss实战专栏,我将在专栏内完成5050挑战:50天50个Tailwindcss练习项目,欢迎大家订阅!!!

Tailwind CSS v4 带来了更强大的主题定制能力,给了前端开发者更加灵活的设计空间。
今天,我们将来学习 Tailwind CSS v4 的主题相关特性,并且给出一套实践模板 🚀

主题相关核心 API 介绍

Tailwind v4 主题使用 @theme 定义,并支持直接使用 CSS 变量来简化主题设计。下面是官方文档链接:

  • 主题变量
  • 添加自定义样式
  • 函数和指令

下面介绍集中常见的主题相关的指令以及自定义变体。

1. @theme 元素

Tailwind v4 引入 @theme 用来定义 CSS 变量,与v3版本需要在 tailwind.config.js 里配置相比,更为简洁统一。

@theme {--color-primary: var(--primary);--radius-md: calc(var(--radius) - 2px);
}

2. @custom-variant

Tailwind v4 支持自定义优先级,实现更灵活的 dark mode 、 sidebar mode 等 UI 体验的切换。

@custom-variant dark (&:is(.dark *));

定义了一个名为 dark 的自定义变体,它会匹配所有带有 .dark 类的元素内部的所有元素。

3. @layer

虽然 Tailwind 能满足大部分样式需求,但有时候还是需要编写纯 CSS。这时,@layer指令就登场了!

  • 使用 @layer 指令告诉 Tailwind 一组自定义样式属于哪个 bucket。有效图层为 basecomponentsutilities
    • 三个图层的生效顺序是不一致的,作用在同一元素上的相同的样式属性,生效优先级顺序是:utilities > components >base
  • 使用 @apply 将任何现有工具类内联到你自己的自定义 CSS 中
  • 你仍然可以在你的css文件中写出任何原生的css样式,但是通常不建议这么做,这会增加维护难度。
@layer base {body {@apply bg-background text-foreground;}
}@layer components {card {@apply bg-card text-card-foreground;}
}@layer utilities {.heading {@apply text-4xl font-bold;}
}

利用Theme 实现主题切换

我们可以通过 :root.dark 样式规则来分别定义不同主题模式下的 变量 值,然后配合 @theme 以及 自定义变体 展开 Tailwind 内部设计。

@custom-variant dark (&:is(.dark *));@theme {--color-background: var(--background);--color-foreground: var(--foreground);--color-card: var(--card);--color-card-foreground: var(--card-foreground);--color-popover: var(--popover);--color-popover-foreground: var(--popover-foreground);--color-primary: var(--primary);--color-primary-foreground: var(--primary-foreground);--color-secondary: var(--secondary);--color-secondary-foreground: var(--secondary-foreground);--color-muted: var(--muted);--color-muted-foreground: var(--muted-foreground);--color-accent: var(--accent);--color-accent-foreground: var(--accent-foreground);--color-destructive: var(--destructive);--color-destructive-foreground: var(--destructive-foreground);--color-border: var(--border);--color-input: var(--input);--color-ring: var(--ring);--color-chart-1: var(--chart-1);--color-chart-2: var(--chart-2);--color-chart-3: var(--chart-3);--color-chart-4: var(--chart-4);--color-chart-5: var(--chart-5);--radius-sm: calc(var(--radius) - 4px);--radius-md: calc(var(--radius) - 2px);--radius-lg: var(--radius);--radius-xl: calc(var(--radius) + 4px);--color-sidebar: var(--sidebar);--color-sidebar-foreground: var(--sidebar-foreground);--color-sidebar-primary: var(--sidebar-primary);--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);--color-sidebar-accent: var(--sidebar-accent);--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);--color-sidebar-border: var(--sidebar-border);--color-sidebar-ring: var(--sidebar-ring);
}:root {--background: oklch(1 0 0);--foreground: oklch(0.145 0 0);--card: oklch(1 0 0);--card-foreground: oklch(0.145 0 0);--popover: oklch(1 0 0);--popover-foreground: oklch(0.145 0 0);--primary: oklch(0.205 0 0);--primary-foreground: oklch(0.985 0 0);--secondary: oklch(0.97 0 0);--secondary-foreground: oklch(0.205 0 0);--muted: oklch(0.97 0 0);--muted-foreground: oklch(0.556 0 0);--accent: oklch(0.97 0 0);--accent-foreground: oklch(0.205 0 0);--destructive: oklch(0.577 0.245 27.325);--destructive-foreground: oklch(0.577 0.245 27.325);--border: oklch(0.922 0 0);--input: oklch(0.922 0 0);--ring: oklch(0.708 0 0);--chart-1: oklch(0.646 0.222 41.116);--chart-2: oklch(0.6 0.118 184.704);--chart-3: oklch(0.398 0.07 227.392);--chart-4: oklch(0.828 0.189 84.429);--chart-5: oklch(0.769 0.188 70.08);--radius: 0.625rem;--sidebar: oklch(0.985 0 0);--sidebar-foreground: oklch(0.145 0 0);--sidebar-primary: oklch(0.205 0 0);--sidebar-primary-foreground: oklch(0.985 0 0);--sidebar-accent: oklch(0.97 0 0);--sidebar-accent-foreground: oklch(0.205 0 0);--sidebar-border: oklch(0.922 0 0);--sidebar-ring: oklch(0.708 0 0);
}.dark {--background: oklch(0.145 0 0);--foreground: oklch(0.985 0 0);--card: oklch(0.145 0 0);--card-foreground: oklch(0.985 0 0);--popover: oklch(0.145 0 0);--popover-foreground: oklch(0.985 0 0);--primary: oklch(0.985 0 0);--primary-foreground: oklch(0.205 0 0);--secondary: oklch(0.269 0 0);--secondary-foreground: oklch(0.985 0 0);--muted: oklch(0.269 0 0);--muted-foreground: oklch(0.708 0 0);--accent: oklch(0.269 0 0);--accent-foreground: oklch(0.985 0 0);--destructive: oklch(0.396 0.141 25.723);--destructive-foreground: oklch(0.637 0.237 25.331);--border: oklch(0.269 0 0);--input: oklch(0.269 0 0);--ring: oklch(0.439 0 0);--chart-1: oklch(0.488 0.243 264.376);--chart-2: oklch(0.696 0.17 162.48);--chart-3: oklch(0.769 0.188 70.08);--chart-4: oklch(0.627 0.265 303.9);--chart-5: oklch(0.645 0.246 16.439);--sidebar: oklch(0.205 0 0);--sidebar-foreground: oklch(0.985 0 0);--sidebar-primary: oklch(0.488 0.243 264.376);--sidebar-primary-foreground: oklch(0.985 0 0);--sidebar-accent: oklch(0.269 0 0);--sidebar-accent-foreground: oklch(0.985 0 0);--sidebar-border: oklch(0.269 0 0);--sidebar-ring: oklch(0.439 0 0);
}
... 其他主题样式

最佳实践:切换主题按钮组件

下面是我创建的用于切换主题的按钮组件,大家可以参考一下:

<template><button@click="toggleTheme"class="flex items-center gap-2 rounded bg-gray-200 px-4 py-2 text-gray-800 transition-colors duration-300 hover:bg-gray-300 dark:bg-gray-700 dark:text-gray-100 dark:hover:bg-gray-600"><span v-if="isDark">🌙 暗黑</span><span v-else>☀️ 亮色</span></button>
</template><script setup>import { ref, onMounted } from 'vue'const isDark = ref(false)const toggleTheme = () => {isDark.value = !isDark.valuedocument.documentElement.classList.toggle('dark')localStorage.setItem('theme', isDark.value ? 'dark' : 'light')}onMounted(() => {const theme = localStorage.getItem('theme')isDark.value = theme === 'dark'if (isDark.value) {document.documentElement.classList.add('dark')}})
</script>

其他

当然tailwindcss v4支持丰富的 自定义样式 复杂样式 以及 自定义变体,今天们探讨一些常用的主题配置和规则。

Tailwind CSS v4 主题相关引入,让你从分散的属性处理升级到全局统一。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/79909.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SAF利用由Varjo和AFormX开发的VR/XR模拟器推动作战训练

通过将AFormX的先进军用飞行模拟器与Varjo的行业领先的VR/XR硬件相结合&#xff0c;斯洛文尼亚武装部队正以经济高效、沉浸式的训练方式培训战斗机飞行员&#xff0c;以提高其战术准备和作战效率。 挑战&#xff1a;获得战术军事航空训练的机会有限 军事航空训练长期以来一直…

VUE中通过DOM导出PDF

最终效果 前端导出PDF的核心在于样式的绘制上&#xff0c;这里其实直接使用CSS进行绘制和布局就行&#xff0c;只不过需要计算好每页DIV盒子的大小&#xff0c;防止一页放不下造成样式错乱。 项目依赖 项目是Vue3 TS npm i html2canvas1.4.1 npm i jspdf3.0.1工具类(htmlToPdf…

SpringAI框架中的RAG模块详解及应用示例

SpringAI框架中的RAG模块详解及应用示例 RAG&#xff08;Retrieval-Augmented Generation&#xff09;可以通过检索知识库&#xff0c;克服大模型训练完成后参数冻结的局限性&#xff0c;携带知识让大模型根据知识进行回答。SpringAI框架提供了模块化的API来支持RAG&#xff0…

MySQL-数据查询(测试)-05-(12-1)

1-数据准备&#xff1a; CREATE TABLE 员工信息表 (员工编号 VARCHAR(10) PRIMARY KEY,姓名 VARCHAR(20),学历 VARCHAR(20),出生日期 DATE,性别 INT,工作年限 INT,地址 VARCHAR(100),电话号码 VARCHAR(20),员工部门号 INT ); INSERT INTO 员工信息表 (员工编号, 姓名, 学历, 出…

5G网络:能源管理的“智能电网“革命,Python如何成为关键推手?

5G网络:能源管理的"智能电网"革命,Python如何成为关键推手? 大家好,我是Echo_Wish。今天咱们聊一个既硬核又接地气的话题——5G网络如何用Python代码重构全球能源管理。 不知道你们有没有注意过: • 家里装了智能电表后,电费突然变"聪明"了,谷时充…

AI背景下,如何重构你的产品?

当AI敲门时&#xff0c;你的产品准备好开门了吗&#xff1f; 最近和做产品的老张聊天&#xff0c;他愁眉苦脸地说&#xff1a;"现在AI这么火&#xff0c;我们的产品就像个老古董&#xff0c;用户都跑隔壁用AI产品去了。“这话让我想起三年前另一个朋友&#xff0c;当时区…

互联网大厂Java面试实战:从Spring Boot到微服务的技术问答与解析

&#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通 &#x1f601; 2. 毕业设计专栏&#xff0c;毕业季咱们不慌忙&#xff0c;几百款毕业设计等你选。 ❤️ 3. Python爬虫专栏…

Apollo学习——aem问题

执行aem指令出现一下问题 lxflxf:~/MYFile/apollo_v10.0 $aem enter permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.49/containers/json?filters%7B%22name%22%…

数字IC后端零基础入门基础理论(Day2)

数字IC后端零基础入门基础理论&#xff08;Day1&#xff09; Placement Blockage: cell摆放阻挡层。它是用来引导工具做placement的一种物理约束或手段&#xff0c;目的是希望工具按照我们的要求来做标准单元的摆放。 它主要有三种类型&#xff0c;分别是hard placement bloc…

如何远程执行脚本不留痕迹

通常我们在做远程维护的时候&#xff0c;会有这么一个需求&#xff0c;就是我想在远程主机执行一个脚本&#xff0c;但是这个脚本我又不想保留在远程主机上&#xff0c;那么有人就说了&#xff0c;那就复制过去再登录远程执行不就行了吗&#xff1f;嗯嗯&#xff0c;但是这还不…

【Lua】java 调用redis执行 lua脚本

【Lua】java 调用redis执行 lua脚本 public Object executeLuaScript(String script, List<String> keys, Object... args) {// 注意: 这里 Long.class 是返回值类型, 一定要指定清楚 不然会报错return this.redisTemplate.execute(RedisScript.of(j脚本, Long.class), k…

利用混合磁共振成像 - 显微镜纤维束成像技术描绘结构连接组|文献速递-深度学习医疗AI最新文献

Title 题目 Imaging the structural connectome with hybrid MRI-microscopy tractography 利用混合磁共振成像 - 显微镜纤维束成像技术描绘结构连接组 01 文献速递介绍 通过多种模态绘制大脑结构能够增进我们对大脑功能、发育、衰老以及疾病的理解&#xff08;汉森等人&am…

Shell脚本实践(修改文件,修改配置文件,执行jar包)

1、前言 需要编写一个shell脚本支持 1、修改.so文件名 2、修改配置文件 3、执行jar包 2、代码解析 2.1、修改.so文件名 so_file_dir="/opt/casb/xxx/lib" # 处理.so文件 cd "$so_file_dir" || { echo "错误: 无法进入目录 $so_file_dir"; exit …

基于GPUGEEK 平台进行深度学习

一、平台简介 GPUGEEK 是一个专注于提供 GPU 算力租赁服务的平台&#xff0c;在人工智能与深度学习领域为用户搭建起便捷的算力桥梁。它整合了丰富多样的 GPU 资源&#xff0c;涵盖 RTX - 4090、RTX - 3090、A100 - PCIE 等多种型号&#xff0c;满足不同用户在模型训练、数据处…

Android Framework学习五:APP启动过程原理及速度优化

文章目录 APP启动优化概述APP启动流程点击图片启动APP的过程启动触发Zygote 与应用进程创建Zygote进程的创建应用进程初始化 ApplicationActivity 启动与显示 优化启动时黑白屏现象可优化的阶段Application阶段相关优化 Activity阶段数据加载阶段 Framework学习系列文章 APP启动…

Web 实时通信技术:WebSocket 与 Server-Sent Events (SSE) 深入解析

一、WebSocket&#xff1a; &#xff08;一&#xff09;WebSocket 是什么&#xff1f; WebSocket 是一种网络通信协议&#xff0c;它提供了一种在单个 TCP 连接上进行全双工通信的方式。与传统的 HTTP 请求 - 响应模型不同&#xff0c;WebSocket 允许服务器和客户端在连接建立…

MySQL(8)什么是主键和外键?

主键&#xff08;Primary Key&#xff09;和外键&#xff08;Foreign Key&#xff09;是关系数据库中用于定义和维护表之间关系的重要概念。以下是详细的解释、示例代码和操作步骤。 主键&#xff08;Primary Key&#xff09; 定义 主键是表中的一个或多个字段&#xff0c;其…

任意复杂度的 JSON 数据转换为多个结构化的 Pandas DataFrame 表格

以下是一个 完整、结构清晰、可运行的 Python 工具&#xff0c;用于将任意复杂度的 JSON 数据转换为多个结构化的 Pandas DataFrame 表格。该工具支持嵌套对象、嵌套数组&#xff0c;并通过主键和外键建立表之间的关联关系。 if __name__ "__main__":# 示例 JSON 数…

【SSL部署与优化​】​​HTTP/2与HTTPS的协同效应

HTTP/2与HTTPS的协同效应&#xff1a;为何HTTP/2强制要求TLS 1.2&#xff1f; HTTP/2是HTTP协议的现代升级版&#xff0c;旨在通过多路复用、头部压缩等技术提升性能。然而&#xff0c;HTTP/2的设计与部署与HTTPS&#xff08;TLS加密&#xff09;紧密相关&#xff0c;甚至强制…

爬虫请求频率应控制在多少合适?

爬虫请求频率的控制是一个非常重要的问题&#xff0c;它不仅关系到爬虫的效率&#xff0c;还涉及到对目标网站服务器的影响以及避免被封禁的风险。合理的请求频率需要根据多个因素来综合考虑&#xff0c;以下是一些具体的指导原则和建议&#xff1a; 一、目标网站的政策 查看网…