Laravel中判断深色模式并切换SVG:适配Tailwind两种模式
适配Tailwind两种深色模式的全局主题切换方案
一、Media模式(跟随系统偏好)下的SVG切换
系统深色模式属于客户端媒体查询状态,后端无法直接获取,需结合前端逻辑实现SVG切换:
方案1:CSS控制显示隐藏
无需Blade判断,直接输出两个SVG,用Tailwind的深色模式类控制显隐:
<!-- 浅色SVG:仅在非深色模式显示 --> <svg class="block dark:hidden" ...>[浅色SVG内容]</svg> <!-- 深色SVG:仅在深色模式显示 --> <svg class="hidden dark:block" ...>[深色SVG内容]</svg>
注意:确保Tailwind配置中darkMode: 'media',dark:前缀会自动跟随系统媒体查询生效。
方案2:JS动态切换(可选)
若需动态替换SVG内容,可通过JS监听媒体查询状态:
const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)'); const svgContainer = document.getElementById('theme-svg'); function updateSvg(isDark) { svgContainer.innerHTML = isDark ? '[深色SVG代码]' : '[浅色SVG代码]'; } // 初始化加载时执行 updateSvg(darkModeQuery.matches); // 监听系统模式变化 darkModeQuery.addEventListener('change', (e) => updateSvg(e.matches));
Blade中仅需一个容器:
<div id="theme-svg"></div>
二、Class模式下的全局主题切换(解决未登录失效问题)
1. 修复全局视图变量共享问题
原view()->composer仅作用于layouts.app,导致其他视图无法获取$theme。修改AppServiceProvider.php的boot方法,实现全局变量共享:
public function boot() { // 全局共享theme变量到所有视图 view()->share('theme', $this->getCurrentTheme()); } private function getCurrentTheme() { $theme = request()->cookie('theme'); // Cookie不存在时,通过请求头获取系统偏好 if (!in_array($theme, ['dark', 'light'])) { $prefersDark = request()->header('Sec-CH-Prefers-Color-Scheme') === 'dark'; $theme = $prefersDark ? 'dark' : 'light'; } return $theme; }
关键改进:
- 用
view()->share替代局部视图 composer,确保所有视图都能拿到$theme - 无Cookie时,通过浏览器自动发送的
Sec-CH-Prefers-Color-Scheme头获取系统偏好
2. 初始化DOM深色模式类
在layouts.app的<html>标签中设置对应class:
<html class="{{ $theme === 'dark' ? 'dark' : '' }}">
3. 主题切换逻辑(前端+后端)
后端:创建切换路由
在web.php中添加:
Route::post('/toggle-theme', function () { $currentTheme = request()->cookie('theme', 'light'); $newTheme = $currentTheme === 'dark' ? 'light' : 'dark'; // 设置全局生效的Cookie,有效期30天 return response()->json(['theme' => $newTheme]) ->cookie('theme', $newTheme, 60*24*30, '/'); });
前端:实现切换按钮
<button id="theme-toggle" class="p-2"> {{ $theme === 'dark' ? '切换到浅色' : '切换到深色' }} </button> <script> const toggleBtn = document.getElementById('theme-toggle'); const htmlEl = document.documentElement; toggleBtn.addEventListener('click', async () => { const response = await fetch('/toggle-theme', { method: 'POST', headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' } }); const data = await response.json(); // 更新DOM类与按钮文本 if (data.theme === 'dark') { htmlEl.classList.add('dark'); toggleBtn.textContent = '切换到浅色'; } else { htmlEl.classList.remove('dark'); toggleBtn.textContent = '切换到深色'; } });
4. 自动跟随系统偏好(无手动设置时)
若希望用户未手动设置主题时,自动跟随系统偏好变化:
const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)'); // 仅当无手动设置的theme Cookie时生效 if (!document.cookie.includes('theme=')) { function updateSystemTheme(isDark) { const htmlEl = document.documentElement; isDark ? htmlEl.classList.add('dark') : htmlEl.classList.remove('dark'); } updateSystemTheme(darkModeQuery.matches); darkModeQuery.addEventListener('change', (e) => updateSystemTheme(e.matches)); }
三、两种模式的兼容切换
若需在media和class模式之间动态切换,可通过Tailwind配置实现:
修改tailwind.config.js:
module.exports = { // 可通过环境变量或配置文件切换模式 darkMode: process.env.TAILWIND_DARK_MODE || 'media', // ...其他配置 };
内容的提问来源于stack exchange,提问作者ThurstonLevi
相关产品推荐
相关产品推荐

