Files
argon-theme/.kiro/specs/global-ui-optimization/design.md
nanhaoluo f8d7c79b86 feat: 全局 UI 优化与邮件模板系统
- 新增动画系统 CSS 变量(时长、缓动函数、状态层透明度)
- 新增 prefers-reduced-motion 媒体查询支持
- 优化按钮组件样式,移除渐变背景,添加涟漪效果
- 优化分享按钮错落有致的展开动画
- 优化评论区展开动画效果
- 新增设置面板 Material 3 风格分段控件
- 新增玻璃拟态(Glassmorphism)主题变体
- 新增新拟态(Neumorphism)主题变体
- 新增邮件模板系统(base.php、comment-notify.php、reply-notify.php)
- 新增邮件模板后台设置(主题色、Logo、社交链接、预览功能)
- 集成邮件模板到评论回复通知
- 版本更新至 1.5.0
2026-01-11 22:13:59 +08:00

26 KiB
Raw Blame History

Design Document: Global UI Optimization

Overview

本设计文档描述 Argon WordPress 主题的全局 UI 优化方案,参考 Apple Human Interface Guidelines 和 Material Design 3 设计规范。优化重点包括:按钮样式现代化、设置面板重构、分享按钮动画增强、评论展开动画优化,以及新增多种设计风格选项。

Architecture

设计系统架构

┌─────────────────────────────────────────────────────────────┐
│                    CSS Variables Layer                       │
│  (动画时长、缓动函数、颜色、圆角、阴影等设计令牌)              │
├─────────────────────────────────────────────────────────────┤
│                    Base Components Layer                     │
│  (按钮、卡片、输入框等基础组件样式)                           │
├─────────────────────────────────────────────────────────────┤
│                    Feature Components Layer                  │
│  (设置面板、分享按钮、评论切换等功能组件)                     │
├─────────────────────────────────────────────────────────────┤
│                    Theme Variants Layer                      │
│  (玻璃拟态、新拟态、Material 3 等主题变体)                    │
└─────────────────────────────────────────────────────────────┘

文件结构

style.css                    # 主样式文件(修改)
argontheme.js               # 主脚本文件(修改)
functions.php               # 主函数文件(修改 - 添加邮件模板函数)
settings.php                # 设置页面(修改 - 添加邮件模板设置)
template-parts/
  └── post-actions.php      # 文章操作按钮模板(修改)
email-templates/
  └── base.php              # 邮件基础模板(新增)
  └── comment-notify.php    # 评论通知模板(新增)
  └── reply-notify.php      # 回复通知模板(新增)

Components and Interfaces

1. 动画系统 CSS 变量

:root {
  /* 动画时长 */
  --animation-fast: 150ms;
  --animation-normal: 250ms;
  --animation-slow: 400ms;
  --animation-slower: 600ms;
  
  /* 缓动函数 - Material 3 标准 */
  --ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --ease-standard-decelerate: cubic-bezier(0, 0, 0, 1);
  --ease-standard-accelerate: cubic-bezier(0.3, 0, 1, 1);
  --ease-emphasized: cubic-bezier(0.2, 0, 0, 1);
  --ease-emphasized-decelerate: cubic-bezier(0.05, 0.7, 0.1, 1);
  --ease-emphasized-accelerate: cubic-bezier(0.3, 0, 0.8, 0.15);
  
  /* 弹性缓动 */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
  
  /* 状态层透明度 - Material 3 */
  --state-hover-opacity: 0.08;
  --state-focus-opacity: 0.12;
  --state-pressed-opacity: 0.12;
  --state-dragged-opacity: 0.16;
}

2. 按钮组件设计

主要按钮 (Filled Button)

.btn-primary {
  background-color: var(--themecolor);
  border: none;
  border-radius: var(--card-radius);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
  transition: 
    background-color var(--animation-fast) var(--ease-standard),
    box-shadow var(--animation-fast) var(--ease-standard),
    transform var(--animation-fast) var(--ease-standard);
  position: relative;
  overflow: hidden;
}

.btn-primary:hover {
  background-color: var(--themecolor-dark);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}

.btn-primary:active {
  background-color: var(--themecolor-dark2);
  transform: scale(0.98);
}

涟漪效果 (Ripple Effect)

.btn-ripple {
  position: relative;
  overflow: hidden;
}

.btn-ripple::after {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  pointer-events: none;
  background-image: radial-gradient(circle, rgba(255,255,255,0.3) 10%, transparent 10.01%);
  background-repeat: no-repeat;
  background-position: 50%;
  transform: scale(10, 10);
  opacity: 0;
  transition: transform var(--animation-slow), opacity var(--animation-normal);
}

.btn-ripple:active::after {
  transform: scale(0, 0);
  opacity: 1;
  transition: 0s;
}

3. 设置面板设计

面板容器

#fabtn_blog_settings_popup {
  background: var(--color-foreground);
  border-radius: 16px;
  box-shadow: 
    0 8px 32px rgba(0, 0, 0, 0.12),
    0 2px 8px rgba(0, 0, 0, 0.08);
  padding: 16px 20px;
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}

分组卡片布局

设计决策:使用分组卡片将相关设置项组织在一起,提升视觉层次和可读性。

.settings-group {
  background: var(--color-background);
  border-radius: 12px;
  padding: 12px 16px;
  margin-bottom: 12px;
}

.settings-group-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--color-text-light);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-bottom: 8px;
}

.settings-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 0;
}

.settings-item + .settings-item {
  border-top: 1px solid var(--color-border-light);
}

分段控件 (Segmented Control)

.segmented-control {
  display: inline-flex;
  background: var(--color-widgets-disabled);
  border-radius: 10px;
  padding: 3px;
  gap: 2px;
}

.segmented-control-item {
  padding: 6px 14px;
  border-radius: 8px;
  border: none;
  background: transparent;
  color: var(--color-text-deeper);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: all var(--animation-fast) var(--ease-standard);
}

.segmented-control-item.active {
  background: var(--themecolor);
  color: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
}

4. 分享按钮动画设计

容器样式

#share_container {
  position: relative;
  display: inline-flex;
  align-items: center;
}

#share {
  display: flex;
  gap: 6px;
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  opacity: 0;
  pointer-events: none;
}

#share > a {
  opacity: 0;
  transform: scale(0.8) translateX(10px);
}

展开动画

#share_container.opened #share {
  opacity: 1;
  pointer-events: auto;
}

#share_container.opened #share > a {
  opacity: 1;
  transform: scale(1) translateX(0);
  transition: 
    opacity var(--animation-normal) var(--ease-emphasized-decelerate),
    transform var(--animation-normal) var(--ease-spring);
}

/* 错落动画延迟 */
#share_container.opened #share > a:nth-child(1) { transition-delay: 0ms; }
#share_container.opened #share > a:nth-child(2) { transition-delay: 30ms; }
#share_container.opened #share > a:nth-child(3) { transition-delay: 60ms; }
#share_container.opened #share > a:nth-child(4) { transition-delay: 90ms; }
#share_container.opened #share > a:nth-child(5) { transition-delay: 120ms; }
#share_container.opened #share > a:nth-child(6) { transition-delay: 150ms; }
#share_container.opened #share > a:nth-child(7) { transition-delay: 180ms; }
#share_container.opened #share > a:nth-child(8) { transition-delay: 210ms; }

主按钮变换

#share_show {
  transition: 
    transform var(--animation-normal) var(--ease-standard),
    opacity var(--animation-normal) var(--ease-standard);
}

#share_container.opened #share_show {
  transform: rotate(45deg) scale(0.9);
  opacity: 0.7;
}

点击外部收起逻辑

设计决策:使用事件委托监听 document 点击事件,判断点击目标是否在分享容器外部。

// 点击外部收起分享面板
document.addEventListener('click', function(e) {
  const shareContainer = document.getElementById('share_container');
  if (shareContainer && shareContainer.classList.contains('opened')) {
    // 检查点击目标是否在分享容器外部
    if (!shareContainer.contains(e.target)) {
      shareContainer.classList.remove('opened');
    }
  }
});

5. 评论展开动画设计

评论区容器

#comments, #post_comment {
  transition: 
    max-height var(--animation-slow) var(--ease-emphasized),
    opacity var(--animation-normal) var(--ease-standard),
    margin var(--animation-slow) var(--ease-standard),
    padding var(--animation-slow) var(--ease-standard);
  overflow: hidden;
  will-change: max-height, opacity;
}

#comments.comments-collapsed,
#post_comment.comments-collapsed {
  max-height: 0 !important;
  opacity: 0;
  margin-top: 0 !important;
  margin-bottom: 0 !important;
  padding-top: 0 !important;
  padding-bottom: 0 !important;
  border: none !important;
}

#comments:not(.comments-collapsed),
#post_comment:not(.comments-collapsed) {
  max-height: 9999px;
  opacity: 1;
}

切换按钮图标动画

#comments_toggle .btn-inner--icon i {
  transition: transform var(--animation-normal) var(--ease-spring);
}

#comments_toggle.expanded .btn-inner--icon i {
  transform: rotate(180deg);
}

折叠反向动画

设计决策折叠动画使用与展开相同的过渡属性CSS transition 会自动处理反向动画。通过调整缓动函数实现自然的收起效果。

/* 折叠状态 - 使用 accelerate 缓动使收起更自然 */
#comments.comments-collapsed,
#post_comment.comments-collapsed {
  transition: 
    max-height var(--animation-slow) var(--ease-emphasized-accelerate),
    opacity var(--animation-fast) var(--ease-standard-accelerate),
    margin var(--animation-slow) var(--ease-standard),
    padding var(--animation-slow) var(--ease-standard);
}

6. 主题变体设计

悬停效果增强

设计决策:为所有可交互元素添加统一的悬停效果,使用微妙的缩放和阴影变化提升交互反馈。

/* 通用悬停效果 */
.card:hover,
.btn:hover {
  transform: translateY(-1px);
  box-shadow: 
    0 4px 12px rgba(0, 0, 0, 0.1),
    0 2px 4px rgba(0, 0, 0, 0.06);
  transition: 
    transform var(--animation-fast) var(--ease-standard),
    box-shadow var(--animation-fast) var(--ease-standard);
}

/* 可点击元素的微缩放效果 */
.clickable:hover {
  transform: scale(1.02);
}

.clickable:active {
  transform: scale(0.98);
}

玻璃拟态 (Glassmorphism)

html.style-glass .card,
html.style-glass #fabtn_blog_settings_popup {
  background: rgba(255, 255, 255, 0.7);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  border: 1px solid rgba(255, 255, 255, 0.3);
}

html.darkmode.style-glass .card,
html.darkmode.style-glass #fabtn_blog_settings_popup {
  background: rgba(66, 66, 66, 0.7);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

新拟态 (Neumorphism)

html.style-neumorphism .card {
  background: var(--color-background);
  box-shadow: 
    8px 8px 16px rgba(0, 0, 0, 0.1),
    -8px -8px 16px rgba(255, 255, 255, 0.8);
  border: none;
}

html.darkmode.style-neumorphism .card {
  box-shadow: 
    8px 8px 16px rgba(0, 0, 0, 0.3),
    -8px -8px 16px rgba(255, 255, 255, 0.05);
}

Material 3 动态色彩系统

设计决策:实现 Material 3 的动态色彩系统,根据主题色自动生成协调的色彩方案。使用 CSS 变量和 HSL 色彩空间实现动态计算。

:root {
  /* Material 3 色彩角色 - 基于主题色动态生成 */
  --md-primary: var(--themecolor);
  --md-on-primary: #ffffff;
  --md-primary-container: var(--themecolor-light);
  --md-on-primary-container: var(--themecolor-dark2);
  
  /* 表面色彩 */
  --md-surface: var(--color-background);
  --md-surface-variant: var(--color-foreground);
  --md-on-surface: var(--color-text);
  --md-on-surface-variant: var(--color-text-light);
  
  /* 轮廓色彩 */
  --md-outline: var(--color-border);
  --md-outline-variant: var(--color-border-light);
}

/* Material 3 风格组件 */
html.style-material3 .card {
  background: var(--md-surface);
  border-radius: 16px;
  box-shadow: 
    0 1px 3px rgba(0, 0, 0, 0.12),
    0 1px 2px rgba(0, 0, 0, 0.24);
}

html.style-material3 .btn-primary {
  background: var(--md-primary);
  color: var(--md-on-primary);
  border-radius: 20px;
  font-weight: 500;
  letter-spacing: 0.1px;
}

html.style-material3 .btn-primary:hover {
  box-shadow: 
    0 2px 4px rgba(0, 0, 0, 0.14),
    0 3px 4px rgba(0, 0, 0, 0.12);
}
// Material 3 动态色彩生成函数
function generateMaterial3Colors(primaryColor) {
  // 将主题色转换为 HSL
  const hsl = hexToHSL(primaryColor);
  
  return {
    primary: primaryColor,
    primaryContainer: hslToHex(hsl.h, Math.max(hsl.s - 20, 0), Math.min(hsl.l + 30, 95)),
    onPrimary: hsl.l > 50 ? '#000000' : '#ffffff',
    onPrimaryContainer: hslToHex(hsl.h, hsl.s, Math.max(hsl.l - 40, 10))
  };
}

Data Models

设置存储结构

// localStorage 存储的设置项
{
  'Argon_UI_Style': 'default' | 'glass' | 'neumorphism' | 'material3',
  'Argon_Animation_Reduced': 'true' | 'false',
  'Argon_Use_Serif': 'true' | 'false',
  'Argon_Use_Big_Shadow': 'true' | 'false',
  'Argon_Filter': 'off' | 'sunset' | 'darkness' | 'grayscale'
}

邮件模板设置结构

// WordPress 选项存储的邮件模板设置
[
  'argon_email_theme_color' => '#5e72e4',      // 主题色
  'argon_email_logo_url' => '',                 // Logo 图片 URL
  'argon_email_blog_name' => get_bloginfo('name'), // 博客名称
  'argon_email_footer_text' => '',              // 页脚版权信息
  'argon_email_social_links' => [               // 社交链接
    'twitter' => '',
    'github' => '',
    'weibo' => ''
  ]
]

7. 邮件模板系统设计

设计决策

  • 使用内联 CSS 确保邮件客户端兼容性(邮件客户端不支持外部样式表)
  • 采用表格布局保证跨客户端一致性Outlook 等客户端对 div 布局支持有限)
  • 提供简洁的后台设置界面,仅暴露必要的自定义选项

模板基础结构

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body style="margin: 0; padding: 0; background-color: #f4f5f7; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
  <table width="100%" cellpadding="0" cellspacing="0" style="background-color: #f4f5f7; padding: 40px 20px;">
    <tr>
      <td align="center">
        <table width="600" cellpadding="0" cellspacing="0" style="max-width: 600px; width: 100%;">
          <!-- 页眉 -->
          <tr>
            <td style="padding: 24px; text-align: center;">
              {{#if logo_url}}
              <img src="{{logo_url}}" alt="{{blog_name}}" style="max-height: 48px; max-width: 200px;">
              {{else}}
              <h1 style="margin: 0; font-size: 24px; color: {{theme_color}};">{{blog_name}}</h1>
              {{/if}}
            </td>
          </tr>
          
          <!-- 内容区 -->
          <tr>
            <td style="background: #ffffff; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.08);">
              <table width="100%" cellpadding="0" cellspacing="0">
                <tr>
                  <td style="padding: 32px;">
                    {{content}}
                  </td>
                </tr>
              </table>
            </td>
          </tr>
          
          <!-- 页脚 -->
          <tr>
            <td style="padding: 24px; text-align: center;">
              {{#if social_links}}
              <p style="margin: 0 0 12px 0;">
                {{#each social_links}}
                <a href="{{this.url}}" style="display: inline-block; margin: 0 8px; color: #8898aa; text-decoration: none;">{{this.name}}</a>
                {{/each}}
              </p>
              {{/if}}
              <p style="margin: 0; font-size: 12px; color: #8898aa;">
                {{footer_text}}
              </p>
            </td>
          </tr>
        </table>
      </td>
    </tr>
  </table>
</body>
</html>

评论通知邮件内容模板

<h2 style="margin: 0 0 16px 0; font-size: 20px; color: #32325d;">
  您的文章收到了新评论
</h2>
<p style="margin: 0 0 24px 0; color: #525f7f; line-height: 1.6;">
  <strong>{{commenter_name}}</strong> 在《<a href="{{post_url}}" style="color: {{theme_color}};">{{post_title}}</a>》中发表了评论:
</p>
<div style="background: #f6f9fc; border-left: 4px solid {{theme_color}}; padding: 16px; border-radius: 4px; margin: 0 0 24px 0;">
  <p style="margin: 0; color: #525f7f; line-height: 1.6;">{{comment_content}}</p>
</div>
<a href="{{comment_url}}" style="display: inline-block; background: {{theme_color}}; color: #ffffff; padding: 12px 24px; border-radius: 6px; text-decoration: none; font-weight: 500;">
  查看评论
</a>

评论回复通知邮件内容模板

<h2 style="margin: 0 0 16px 0; font-size: 20px; color: #32325d;">
  您的评论收到了回复
</h2>
<p style="margin: 0 0 16px 0; color: #8898aa; font-size: 14px;">
  您在《<a href="{{post_url}}" style="color: {{theme_color}};">{{post_title}}</a>》的评论:
</p>
<div style="background: #f6f9fc; padding: 12px 16px; border-radius: 4px; margin: 0 0 16px 0;">
  <p style="margin: 0; color: #8898aa; font-size: 14px;">{{original_comment}}</p>
</div>
<p style="margin: 0 0 16px 0; color: #525f7f;">
  <strong>{{replier_name}}</strong> 回复了您:
</p>
<div style="background: #f6f9fc; border-left: 4px solid {{theme_color}}; padding: 16px; border-radius: 4px; margin: 0 0 24px 0;">
  <p style="margin: 0; color: #525f7f; line-height: 1.6;">{{reply_content}}</p>
</div>
<a href="{{comment_url}}" style="display: inline-block; background: {{theme_color}}; color: #ffffff; padding: 12px 24px; border-radius: 6px; text-decoration: none; font-weight: 500;">
  查看回复
</a>

后台设置界面

// 邮件模板设置区域 - 添加到 settings.php
function argon_email_settings_section() {
  // 主题色选择器
  add_settings_field('argon_email_theme_color', '邮件主题色', ...);
  
  // Logo 上传
  add_settings_field('argon_email_logo_url', '邮件 Logo', ...);
  
  // 博客名称(默认使用站点名称)
  add_settings_field('argon_email_blog_name', '邮件显示名称', ...);
  
  // 页脚文本
  add_settings_field('argon_email_footer_text', '页脚版权信息', ...);
  
  // 社交链接
  add_settings_field('argon_email_social_links', '社交链接', ...);
  
  // 预览按钮
  add_settings_field('argon_email_preview', '邮件预览', ...);
}

邮件预览功能

// AJAX 预览邮件
function previewEmail(type) {
  fetch(ajaxurl, {
    method: 'POST',
    body: new URLSearchParams({
      action: 'argon_preview_email',
      type: type, // 'comment' | 'reply'
      nonce: argon_email_nonce
    })
  })
  .then(res => res.text())
  .then(html => {
    // 在模态框中显示预览
    openPreviewModal(html);
  });
}

PHP 邮件发送函数

/**
 * 发送统一格式的邮件
 * @param string $to 收件人
 * @param string $subject 主题
 * @param string $content 内容 HTML
 * @param string $type 邮件类型
 */
function argon_send_email($to, $subject, $content, $type = 'general') {
  $template = argon_get_email_template();
  $settings = argon_get_email_settings();
  
  // 替换模板变量
  $html = str_replace([
    '{{theme_color}}',
    '{{logo_url}}',
    '{{blog_name}}',
    '{{footer_text}}',
    '{{content}}'
  ], [
    $settings['theme_color'],
    $settings['logo_url'],
    $settings['blog_name'],
    $settings['footer_text'],
    $content
  ], $template);
  
  // 设置邮件头
  $headers = [
    'Content-Type: text/html; charset=UTF-8',
    'From: ' . $settings['blog_name'] . ' <' . get_option('admin_email') . '>'
  ];
  
  return wp_mail($to, $subject, $html, $headers);
}

Correctness Properties

A property is a characteristic or behavior that should hold true across all valid executions of a system—essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.

Property 1: 按钮使用纯色背景

For any 主要按钮元素(.btn-primary, #share .btn, #comments_toggle其 background 属性应该使用纯色var(--themecolor) 或具体颜色值),而不包含 gradient 关键字。

Validates: Requirements 1.1, 3.6

Property 2: 组件使用主题色 CSS 变量

For any 使用主题色的组件(按钮、选中状态、链接等),其颜色相关属性应该使用 var(--themecolor) 或其派生变量(--themecolor-dark, --themecolor-light 等),而非硬编码的颜色值。

Validates: Requirements 1.4, 2.3

Property 3: 动画系统 CSS 变量定义

For any 动画相关的 CSS 变量,:root 选择器中应该定义 --animation-fast, --animation-normal, --animation-slow 时长变量,以及 --ease-standard, --ease-emphasized, --ease-spring 等缓动函数变量。

Validates: Requirements 5.1, 5.2

Property 4: 分享按钮错落动画延迟

For any 分享按钮容器中的子元素(#share > a每个元素应该有递增的 transition-delay 值,形成错落有致的动画效果。

Validates: Requirements 3.2

Property 5: 评论区过渡动画属性

For any 评论区容器(#comments, #post_comment其 transition 属性应该包含 max-height 和 opacity并使用 CSS 变量定义的动画时长。

Validates: Requirements 4.1, 4.2, 4.4

Property 6: GPU 加速动画属性

For any 交互动画(悬停、点击、展开/收起),应该主要使用 transform 和 opacity 属性进行动画,而非 width, height, top, left 等触发重排的属性。

Validates: Requirements 5.3

Property 7: 样式切换过渡动画

For any 主要容器元素(.card, #fabtn_blog_settings_popup应该定义 transition 属性覆盖 background-color 和 box-shadow 的变化,以支持样式切换时的平滑过渡。

Validates: Requirements 6.4

Property 8: 点击外部收起分享面板

For any 处于展开状态的分享面板,当用户点击分享容器外部区域时,分享面板应该收起(移除 .opened 类)。

Validates: Requirements 3.5

Property 9: 悬停效果使用 transform 和 box-shadow

For any 可交互元素(.card, .btn的悬停状态应该使用 transform如 translateY 或 scale和 box-shadow 属性实现视觉反馈,而非改变元素尺寸或位置属性。

Validates: Requirements 5.5

Property 10: Material 3 色彩变量定义

For any 启用 Material 3 样式的页面,:root 选择器中应该定义 --md-primary, --md-surface, --md-on-primary 等 Material 3 色彩角色变量。

Validates: Requirements 6.3

Property 11: 邮件模板统一结构

For any 发送的邮件(评论通知、回复通知等),其 HTML 结构应该包含页眉logo/博客名)、内容区、页脚(版权信息)三个区域,且使用相同的基础模板。

Validates: Requirements 7.1

Property 12: 邮件模板主题色应用

For any 邮件模板中的主题色元素(按钮背景、链接颜色、边框强调色),应该使用后台设置的 argon_email_theme_color 值,而非硬编码颜色。

Validates: Requirements 7.2

Property 13: 邮件模板内联样式

For any 邮件模板的 HTML 输出所有样式应该以内联方式style 属性)应用,不依赖外部 CSS 文件或 <style> 标签,以确保邮件客户端兼容性。

Validates: Requirements 7.7

Error Handling

CSS 兼容性处理

  1. backdrop-filter 不支持时的降级

    • 使用 @supports 查询检测支持情况
    • 降级为纯色背景加透明度
  2. CSS 变量不支持时的降级

    • 在变量值前提供硬编码的回退值
    • 示例:transition: all 250ms ease; transition: all var(--animation-normal) var(--ease-standard);
  3. prefers-reduced-motion 处理

    • 检测用户偏好减少动画
    • 将所有动画时长设为 0 或极短值

JavaScript 错误处理

  1. localStorage 不可用

    • 使用 try-catch 包装存储操作
    • 降级为内存存储或 cookie
  2. 动画 API 不支持

    • 检测 Web Animations API 支持
    • 降级为 CSS transition

邮件发送错误处理

  1. wp_mail 发送失败

    • 记录错误日志
    • 返回友好的错误提示
  2. 模板变量缺失

    • 提供默认值回退
    • 使用站点名称作为博客名称默认值
    • 使用主题色作为邮件主题色默认值
  3. 图片加载失败

    • Logo 图片加载失败时显示文字博客名称
    • 使用 alt 属性提供替代文本

Testing Strategy

单元测试

  1. CSS 变量定义测试

    • 验证所有必需的 CSS 变量已定义
    • 验证变量值格式正确
  2. 样式类存在性测试

    • 验证 .style-glass, .style-neumorphism 等类已定义
    • 验证 .segmented-control 组件样式已定义
  3. JavaScript 功能测试

    • 验证样式切换函数正确更新 localStorage
    • 验证分享按钮展开/收起逻辑

属性测试

由于本功能主要涉及 CSS 样式和视觉效果,属性测试将通过以下方式进行:

  1. CSS 解析验证

    • 解析 style.css 文件
    • 验证按钮背景不包含 gradient
    • 验证动画属性使用 CSS 变量
  2. DOM 结构验证

    • 验证分享按钮子元素具有递增的 transition-delay
    • 验证评论区容器具有正确的 transition 属性

视觉回归测试(可选)

  1. 使用截图对比工具验证样式变更
  2. 在不同浏览器中验证兼容性

邮件模板测试

  1. 模板渲染测试

    • 验证所有模板变量正确替换
    • 验证 HTML 结构完整性
  2. 邮件客户端兼容性测试

    • 在 Gmail Web 端验证显示效果
    • 在 Outlook 验证表格布局
    • 在 Apple Mail 验证样式渲染
  3. 设置功能测试

    • 验证主题色修改后邮件颜色更新
    • 验证 Logo 上传和显示
    • 验证预览功能正确渲染当前设置