Python Web 实现日夜模式切换功能:从原理到实践

在现代 Web 应用中,日夜模式切换已成为提升用户体验的重要功能。它能有效减少夜间使用时的视觉疲劳,满足不同用户的使用习惯。本文将详细介绍如何在 Python Web 项目中实现这一功能,以 Flask 框架为例,从核心原理到完整代码实现,帮助你快速掌握这一实用技能。

日夜模式切换的核心原理

日夜模式切换本质上是通过动态改变页面的 CSS 样式来实现视觉效果的转换,主要涉及三个关键环节:

  1. 样式分离:为日模式和夜模式分别定义独立的样式规则
  2. 状态存储:使用 Cookie 记录用户的模式偏好
  3. 动态切换:根据用户选择即时切换样式并持久化保存偏好

实现方案选择

在 Python Web 中实现日夜模式有多种方案,各有特点:

纯前端实现

切换无刷新,体验流畅

首次加载可能不符合用户偏好

后端渲染 + Cookie

首屏即可应用正确样式

切换需请求后端,体验稍差

混合方案(推荐)

兼顾首屏正确性和切换流畅度

实现略复杂

本文将采用混合方案,结合前端即时切换和后端状态保存,提供最佳用户体验。

具体实现步骤(基于 Flask)

1. 项目结构准备

首先创建基本的 Flask 项目结构:

"gcdr.thinkobd.cn", "good.thinkobd.cn", "shanzhanggui.cn", "www.shanzhanggui.cn",

plaintext

theme-switch-demo/
├── app.py              # 主应用文件
├── static/
│   ├── css/
│   │   ├── base.css    # 基础共用样式
│   │   ├── day.css     # 日模式样式
│   │   └── night.css   # 夜模式样式
│   └── js/
│       └── theme.js    # 主题切换逻辑
└── templates/
    └── index.html      # 示例页面

2. 准备样式文件

创建三个样式文件,分别存放基础样式和两种模式的特定样式:

"m.shanzhanggui.cn", "wap.shanzhanggui.cn", "gov.cn.shanzhanggui.cn",

static/css/base.css(基础共用样式)

css

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    transition: background-color 0.3s ease, color 0.3s ease;
}

body {
    font-family: 'Segoe UI', sans-serif;
    line-height: 1.6;
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
}

.header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem 0;
    margin-bottom: 2rem;
    border-bottom: 1px solid var(--border-color);
}

.theme-switch {
    display: flex;
    gap: 10px;
}

.theme-btn {
    padding: 8px 16px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 14px;
}

.theme-btn.active {
    font-weight: bold;
}

.content {
    padding: 20px;
}

.card {
    padding: 20px;
    margin-bottom: 20px;
    border-radius: 8px;
}

"gov.shanzhanggui.cn", "govzb.shanzhanggui.cn", "vip.shanzhanggui.cn",

static/css/day.css(日模式样式)

css

:root {
    --bg-color: #ffffff;
    --text-color: #333333;
    --card-bg: #f8f9fa;
    --border-color: #dee2e6;
    --btn-bg: #e9ecef;
    --btn-active: #0d6efd;
}

body {
    background-color: var(--bg-color);
    color: var(--text-color);
}

.card {
    background-color: var(--card-bg);
    border: 1px solid var(--border-color);
}

.theme-btn {
    background-color: var(--btn-bg);
    color: var(--text-color);
}

.theme-btn.active {
    background-color: var(--btn-active);
    color: white;
}

static/css/night.css(夜模式样式)

"gcdr.shanzhanggui.cn", "good.shanzhanggui.cn", "jsdashun.cn", "www.jsdashun.cn",

css

:root {
    --bg-color: #1a1a2e;
    --text-color: #e9ecef;
    --card-bg: #16213e;
    --border-color: #0f3460;
    --btn-bg: #0f3460;
    --btn-active: #e94560;
}

body {
    background-color: var(--bg-color);
    color: var(--text-color);
}

.card {
    background-color: var(--card-bg);
    border: 1px solid var(--border-color);
}

.theme-btn {
    background-color: var(--btn-bg);
    color: var(--text-color);
}

.theme-btn.active {
    background-color: var(--btn-active);
    color: white;
}

3. 创建 Flask 应用核心逻辑

app.py 文件实现后端逻辑,处理主题切换和 Cookie 管理:

"m.jsdashun.cn", "wap.jsdashun.cn", "gov.cn.jsdashun.cn", "gov.jsdashun.cn",

python

运行

from flask import Flask, render_template, make_response, request, redirect, url_for
import os

app = Flask(__name__)

# 主题常量定义
DAY_THEME = 'day'
NIGHT_THEME = 'night'
THEME_COOKIE_NAME = 'preferred_theme'
THEME_EXPIRY_DAYS = 30  # Cookie有效期30天

def get_preferred_theme(request):
    """获取用户偏好的主题"""
    # 从Cookie获取
    theme = request.cookies.get(THEME_COOKIE_NAME)
    if theme in [DAY_THEME, NIGHT_THEME]:
        return theme
    
    # 未设置则尝试检测系统偏好
    # 注意:这只是简单检测,实际生产环境需更完善的处理
    user_agent = request.headers.get('User-Agent', '').lower()
    if 'mac os' in user_agent or 'windows' in user_agent:
        # 这里简化处理,实际应根据更复杂的header判断
        pass
        
    # 默认返回日模式
    return DAY_THEME

@app.route('/')
def index():
    """首页"""
    current_theme = get_preferred_theme(request)
    return render_template('index.html', current_theme=current_theme)

@app.route('/switch-theme')
def switch_theme():
    """切换主题并保存偏好"""
    theme = request.args.get('theme')
    if theme not in [DAY_THEME, NIGHT_THEME]:
        # 无效主题参数,使用默认
        theme = DAY_THEME
    
    # 获取来源页面,默认为首页
    referrer = request.headers.get('Referer', url_for('index'))
    
    # 创建响应
    response = make_response(redirect(referrer))
    
    # 设置Cookie
    response.set_cookie(
        THEME_COOKIE_NAME,
        value=theme,
        max_age=THEME_EXPIRY_DAYS * 24 * 3600,  # 转换为秒
        path='/',
        secure=app.env == 'production',  # 生产环境使用HTTPS
        httponly=True,
        samesite='Lax'
    )
    
    return response

if __name__ == '__main__':
    app.run(debug=True)

4. 创建前端页面

templates/index.html 实现页面结构和主题切换交互:

html

预览

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Python Web 日夜模式示例</title>
    <!-- 基础样式 -->
    <link rel="stylesheet" href="{{ url_for('static', filename='css/base.css') }}">
    <!-- 日模式样式 -->
    <link rel="stylesheet" href="{{ url_for('static', filename='css/day.css') }}" 
          id="day-theme" 
          {% if current_theme == 'night' %}disabled{% endif %}>
    <!-- 夜模式样式 -->
    <link rel="stylesheet" href="{{ url_for('static', filename='css/night.css') }}" 
          id="night-theme" 
          {% if current_theme == 'day' %}disabled{% endif %}>
</head>
<body>
    <header class="header">
        <h1>Python Web 日夜模式切换示例</h1>
        <div class="theme-switch">
            <button id="day-btn" class="theme-btn {% if current_theme == 'day' %}active{% endif %}">
                日模式
            </button>
            <button id="night-btn" class="theme-btn {% if current_theme == 'night' %}active{% endif %}">
                夜模式
            </button>
        </div>
    </header>
    
    <main class="content">
        <div class="card">
            <h2>欢迎使用</h2>
            <p>这是一个演示如何在Python Web项目中实现日夜模式切换的示例页面。</p>
            <p>点击右上角的按钮可以切换模式,您的偏好会被记住。</p>
        </div>
        
        <div class="card">
            <h3>功能特点</h3>
            <ul>
                <li>即时切换,无需页面刷新</li>
                <li>通过Cookie记住用户偏好</li>
                <li>平滑过渡动画效果</li>
                <li>响应式设计,适配各种设备</li>
            </ul>
        </div>
    </main>

    <script src="{{ url_for('static', filename='js/theme.js') }}"></script>
</body>
</html>

5. 实现前端切换逻辑

static/js/theme.js 处理前端即时切换和后端同步:

javascript

运行

// 获取DOM元素
const dayTheme = document.getElementById('day-theme');
const nightTheme = document.getElementById('night-theme');
const dayBtn = document.getElementById('day-btn');
const nightBtn = document.getElementById('night-btn');

// 切换到日模式
function switchToDayMode() {
    dayTheme.disabled = false;
    nightTheme.disabled = true;
    dayBtn.classList.add('active');
    nightBtn.classList.remove('active');
    syncWithServer('day');
}

// 切换到夜模式
function switchToNightMode() {
    dayTheme.disabled = true;
    nightTheme.disabled = false;
    dayBtn.classList.remove('active');
    nightBtn.classList.add('active');
    syncWithServer('night');
}

// 与服务器同步主题设置
function syncWithServer(theme) {
    // 使用fetch API发送请求
    fetch(`/switch-theme?theme=${theme}`, {
        method: 'GET',
        credentials: 'include'  // 确保发送Cookie
    })
    .catch(error => console.error('主题同步失败:', error));
}

// 绑定按钮事件
dayBtn.addEventListener('click', switchToDayMode);
nightBtn.addEventListener('click', switchToNightMode);

// 检测系统主题偏好(如果没有用户设置)
if (!document.cookie.includes('preferred_theme=')) {
    const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
    if (prefersDark) {
        switchToNightMode();
    }
}

// 监听系统主题变化
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
    // 只有在没有用户设置的情况下才响应系统变化
    if (!document.cookie.includes('preferred_theme=')) {
        if (event.matches) {
            switchToNightMode();
        } else {
            switchToDayMode();
        }
    }
});

实现要点与优化建议

  1. 安全性考虑:设置 Cookie 的httponly属性防止 XSS 攻击生产环境中启用secure属性确保通过 HTTPS 传输验证所有用户输入的主题参数
  2. 用户体验优化:添加 CSS 过渡动画使切换更平滑支持系统主题自动检测切换按钮添加视觉反馈确保两种模式下文本与背景的对比度符合无障碍标准
  3. 性能优化:使用 CSS 变量减少样式冗余合并静态资源,减少 HTTP 请求考虑使用 localStorage 缓存主题设置,减少 Cookie 依赖
  4. 扩展性考虑:可扩展为多主题支持(不仅仅是日夜两种)可添加主题重置功能可支持用户自定义主题颜色

总结

通过本文介绍的方法,你可以在 Python Web 项目(以 Flask 为例)中快速实现一个体验良好的日夜模式切换功能。该方案结合了后端 Cookie 管理和前端即时切换的优势,既保证了用户首次访问就能看到符合其偏好的主题,又实现了无刷新的平滑切换效果。

这种实现方式不仅适用于 Flask,其核心思想也可以轻松迁移到 Django 等其他 Python Web 框架中。在实际项目中,你可以根据具体需求调整样式和交互细节,为用户提供更加个性化的浏览体验。

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务