tailwindcss-responsive-darkmode by josiahsiegel/claude-plugin-marketplace
npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill tailwindcss-responsive-darkmodeTailwind 采用移动优先的断点系统。鉴于全球超过 60% 的网络流量来自移动设备,以及谷歌的移动优先索引策略,这种方法至关重要。
核心原则:未添加前缀的实用类适用于所有屏幕尺寸。断点前缀则在该尺寸及以上生效。
<!-- 正确:移动优先(渐进增强) -->
<div class="text-sm md:text-base lg:text-lg">...</div>
<!-- 错误:桌面优先思维 -->
<div class="lg:text-lg md:text-base text-sm">...</div>
| 前缀 | 最小宽度 | 典型设备 | CSS 媒体查询 |
|---|---|---|---|
| (无) | 0px | 所有手机 | 所有尺寸 |
sm: | 640px (40rem) | 大屏手机、小平板 | @media (min-width: 640px) |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
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) |
需要测试的常见设备尺寸:
@theme {
/* 为特定内容需求添加自定义断点 */
--breakpoint-xs: 20rem; /* 320px - 非常小的设备 */
--breakpoint-3xl: 100rem; /* 1600px */
--breakpoint-4xl: 120rem; /* 1920px - 全高清 */
/* 根据您的内容覆盖现有断点 */
--breakpoint-sm: 36rem; /* 576px - 当内容需要空间时 */
--breakpoint-lg: 62rem; /* 992px - 常见内容宽度 */
}
用法:
<div class="grid xs:grid-cols-2 3xl:grid-cols-6">
<!-- 自定义断点的工作方式与内置断点相同 -->
</div>
不要以设备为目标,而应让您的内容决定断点:
@theme {
/* 基于内容需求,而非设备规格 */
--breakpoint-prose: 65ch; /* 最佳阅读宽度 */
--breakpoint-content: 75rem; /* 主要内容最大宽度 */
}
在不同宽度下测试您的设计,并在布局断裂处添加断点。
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
<div>项目 1</div>
<div>项目 2</div>
<div>项目 3</div>
<div>项目 4</div>
</div>
<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>
<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>
<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>
<!-- 在移动端隐藏,在桌面端显示 -->
<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>
容器查询支持组件级别的响应式设计,独立于视口尺寸。这对于 2025 年的可复用组件至关重要。
@plugin "@tailwindcss/container-queries";
<!-- 将父元素标记为查询容器 -->
<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>
| 类 | 最小宽度 | 使用场景 |
|---|---|---|
@xs | 20rem (320px) | 小组件 |
@sm | 24rem (384px) | 紧凑卡片 |
@md | 28rem (448px) | 标准卡片 |
@lg | 32rem (512px) | 宽卡片 |
@xl | 36rem (576px) | 全宽组件 |
@2xl | 42rem (672px) | 大容器 |
@3xl | 48rem (768px) | 页面区域 |
| 容器查询 | 视口查询 |
|---|---|
| 可复用组件 | 页面级布局 |
| 不同上下文中的卡片 | 导航栏 |
| 侧边栏小组件 | 英雄区域 |
| CMS/嵌入式内容 | 全宽区域 |
针对小于特定尺寸的屏幕:
<!-- 仅在小屏幕(小于 md < 768px)上显示 -->
<div class="md:hidden">仅小屏幕</div>
<!-- 自定义最大宽度媒体查询 -->
<div class="[@media(max-width:600px)]:text-sm">
自定义最大宽度
</div>
深色模式遵循用户操作系统偏好,使用 prefers-color-scheme:
@import "tailwindcss";
/* 无需额外配置 */
<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>
通过 CSS 类控制深色模式:
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
<!-- 向 html 或 body 添加 .dark 类以启用深色模式 -->
<html class="dark">
<body>
<div class="bg-white dark:bg-gray-900">
内容
</div>
</body>
</html>
// 简单切换
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();
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();
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
<html data-theme="dark">
<body>
<div class="bg-white dark:bg-gray-900">内容</div>
</body>
</html>
npm install next-themes
// app/providers.tsx
'use client';
import { ThemeProvider } from 'next-themes';
export function Providers({ children }) {
return (
<ThemeProvider attribute="class" defaultTheme="system">
{children}
</ThemeProvider>
);
}
// app/layout.tsx
import { Providers } from './providers';
export default function RootLayout({ children }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
// 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>
);
}
<!-- 文本颜色 -->
<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>
@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);
}
}
<div class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]">
语义化颜色
</div>
<article class="prose dark:prose-invert">
<!-- Markdown 内容自动适配深色模式 -->
</article>
<!-- 根据屏幕尺寸和主题的不同布局和颜色 -->
<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>
<!-- 正确:移动优先渐进 -->
<div class="text-sm md:text-base lg:text-lg">
<!-- 错误:桌面优先思维(更多代码,更多错误) -->
<div class="lg:text-lg md:text-base text-sm">
WCAG 2.2 要求最小 24x24px,但推荐 44x44px:
<!-- 触控友好按钮(最小 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>
@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);
}
<h1 class="text-fluid-xl font-bold">平滑缩放标题</h1>
<p class="text-fluid-base leading-relaxed">平滑缩放正文文本。</p>
@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);
}
在开发过程中使用 debug-screens 插件:
npm install -D @tailwindcss/debug-screens
@plugin "@tailwindcss/debug-screens";
/* 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;
}
}
确保在浅色和深色模式下都有足够的对比度 (WCAG 2.2):
普通文本:最小对比度 4.5:1
大文本 (18pt+):最小对比度 3:1
交互元素:与相邻颜色的对比度 3:1
<!-- 在两种模式下都有良好对比度 --><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>
尊重偏好减少动画的用户:
<div class="
transition-transform duration-300
hover:scale-105
motion-reduce:transition-none
motion-reduce:hover:scale-100
">
尊重动画偏好
</div>
<!-- 懒加载首屏以下的图片 -->
<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"
/>
@utility safe-area-pb {
padding-bottom: env(safe-area-inset-bottom);
}
<!-- 底部导航栏尊重设备刘海 -->
<nav class="fixed bottom-0 inset-x-0 safe-area-pb bg-white border-t">
导航
</nav>
每周安装量
252
仓库
GitHub 星标
21
首次出现
Jan 23, 2026
安全审计
安装于
opencode221
gemini-cli217
codex212
github-copilot202
cursor193
amp180
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.
<!-- 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>
| Prefix | Min Width | Typical Devices | CSS Media Query |
|---|---|---|---|
| (none) | 0px | All mobile phones | All 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) |
Common device sizes to test:
@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:
<div class="grid xs:grid-cols-2 3xl:grid-cols-6">
<!-- Custom breakpoints work like built-in ones -->
</div>
Instead of targeting devices, let your content determine breakpoints:
@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.
<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>
<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>
<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>
<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>
<!-- 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>
Container queries enable component-level responsiveness, independent of viewport size. This is essential for reusable components in 2025.
@plugin "@tailwindcss/container-queries";
<!-- 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>
| Class | Min-width | Use 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 |
| Container Queries | Viewport Queries |
|---|---|
| Reusable components | Page-level layouts |
| Cards in various contexts | Navigation bars |
| Sidebar widgets | Hero sections |
| CMS/embedded content | Full-width sections |
Target screens below a certain size:
<!-- 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>
Dark mode follows the user's operating system preference using prefers-color-scheme:
@import "tailwindcss";
/* No additional configuration needed */
<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>
Control dark mode with a CSS class:
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
<!-- 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>
// 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();
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();
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
<html data-theme="dark">
<body>
<div class="bg-white dark:bg-gray-900">Content</div>
</body>
</html>
npm install next-themes
// app/providers.tsx
'use client';
import { ThemeProvider } from 'next-themes';
export function Providers({ children }) {
return (
<ThemeProvider attribute="class" defaultTheme="system">
{children}
</ThemeProvider>
);
}
// app/layout.tsx
import { Providers } from './providers';
export default function RootLayout({ children }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
// 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>
);
}
<!-- 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>
@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);
}
}
<div class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]">
Semantic colors
</div>
<article class="prose dark:prose-invert">
<!-- Markdown content automatically adapts to dark mode -->
</article>
<!-- 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>
<!-- 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">
WCAG 2.2 requires 24x24px minimum, but 44x44px is recommended:
<!-- 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>
@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);
}
<h1 class="text-fluid-xl font-bold">Smoothly Scaling Heading</h1>
<p class="text-fluid-base leading-relaxed">Smoothly scaling body text.</p>
@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);
}
Use the debug-screens plugin during development:
npm install -D @tailwindcss/debug-screens
@plugin "@tailwindcss/debug-screens";
/* 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;
}
}
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
<!-- 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>
Respect users who prefer reduced motion:
<div class="
transition-transform duration-300
hover:scale-105
motion-reduce:transition-none
motion-reduce:hover:scale-100
">
Respects motion preferences
</div>
<!-- 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"
/>
@utility safe-area-pb {
padding-bottom: env(safe-area-inset-bottom);
}
<!-- Bottom navigation respects device notch -->
<nav class="fixed bottom-0 inset-x-0 safe-area-pb bg-white border-t">
Navigation
</nav>
Weekly Installs
252
Repository
GitHub Stars
21
First Seen
Jan 23, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode221
gemini-cli217
codex212
github-copilot202
cursor193
amp180
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
106,200 周安装
MarsWaveAI TTS:文本转语音API,支持多说话人脚本与快速语音合成
624 周安装
AI代码安全审计工具 - 检测vibe-coding应用漏洞,防止数据泄露与API密钥被盗
629 周安装
钉钉文档API技能:知识库与文档自动化操作完整指南
636 周安装
Office转Markdown工具:Word/Excel/PPT/PDF一键转换,支持AI增强处理
630 周安装
Oracle到PostgreSQL迁移测试项目脚手架 - 集成测试基础设施搭建指南
641 周安装
Oracle到PostgreSQL迁移集成测试规划指南 | 数据库迁移测试自动化
643 周安装
@2xl |
| 42rem (672px) |
| Large containers |
@3xl | 48rem (768px) | Page sections |