You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 10:02:43