You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 12:52:52