基于Next.js 12+Tailwind CSS实现无障碍动态字体大小调整
基于Next.js 12 + Tailwind CSS的全站字体缩放无障碍实现方案
针对你的需求,我整理了一套不用新增类名、完全兼容现有Tailwind工具类的全站字体缩放方案,同时满足WCAG无障碍标准,具体实现如下:
核心思路
用CSS变量替代Tailwind默认的固定字体大小值,结合Next.js的全局Context管理缩放档位(默认/放大/缩小),并将用户设置持久化到localStorage。这样不用修改任何现有组件的text-xs/text-sm等类名,点击按钮就能全局切换字体大小。
1. 调整Tailwind配置,绑定字体大小到CSS变量
在tailwind.config.js里,把默认的fontSize映射到自定义CSS变量,让所有使用text-xs/text-sm/text-md的地方都读取变量值:
module.exports = { theme: { extend: { fontSize: { xs: 'var(--text-xs)', sm: 'var(--text-sm)', md: 'var(--text-md)', // 其他字体大小(如lg/xl)也可以按同样方式添加 }, }, }, }
2. 创建全局字体缩放Context,管理状态与持久化
在context/FontSizeContext.js中实现状态管理,包含缩放档位切换方法,同时把用户选择存在localStorage里,刷新页面不会丢失:
import { createContext, useContext, useState, useEffect } from 'react'; const FontSizeContext = createContext(); export function FontSizeProvider({ children }) { // 定义三个档位:默认、放大、缩小 const [sizeMode, setSizeMode] = useState('default'); // 页面加载时恢复用户之前的设置 useEffect(() => { const savedMode = localStorage.getItem('font-size-mode'); if (savedMode) setSizeMode(savedMode); }, []); // 每次切换档位时保存到localStorage useEffect(() => { localStorage.setItem('font-size-mode', sizeMode); }, [sizeMode]); // 增大字体:从缩小→默认→放大 const increaseFont = () => { setSizeMode(prev => prev === 'smaller' ? 'default' : prev === 'default' ? 'larger' : 'larger' ); }; // 减小字体:从放大→默认→缩小 const decreaseFont = () => { setSizeMode(prev => prev === 'larger' ? 'default' : prev === 'default' ? 'smaller' : 'smaller' ); }; // 重置到默认大小 const resetFont = () => setSizeMode('default'); return ( <FontSizeContext.Provider value={{ sizeMode, increaseFont, decreaseFont, resetFont }}> {children} </FontSizeContext.Provider> ); } // 自定义Hook,方便其他组件调用 export function useFontSize() { return useContext(FontSizeContext); }
3. 全局注入动态CSS变量
在pages/_app.js里,根据当前的sizeMode动态设置CSS变量的值,同时用FontSizeProvider包裹整个应用,让所有页面都能访问状态:
import { FontSizeProvider, useFontSize } from '../context/FontSizeContext'; import '../styles/globals.css'; function MyApp({ Component, pageProps }) { return ( <FontSizeProvider> <DynamicFontStyles /> <Component {...pageProps} /> </FontSizeProvider> ); } // 动态生成CSS变量的组件 function DynamicFontStyles() { const { sizeMode } = useFontSize(); let rootStyles = ''; switch (sizeMode) { case 'larger': rootStyles = ` :root { --text-xs: 12px; --text-sm: 14px; --text-md: 16px; } `; break; case 'smaller': rootStyles = ` :root { --text-xs: 8px; --text-sm: 10px; --text-md: 12px; } `; break; default: rootStyles = ` :root { --text-xs: 10px; --text-sm: 12px; --text-md: 14px; } `; } return <style dangerouslySetInnerHTML={{ __html: rootStyles }} />; } export default MyApp;
4. 实现无障碍字体控制按钮组件
创建components/FontSizeControls.js,确保按钮符合WCAG标准:支持键盘操作、有明确的aria标签、禁用状态有视觉提示:
import { useFontSize } from '../context/FontSizeContext'; export default function FontSizeControls() { const { increaseFont, decreaseFont, resetFont, sizeMode } = useFontSize(); return ( <div className="flex gap-2 p-2 bg-gray-100"> <button onClick={decreaseFont} disabled={sizeMode === 'smaller'} className="px-3 py-1 rounded border disabled:opacity-50 disabled:cursor-not-allowed" aria-label="减小字体" aria-disabled={sizeMode === 'smaller'} > A- </button> <button onClick={resetFont} className="px-3 py-1 rounded border" aria-label="重置字体大小" > A </button> <button onClick={increaseFont} disabled={sizeMode === 'larger'} className="px-3 py-1 rounded border disabled:opacity-50 disabled:cursor-not-allowed" aria-label="增大字体" aria-disabled={sizeMode === 'larger'} > A+ </button> </div> ); }
5. 在页面中使用控制组件
把这个组件放到全局导航、侧边栏或者footer里,比如在首页pages/index.js中引入:
import FontSizeControls from '../components/FontSizeControls'; export default function Home() { return ( <div> <FontSizeControls /> <div className="p-4"> <p className="text-xs">这是text-xs的文本</p> <p className="text-sm mt-2">这是text-sm的文本</p> <p className="text-md mt-2">这是text-md的文本</p> </div> </div> ); }
无障碍合规说明
- 所有按钮都添加了
aria-label,屏幕阅读器能识别功能 - 支持键盘操作:Tab键聚焦,Enter/Space键触发点击
- 禁用状态下设置了
disabled和aria-disabled属性,同时降低透明度给出视觉反馈 - 字体变化可逆,符合WCAG 2.1可操作性要求
- 用户设置持久化,刷新页面后保持选择
内容的提问来源于stack exchange,提问作者Brandon Han
相关产品推荐
相关产品推荐

