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

如何在JavaScript中复刻Bootstrap的WCAG算法选择激活态颜色?

实现Bootstrap 5按钮hover/active状态的文本颜色自动选择逻辑

Bootstrap 5的按钮文本颜色自动切换核心是基于WCAG 2.1的对比度标准,通过计算背景色的相对亮度,判断使用黑色(#000000)还是白色(#FFFFFF)文本,来满足最小对比度要求(默认min-contrast-ratio为4.5)。以下是完整的JavaScript实现方案:

核心步骤说明

  1. 将任意格式的颜色(Hex/RGB/RGBA/颜色关键字)转换为标准RGB数值(0-255)
  2. 根据WCAG 2.1公式计算背景色的相对亮度
  3. 计算白色、黑色与背景色的对比度
  4. 选择满足最小对比度要求的颜色;若两者都满足,选对比度更高的;若都不满足,选与背景相对亮度差值更大的颜色

完整JavaScript代码

// 辅助函数:将Hex颜色转为RGB数组
function hexToRgb(hex) {
  const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
  hex = hex.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b);
  
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result ? [
    parseInt(result[1], 16),
    parseInt(result[2], 16),
    parseInt(result[3], 16)
  ] : null;
}

// 辅助函数:将RGB/RGBA字符串转为RGB数组
function rgbToRgbArray(rgbStr) {
  const result = /^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*\d+(?:\.\d+)?)*\)$/.exec(rgbStr);
  return result ? [
    parseInt(result[1], 10),
    parseInt(result[2], 10),
    parseInt(result[3], 10)
  ] : null;
}

// 转换任意颜色格式为RGB数组
function getRgbColor(color) {
  if (color.startsWith('#')) return hexToRgb(color);
  if (color.startsWith('rgb') || color.startsWith('rgba')) return rgbToRgbArray(color);
  // 支持颜色关键字(如'black'、'green')
  const tempEl = document.createElement('div');
  tempEl.style.color = color;
  document.body.appendChild(tempEl);
  const computedColor = window.getComputedStyle(tempEl).color;
  document.body.removeChild(tempEl);
  return rgbToRgbArray(computedColor);
}

// WCAG 2.1 相对亮度计算
function getRelativeLuminance(rgb) {
  const [r, g, b] = rgb.map(val => {
    const normalized = val / 255;
    return normalized <= 0.03928 ? normalized / 12.92 : Math.pow((normalized + 0.055) / 1.055, 2.4);
  });
  return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}

// 计算两种颜色的对比度
function getContrast(l1, l2) {
  const lighter = Math.max(l1, l2);
  const darker = Math.min(l1, l2);
  return (lighter + 0.05) / (darker + 0.05);
}

// 主函数:根据背景色获取合适的文本颜色
function getButtonTextColor(backgroundColor, minContrastRatio = 4.5) {
  const bgRgb = getRgbColor(backgroundColor);
  if (!bgRgb) return '#000000'; // 异常情况默认返回黑色
  
  const bgLuminance = getRelativeLuminance(bgRgb);
  const whiteLuminance = getRelativeLuminance([255, 255, 255]);
  const blackLuminance = getRelativeLuminance([0, 0, 0]);
  
  const whiteContrast = getContrast(bgLuminance, whiteLuminance);
  const blackContrast = getContrast(bgLuminance, blackLuminance);
  
  // 判断满足最小对比度的颜色
  const whiteMeets = whiteContrast >= minContrastRatio;
  const blackMeets = blackContrast >= minContrastRatio;
  
  if (whiteMeets && !blackMeets) return '#FFFFFF';
  if (blackMeets && !whiteMeets) return '#000000';
  if (whiteMeets && blackMeets) {
    // 两者都满足,选对比度更高的
    return whiteContrast > blackContrast ? '#FFFFFF' : '#000000';
  }
  // 两者都不满足,选与背景亮度差值更大的极端颜色
  return Math.abs(bgLuminance - whiteLuminance) > Math.abs(bgLuminance - blackLuminance) ? '#FFFFFF' : '#000000';
}

使用示例

// 测试不同背景色
console.log(getButtonTextColor('#000000')); // 黑色背景 → 返回白色#FFFFFF
console.log(getButtonTextColor('#FFFFFF')); // 白色背景 → 返回黑色#000000
console.log(getButtonTextColor('#28a745')); // Bootstrap绿色 → 返回白色#FFFFFF
console.log(getButtonTextColor('#ffc107')); // Bootstrap黄色 → 返回黑色#000000

与Bootstrap逻辑的对应

  • 当背景为纯黑/纯白时,直接返回对比色,对应你观察到的极端情况
  • 对于绿色、蓝色这类中间色,通过minContrastRatio(默认4.5)判断,和Bootstrap的$min-contrast-ratio变量逻辑完全一致

内容的提问来源于stack exchange,提问作者Danilo Bassi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 08:17:39