tailwindcss-responsive-darkmode

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Tailwind CSS Responsive Design & Dark Mode (2025/2026)

Tailwind CSS 响应式设计与深色模式(2025/2026)

Responsive Design

响应式设计

Mobile-First Approach (Industry Standard 2025/2026)

移动端优先方案(2025/2026行业标准)

Tailwind uses a mobile-first breakpoint system. With over 60% of global web traffic from mobile devices and Google's mobile-first indexing, this approach is essential.
Key Principle: Unprefixed utilities apply to ALL screen sizes. Breakpoint prefixes apply at that size AND ABOVE.
html
<!-- CORRECT: Mobile-first (progressive enhancement) -->
<div class="text-sm md:text-base lg:text-lg">...</div>

<!-- INCORRECT: Desktop-first thinking -->
<div class="lg:text-lg md:text-base text-sm">...</div>
Tailwind采用移动端优先的断点系统。鉴于全球超过60%的网络流量来自移动设备,且谷歌采用移动端优先索引,这种方案至关重要。
核心原则:无前缀的工具类适用于所有屏幕尺寸。断点前缀仅在对应尺寸及以上生效。
html
<!-- 正确:移动端优先(渐进式增强) -->
<div class="text-sm md:text-base lg:text-lg">...</div>

<!-- 错误:桌面端优先思路 -->
<div class="lg:text-lg md:text-base text-sm">...</div>

Default Breakpoints

默认断点

PrefixMin WidthTypical DevicesCSS Media Query
(none)0pxAll mobile phonesAll sizes
sm:
640px (40rem)Large phones, small tablets
@media (min-width: 640px)
md:
768px (48rem)Tablets (portrait)
@media (min-width: 768px)
lg:
1024px (64rem)Tablets (landscape), laptops
@media (min-width: 1024px)
xl:
1280px (80rem)Desktops
@media (min-width: 1280px)
2xl:
1536px (96rem)Large desktops
@media (min-width: 1536px)
前缀最小宽度典型设备CSS媒体查询
(无)0px所有移动手机全尺寸
sm:
640px(40rem)大屏手机、小尺寸平板
@media (min-width: 640px)
md:
768px(48rem)平板(竖屏)
@media (min-width: 768px)
lg:
1024px(64rem)平板(横屏)、笔记本电脑
@media (min-width: 1024px)
xl:
1280px(80rem)台式机
@media (min-width: 1280px)
2xl:
1536px(96rem)大尺寸台式机
@media (min-width: 1536px)

2025/2026 Device Coverage

2025/2026设备覆盖范围

Common device sizes to test:
  • 320px: Older iPhones, smallest supported
  • 375px: Modern iPhone base (~17% of mobile)
  • 390-430px: Modern large phones (~35% of mobile)
  • 768px: iPad portrait
  • 1024px: iPad landscape, laptops
  • 1280px: Standard laptops/desktops
  • 1440px: Large desktops
  • 1920px: Full HD displays
需要测试的常见设备尺寸:
  • 320px:旧款iPhone,支持的最小尺寸
  • 375px:现代基础款iPhone(约占移动设备的17%)
  • 390-430px:现代大屏手机(约占移动设备的35%)
  • 768px:iPad竖屏
  • 1024px:iPad横屏、笔记本电脑
  • 1280px:标准笔记本/台式机
  • 1440px:大尺寸台式机
  • 1920px:全高清显示器

Custom Breakpoints

自定义断点

css
@theme {
  /* Add custom breakpoints for specific content needs */
  --breakpoint-xs: 20rem;   /* 320px - very small devices */
  --breakpoint-3xl: 100rem; /* 1600px */
  --breakpoint-4xl: 120rem; /* 1920px - full HD */

  /* Override existing breakpoints based on YOUR content */
  --breakpoint-sm: 36rem;   /* 576px - when content needs space */
  --breakpoint-lg: 62rem;   /* 992px - common content width */
}
Usage:
html
<div class="grid xs:grid-cols-2 3xl:grid-cols-6">
  <!-- Custom breakpoints work like built-in ones -->
</div>
css
@theme {
  /* 根据特定内容需求添加自定义断点 */
  --breakpoint-xs: 20rem;   /* 320px - 极小尺寸设备 */
  --breakpoint-3xl: 100rem; /* 1600px */
  --breakpoint-4xl: 120rem; /* 1920px - 全高清 */

  /* 根据你的内容需求覆盖现有断点 */
  --breakpoint-sm: 36rem;   /* 576px - 当内容需要更多空间时 */
  --breakpoint-lg: 62rem;   /* 992px - 常见内容宽度 */
}
使用方式:
html
<div class="grid xs:grid-cols-2 3xl:grid-cols-6">
  <!-- 自定义断点的使用方式与内置断点一致 -->
</div>

Content-Driven Breakpoints (2025 Best Practice)

内容驱动型断点(2025最佳实践)

Instead of targeting devices, let your content determine breakpoints:
css
@theme {
  /* Based on content needs, not device specs */
  --breakpoint-prose: 65ch;  /* Optimal reading width */
  --breakpoint-content: 75rem; /* Main content max */
}
Test your design at various widths and add breakpoints where layout breaks.
不要针对设备,而是让内容决定断点:
css
@theme {
  /* 基于内容需求,而非设备规格 */
  --breakpoint-prose: 65ch;  /* 最佳阅读宽度 */
  --breakpoint-content: 75rem; /* 主内容最大宽度 */
}
在不同宽度下测试你的设计,在布局出现问题的位置添加断点。

Responsive Examples

响应式示例

Responsive Grid

响应式网格

html
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
  <div>Item 4</div>
</div>
html
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
  <div>Item 4</div>
</div>

Responsive Typography

响应式排版

html
<h1 class="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold">
  Responsive Heading
</h1>

<p class="text-sm md:text-base lg:text-lg leading-relaxed">
  Responsive paragraph text
</p>
html
<h1 class="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold">
  响应式标题
</h1>

<p class="text-sm md:text-base lg:text-lg leading-relaxed">
  响应式段落文本
</p>

Responsive Spacing

响应式间距

html
<section class="py-8 md:py-12 lg:py-16 px-4 md:px-8 lg:px-12">
  <div class="max-w-4xl mx-auto">
    Content with responsive padding
  </div>
</section>
html
<section class="py-8 md:py-12 lg:py-16 px-4 md:px-8 lg:px-12">
  <div class="max-w-4xl mx-auto">
    带响应式内边距的内容
  </div>
</section>

Responsive Navigation

响应式导航

html
<nav class="flex flex-col md:flex-row items-center justify-between">
  <div class="hidden md:flex gap-4">
    <!-- Desktop navigation -->
  </div>
  <button class="md:hidden">
    <!-- Mobile menu button -->
  </button>
</nav>
html
<nav class="flex flex-col md:flex-row items-center justify-between">
  <div class="hidden md:flex gap-4">
    <!-- 桌面端导航 -->
  </div>
  <button class="md:hidden">
    <!-- 移动端菜单按钮 -->
  </button>
</nav>

Show/Hide Based on Screen Size

根据屏幕尺寸显示/隐藏内容

html
<!-- Hidden on mobile, visible on desktop -->
<div class="hidden md:block">Desktop only</div>

<!-- Visible on mobile, hidden on desktop -->
<div class="block md:hidden">Mobile only</div>

<!-- Different content per breakpoint -->
<span class="sm:hidden">XS</span>
<span class="hidden sm:inline md:hidden">SM</span>
<span class="hidden md:inline lg:hidden">MD</span>
<span class="hidden lg:inline xl:hidden">LG</span>
<span class="hidden xl:inline 2xl:hidden">XL</span>
<span class="hidden 2xl:inline">2XL</span>
html
<!-- 移动端隐藏,桌面端显示 -->
<div class="hidden md:block">仅桌面端可见</div>

<!-- 移动端显示,桌面端隐藏 -->
<div class="block md:hidden">仅移动端可见</div>

<!-- 不同断点显示不同内容 -->
<span class="sm:hidden">XS</span>
<span class="hidden sm:inline md:hidden">SM</span>
<span class="hidden md:inline lg:hidden">MD</span>
<span class="hidden lg:inline xl:hidden">LG</span>
<span class="hidden xl:inline 2xl:hidden">XL</span>
<span class="hidden 2xl:inline">2XL</span>

Container Queries (v4) - 2025 Game-Changer

容器查询(v4)- 2025年突破性功能

Container queries enable component-level responsiveness, independent of viewport size. This is essential for reusable components in 2025.
css
@plugin "@tailwindcss/container-queries";
html
<!-- Mark parent as a query container -->
<div class="@container">
  <div class="flex flex-col @md:flex-row @lg:gap-8">
    <!-- Responds to container size, not viewport -->
  </div>
</div>

<!-- Named containers for multiple contexts -->
<div class="@container/card">
  <div class="@lg/card:grid-cols-2 grid grid-cols-1">
    <!-- Responds specifically to 'card' container -->
  </div>
</div>
容器查询支持组件级别的响应式,独立于视口尺寸。这在2025年对于可复用组件至关重要。
css
@plugin "@tailwindcss/container-queries";
html
<!-- 将父元素标记为查询容器 -->
<div class="@container">
  <div class="flex flex-col @md:flex-row @lg:gap-8">
    <!-- 响应容器尺寸,而非视口尺寸 -->
  </div>
</div>

<!-- 命名容器以支持多上下文 -->
<div class="@container/card">
  <div class="@lg/card:grid-cols-2 grid grid-cols-1">
    <!-- 专门响应'card'容器的尺寸 -->
  </div>
</div>

Container Query Breakpoints

容器查询断点

ClassMin-widthUse Case
@xs
20rem (320px)Small widgets
@sm
24rem (384px)Compact cards
@md
28rem (448px)Standard cards
@lg
32rem (512px)Wide cards
@xl
36rem (576px)Full-width components
@2xl
42rem (672px)Large containers
@3xl
48rem (768px)Page sections
类名最小宽度使用场景
@xs
20rem(320px)小组件
@sm
24rem(384px)紧凑卡片
@md
28rem(448px)标准卡片
@lg
32rem(512px)宽卡片
@xl
36rem(576px)全宽组件
@2xl
42rem(672px)大容器
@3xl
48rem(768px)页面区块

When to Use Container vs Viewport Queries

何时使用容器查询 vs 视口查询

Container QueriesViewport Queries
Reusable componentsPage-level layouts
Cards in various contextsNavigation bars
Sidebar widgetsHero sections
CMS/embedded contentFull-width sections
容器查询视口查询
可复用组件页面级布局
多上下文卡片导航栏
侧边栏组件Hero区块
CMS/嵌入式内容全宽区块

Max-Width Breakpoints

最大宽度断点

Target screens below a certain size:
html
<!-- Only on screens smaller than md (< 768px) -->
<div class="md:hidden">Small screens only</div>

<!-- Custom max-width media query -->
<div class="[@media(max-width:600px)]:text-sm">
  Custom max-width
</div>
针对小于特定尺寸的屏幕:
html
<!-- 仅在小于md尺寸的屏幕上生效(<768px) -->
<div class="md:hidden">仅小屏幕可见</div>

<!-- 自定义最大宽度媒体查询 -->
<div class="[@media(max-width:600px)]:text-sm">
  自定义最大宽度
</div>

Dark Mode

深色模式

Strategy: Media (Default)

策略:媒体查询(默认)

Dark mode follows the user's operating system preference using
prefers-color-scheme
:
css
@import "tailwindcss";
/* No additional configuration needed */
html
<div class="bg-white dark:bg-gray-900">
  <h1 class="text-gray-900 dark:text-white">Title</h1>
  <p class="text-gray-600 dark:text-gray-300">Content</p>
</div>
深色模式通过
prefers-color-scheme
跟随用户的操作系统偏好:
css
@import "tailwindcss";
/* 无需额外配置 */
html
<div class="bg-white dark:bg-gray-900">
  <h1 class="text-gray-900 dark:text-white">标题</h1>
  <p class="text-gray-600 dark:text-gray-300">内容</p>
</div>

Strategy: Selector (Manual Toggle)

策略:选择器(手动切换)

Control dark mode with a CSS class:
css
@import "tailwindcss";

@custom-variant dark (&:where(.dark, .dark *));
html
<!-- Add .dark class to html or body to enable dark mode -->
<html class="dark">
  <body>
    <div class="bg-white dark:bg-gray-900">
      Content
    </div>
  </body>
</html>
通过CSS类控制深色模式:
css
@import "tailwindcss";

@custom-variant dark (&:where(.dark, .dark *));
html
<!-- 为html或body添加.dark类以启用深色模式 -->
<html class="dark">
  <body>
    <div class="bg-white dark:bg-gray-900">
      内容
    </div>
  </body>
</html>

JavaScript Toggle

JavaScript切换

javascript
// Simple toggle
function toggleDarkMode() {
  document.documentElement.classList.toggle('dark');
}

// With localStorage persistence
function initDarkMode() {
  const isDark = localStorage.getItem('darkMode') === 'true' ||
    (!localStorage.getItem('darkMode') &&
     window.matchMedia('(prefers-color-scheme: dark)').matches);

  document.documentElement.classList.toggle('dark', isDark);
}

function toggleDarkMode() {
  const isDark = document.documentElement.classList.toggle('dark');
  localStorage.setItem('darkMode', isDark);
}

// Initialize on page load
initDarkMode();
javascript
// 简单切换
function toggleDarkMode() {
  document.documentElement.classList.toggle('dark');
}

// 结合localStorage持久化
function initDarkMode() {
  const isDark = localStorage.getItem('darkMode') === 'true' ||
    (!localStorage.getItem('darkMode') &&
     window.matchMedia('(prefers-color-scheme: dark)').matches);

  document.documentElement.classList.toggle('dark', isDark);
}

function toggleDarkMode() {
  const isDark = document.documentElement.classList.toggle('dark');
  localStorage.setItem('darkMode', isDark);
}

// 页面加载时初始化
initDarkMode();

Three-Way Toggle (Light/Dark/System)

三态切换(亮色/深色/系统)

javascript
const themes = ['light', 'dark', 'system'];

function setTheme(theme) {
  localStorage.setItem('theme', theme);
  applyTheme();
}

function applyTheme() {
  const theme = localStorage.getItem('theme') || 'system';
  const isDark = theme === 'dark' ||
    (theme === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches);

  document.documentElement.classList.toggle('dark', isDark);
}

// Listen for system preference changes
window.matchMedia('(prefers-color-scheme: dark)')
  .addEventListener('change', () => {
    if (localStorage.getItem('theme') === 'system') {
      applyTheme();
    }
  });

applyTheme();
javascript
const themes = ['light', 'dark', 'system'];

function setTheme(theme) {
  localStorage.setItem('theme', theme);
  applyTheme();
}

function applyTheme() {
  const theme = localStorage.getItem('theme') || 'system';
  const isDark = theme === 'dark' ||
    (theme === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches);

  document.documentElement.classList.toggle('dark', isDark);
}

// 监听系统偏好变化
window.matchMedia('(prefers-color-scheme: dark)')
  .addEventListener('change', () => {
    if (localStorage.getItem('theme') === 'system') {
      applyTheme();
    }
  });

applyTheme();

Data Attribute Strategy

数据属性策略

css
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
html
<html data-theme="dark">
  <body>
    <div class="bg-white dark:bg-gray-900">Content</div>
  </body>
</html>
css
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
html
<html data-theme="dark">
  <body>
    <div class="bg-white dark:bg-gray-900">内容</div>
  </body>
</html>

Dark Mode with Next.js (next-themes)

Next.js中的深色模式(next-themes)

bash
npm install next-themes
jsx
// app/providers.tsx
'use client';

import { ThemeProvider } from 'next-themes';

export function Providers({ children }) {
  return (
    <ThemeProvider attribute="class" defaultTheme="system">
      {children}
    </ThemeProvider>
  );
}
jsx
// app/layout.tsx
import { Providers } from './providers';

export default function RootLayout({ children }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}
jsx
// components/ThemeToggle.tsx
'use client';

import { useTheme } from 'next-themes';

export function ThemeToggle() {
  const { theme, setTheme } = useTheme();

  return (
    <button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
      Toggle Theme
    </button>
  );
}
bash
npm install next-themes
jsx
// app/providers.tsx
'use client';

import { ThemeProvider } from 'next-themes';

export function Providers({ children }) {
  return (
    <ThemeProvider attribute="class" defaultTheme="system">
      {children}
    </ThemeProvider>
  );
}
jsx
// app/layout.tsx
import { Providers } from './providers';

export default function RootLayout({ children }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}
jsx
// components/ThemeToggle.tsx
'use client';

import { useTheme } from 'next-themes';

export function ThemeToggle() {
  const { theme, setTheme } = useTheme();

  return (
    <button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
      切换主题
    </button>
  );
}

Dark Mode Color Palette

深色模式调色板

html
<!-- Text colors -->
<p class="text-gray-900 dark:text-gray-100">Primary text</p>
<p class="text-gray-600 dark:text-gray-400">Secondary text</p>
<p class="text-gray-400 dark:text-gray-500">Muted text</p>

<!-- Background colors -->
<div class="bg-white dark:bg-gray-900">Page background</div>
<div class="bg-gray-50 dark:bg-gray-800">Card background</div>
<div class="bg-gray-100 dark:bg-gray-700">Elevated background</div>

<!-- Border colors -->
<div class="border border-gray-200 dark:border-gray-700">Bordered element</div>

<!-- Interactive elements -->
<button class="bg-blue-500 hover:bg-blue-600 dark:bg-blue-600 dark:hover:bg-blue-700">
  Button
</button>
html
<!-- 文本颜色 -->
<p class="text-gray-900 dark:text-gray-100">主文本</p>
<p class="text-gray-600 dark:text-gray-400">次要文本</p>
<p class="text-gray-400 dark:text-gray-500">弱化文本</p>

<!-- 背景颜色 -->
<div class="bg-white dark:bg-gray-900">页面背景</div>
<div class="bg-gray-50 dark:bg-gray-800">卡片背景</div>
<div class="bg-gray-100 dark:bg-gray-700">高亮背景</div>

<!-- 边框颜色 -->
<div class="border border-gray-200 dark:border-gray-700">带边框元素</div>

<!-- 交互元素 -->
<button class="bg-blue-500 hover:bg-blue-600 dark:bg-blue-600 dark:hover:bg-blue-700">
  按钮
</button>

Dark Mode with CSS Variables

结合CSS变量的深色模式

css
@theme {
  /* Light mode colors (default) */
  --color-bg-primary: oklch(1 0 0);
  --color-bg-secondary: oklch(0.98 0 0);
  --color-text-primary: oklch(0.15 0 0);
  --color-text-secondary: oklch(0.4 0 0);
}

/* Dark mode overrides */
@media (prefers-color-scheme: dark) {
  :root {
    --color-bg-primary: oklch(0.15 0 0);
    --color-bg-secondary: oklch(0.2 0 0);
    --color-text-primary: oklch(0.95 0 0);
    --color-text-secondary: oklch(0.7 0 0);
  }
}
html
<div class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]">
  Semantic colors
</div>
css
@theme {
  /* 亮色模式颜色(默认) */
  --color-bg-primary: oklch(1 0 0);
  --color-bg-secondary: oklch(0.98 0 0);
  --color-text-primary: oklch(0.15 0 0);
  --color-text-secondary: oklch(0.4 0 0);
}

/* 深色模式覆盖 */
@media (prefers-color-scheme: dark) {
  :root {
    --color-bg-primary: oklch(0.15 0 0);
    --color-bg-secondary: oklch(0.2 0 0);
    --color-text-primary: oklch(0.95 0 0);
    --color-text-secondary: oklch(0.7 0 0);
  }
}
html
<div class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]">
  语义化颜色
</div>

Typography Plugin Dark Mode

Typography插件深色模式

html
<article class="prose dark:prose-invert">
  <!-- Markdown content automatically adapts to dark mode -->
</article>
html
<article class="prose dark:prose-invert">
  <!-- Markdown内容自动适配深色模式 -->
</article>

Combining Responsive and Dark Mode

结合响应式与深色模式

html
<!-- Different layouts AND colors based on screen size and theme -->
<div class="
  grid grid-cols-1 md:grid-cols-2
  bg-white dark:bg-gray-900
  p-4 md:p-8
  text-gray-900 dark:text-white
">
  <div class="hidden dark:md:block">
    Only visible on md+ screens in dark mode
  </div>
</div>
html
<!-- 根据屏幕尺寸和主题应用不同布局和颜色 -->
<div class="
  grid grid-cols-1 md:grid-cols-2
  bg-white dark:bg-gray-900
  p-4 md:p-8
  text-gray-900 dark:text-white
">
  <div class="hidden dark:md:block">
    仅在深色模式下的md及以上屏幕可见
  </div>
</div>

Best Practices (2025/2026)

最佳实践(2025/2026)

1. Start Mobile, Then Enhance

1. 从移动端开始,逐步增强

html
<!-- CORRECT: Mobile-first progression -->
<div class="text-sm md:text-base lg:text-lg">

<!-- WRONG: Desktop-first thinking (more code, more bugs) -->
<div class="lg:text-lg md:text-base text-sm">
html
<!-- 正确:移动端优先渐进式增强 -->
<div class="text-sm md:text-base lg:text-lg">

<!-- 错误:桌面端优先思路(代码更多,bug更多) -->
<div class="lg:text-lg md:text-base text-sm">

2. Touch-Friendly Interactive Elements

2. 触控友好的交互元素

WCAG 2.2 requires 24x24px minimum, but 44x44px is recommended:
html
<!-- Touch-friendly button (44px minimum) -->
<button class="min-h-11 min-w-11 px-4 py-2.5">
  Click me
</button>

<!-- Touch-friendly navigation link -->
<a href="#" class="block py-3 px-4 min-h-11">
  Navigation Item
</a>

<!-- Adequate spacing between touch targets -->
<div class="flex gap-3">
  <button class="min-h-11 px-4 py-2">Button 1</button>
  <button class="min-h-11 px-4 py-2">Button 2</button>
</div>
WCAG 2.2要求最小24x24px,推荐44x44px:
html
<!-- 触控友好的按钮(最小44px) -->
<button class="min-h-11 min-w-11 px-4 py-2.5">
  点击我
</button>

<!-- 触控友好的导航链接 -->
<a href="#" class="block py-3 px-4 min-h-11">
  导航项
</a>

<!-- 触控目标间的足够间距 -->
<div class="flex gap-3">
  <button class="min-h-11 px-4 py-2">按钮1</button>
  <button class="min-h-11 px-4 py-2">按钮2</button>
</div>

3. Fluid Typography (Eliminates Breakpoint Jumps)

3. 流体排版(消除断点跳跃)

css
@theme {
  --text-fluid-base: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
  --text-fluid-lg: clamp(1.25rem, 1rem + 1.25vw, 2rem);
  --text-fluid-xl: clamp(1.5rem, 1rem + 2.5vw, 3rem);
}
html
<h1 class="text-fluid-xl font-bold">Smoothly Scaling Heading</h1>
<p class="text-fluid-base leading-relaxed">Smoothly scaling body text.</p>
css
@theme {
  --text-fluid-base: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
  --text-fluid-lg: clamp(1.25rem, 1rem + 1.25vw, 2rem);
  --text-fluid-xl: clamp(1.5rem, 1rem + 2.5vw, 3rem);
}
html
<h1 class="text-fluid-xl font-bold">平滑缩放标题</h1>
<p class="text-fluid-base leading-relaxed">平滑缩放正文文本。</p>

2. Use Semantic Dark Mode Colors

2. 使用语义化深色模式颜色

css
@theme {
  /* Instead of raw colors, use semantic names */
  --color-surface: oklch(1 0 0);
  --color-surface-dark: oklch(0.15 0 0);
  --color-on-surface: oklch(0.1 0 0);
  --color-on-surface-dark: oklch(0.95 0 0);
}
css
@theme {
  /* 不要使用原始颜色,使用语义化名称 */
  --color-surface: oklch(1 0 0);
  --color-surface-dark: oklch(0.15 0 0);
  --color-on-surface: oklch(0.1 0 0);
  --color-on-surface-dark: oklch(0.95 0 0);
}

3. Test All Breakpoints

3. 测试所有断点

Use the debug-screens plugin during development:
bash
npm install -D @tailwindcss/debug-screens
css
@plugin "@tailwindcss/debug-screens";
开发期间使用debug-screens插件:
bash
npm install -D @tailwindcss/debug-screens
css
@plugin "@tailwindcss/debug-screens";

4. Reduce Repetition with Components

4. 使用组件减少重复

css
/* components.css */
@layer components {
  .card {
    @apply bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm;
  }

  .section {
    @apply py-12 md:py-16 lg:py-24;
  }
}
css
/* components.css */
@layer components {
  .card {
    @apply bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm;
  }

  .section {
    @apply py-12 md:py-16 lg:py-24;
  }
}

5. Consider Color Contrast

5. 考虑颜色对比度

Ensure sufficient contrast in both light and dark modes (WCAG 2.2):
  • Normal text: 4.5:1 contrast ratio minimum
  • Large text (18pt+): 3:1 contrast ratio minimum
  • Interactive elements: 3:1 against adjacent colors
html
<!-- Good contrast in both modes -->
<button class="
  bg-blue-600 text-white
  dark:bg-blue-500 dark:text-white
  hover:bg-blue-700 dark:hover:bg-blue-400
  /* Focus ring for accessibility */
  focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2
">
  Action
</button>
确保亮色和深色模式下都有足够的对比度(WCAG 2.2):
  • 普通文本:最小4.5:1对比度
  • 大文本(18pt+):最小3:1对比度
  • 交互元素:与相邻颜色的对比度至少3:1
html
<!-- 两种模式下都有良好对比度 -->
<button class="
  bg-blue-600 text-white
  dark:bg-blue-500 dark:text-white
  hover:bg-blue-700 dark:hover:bg-blue-400
  /* 可访问性聚焦环 */
  focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2
">
  操作
</button>

6. Reduced Motion Preference

6. 尊重减少动画偏好

Respect users who prefer reduced motion:
html
<div class="
  transition-transform duration-300
  hover:scale-105
  motion-reduce:transition-none
  motion-reduce:hover:scale-100
">
  Respects motion preferences
</div>
尊重偏好减少动画的用户:
html
<div class="
  transition-transform duration-300
  hover:scale-105
  motion-reduce:transition-none
  motion-reduce:hover:scale-100
">
  尊重动画偏好
</div>

7. Performance-Optimized Responsive Images

7. 性能优化的响应式图片

html
<!-- Lazy load below-fold images -->
<img
  src="image.jpg"
  alt="Description"
  loading="lazy"
  class="w-full h-auto"
/>

<!-- Responsive srcset -->
<img
  src="medium.jpg"
  srcset="small.jpg 400w, medium.jpg 800w, large.jpg 1200w"
  sizes="(min-width: 1024px) 50vw, 100vw"
  alt="Responsive image"
  loading="lazy"
  class="w-full h-auto"
/>
html
<!-- 懒加载视口外图片 -->
<img
  src="image.jpg"
  alt="描述"
  loading="lazy"
  class="w-full h-auto"
/>

<!-- 响应式srcset -->
<img
  src="medium.jpg"
  srcset="small.jpg 400w, medium.jpg 800w, large.jpg 1200w"
  sizes="(min-width: 1024px) 50vw, 100vw"
  alt="响应式图片"
  loading="lazy"
  class="w-full h-auto"
/>

8. Safe Area Handling (Notched Devices)

8. 安全区域处理(带刘海的设备)

css
@utility safe-area-pb {
  padding-bottom: env(safe-area-inset-bottom);
}
html
<!-- Bottom navigation respects device notch -->
<nav class="fixed bottom-0 inset-x-0 safe-area-pb bg-white border-t">
  Navigation
</nav>
css
@utility safe-area-pb {
  padding-bottom: env(safe-area-inset-bottom);
}
html
<!-- 底部导航适配设备刘海 -->
<nav class="fixed bottom-0 inset-x-0 safe-area-pb bg-white border-t">
  导航
</nav>