前端颜色工具函数详解:从 HEX 到 HSL 的完整转换方案

24 阅读9分钟

前端颜色工具函数详解:从 HEX 到 HSL 的完整转换方案

前言

在前端开发中,颜色处理是一个常见且重要的需求。无论是构建颜色选择器、主题切换功能,还是实现动态配色方案,都需要对颜色进行各种格式的转换和处理。本文将深入解析一套完整的颜色工具函数库,涵盖 HEX、RGB、HSL 三种主流颜色格式之间的相互转换,以及对比色计算、色阶生成等实用功能。

RGB转十六进制 - 在线颜色代码转换工具 | 免费快速转换

目录

类型定义

在开始之前,我们先了解一下基础的类型定义:

interface RGB {
  r: number;  // 红色分量,范围 0-255
  g: number;  // 绿色分量,范围 0-255
  b: number;  // 蓝色分量,范围 0-255
}

interface HSL {
  h: number;  // 色相,范围 0-360
  s: number;  // 饱和度,范围 0-100
  l: number;  // 亮度,范围 0-100
}

HEX ↔ RGB 转换

1. hexToRgb:十六进制转 RGB

功能描述:将十六进制颜色值(如 #FF5733FF5733)转换为 RGB 对象。

实现原理

  • 使用正则表达式 /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i 匹配6位十六进制字符串
  • 支持带 # 号和不带 # 号的格式
  • 将每个两位十六进制数解析为十进制(0-255)

代码实现

export const hexToRgb = (hex: string): RGB | null => {
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result ? {
    r: parseInt(result[1], 16),
    g: parseInt(result[2], 16),
    b: parseInt(result[3], 16)
  } : null;
};

使用示例

hexToRgb('#FF5733');  // { r: 255, g: 87, b: 51 }
hexToRgb('FF5733');   // { r: 255, g: 87, b: 51 }
hexToRgb('invalid');  // null

注意事项

  • 如果输入的十六进制格式不正确,函数返回 null
  • 正则表达式使用 i 标志,支持大小写字母

2. rgbToHex:RGB 转十六进制

功能描述:将 RGB 三个分量转换为十六进制颜色字符串。

实现原理

  • 将每个 RGB 分量限制在 0-255 范围内
  • 转换为十六进制字符串,不足两位时补零
  • 组合成 #RRGGBB 格式

代码实现

export const rgbToHex = (r: number, g: number, b: number): string => {
  const toHex = (c: number) => {
    const hex = Math.max(0, Math.min(255, c)).toString(16);
    return hex.length === 1 ? '0' + hex : hex;
  };
  return '#' + toHex(r) + toHex(g) + toHex(b);
};

使用示例

rgbToHex(255, 87, 51);   // '#ff5733'
rgbToHex(0, 0, 0);       // '#000000'
rgbToHex(300, -10, 50);  // '#ff0032' (自动限制范围)

关键点

  • Math.max(0, Math.min(255, c)) 确保值在有效范围内
  • 使用 toString(16) 进行进制转换
  • 单数位时补零,保证输出格式统一

RGB ↔ HSL 转换

3. rgbToHsl:RGB 转 HSL

功能描述:将 RGB 颜色转换为 HSL(色相、饱和度、亮度)格式。

实现原理

  1. 归一化:将 RGB 值从 0-255 范围归一化到 0-1
  2. 计算最大值和最小值:找出 RGB 中的最大值和最小值
  3. 计算亮度(Lightness)L = (max + min) / 2
  4. 计算饱和度(Saturation)
    • 如果 max === min,饱和度为 0(灰度色)
    • 否则根据亮度选择公式:
      • L > 0.5: S = d / (2 - max - min)
      • L ≤ 0.5: S = d / (max + min)
  5. 计算色相(Hue)
    • 根据最大值所在的颜色分量计算
    • 最终转换为 0-360 度范围

代码实现

export const rgbToHsl = (r: number, g: number, b: number): HSL => {
  r /= 255;
  g /= 255;
  b /= 255;
  const max = Math.max(r, g, b), min = Math.min(r, g, b);
  let h = 0, s, l = (max + min) / 2;

  if (max === min) {
    h = s = 0;
  } else {
    const d = max - min;
    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
    switch (max) {
      case r: h = (g - b) / d + (g < b ? 6 : 0); break;
      case g: h = (b - r) / d + 2; break;
      case b: h = (r - g) / d + 4; break;
    }
    h /= 6;
  }

  return {
    h: Math.round(h * 360),
    s: Math.round(s * 100),
    l: Math.round(l * 100)
  };
};

使用示例

rgbToHsl(255, 87, 51);   // { h: 11, s: 100, l: 60 }
rgbToHsl(255, 255, 255); // { h: 0, s: 0, l: 100 } (白色)
rgbToHsl(0, 0, 0);       // { h: 0, s: 0, l: 0 } (黑色)

算法详解

  • HSL 模型更符合人类对颜色的感知
  • 色相(H)表示颜色的种类(红、绿、蓝等)
  • 饱和度(S)表示颜色的纯度(0% 为灰色,100% 为纯色)
  • 亮度(L)表示颜色的明暗(0% 为黑色,100% 为白色)

4. hslToRgb:HSL 转 RGB

功能描述:将 HSL 颜色值转换为 RGB 格式。

实现原理

  1. 归一化输入:将 HSL 值转换为 0-1 范围
  2. 计算辅助变量
    • q = L < 0.5 ? L * (1 + S) : L + S - L * S
    • p = 2 * L - q
  3. 色相转换:使用辅助函数 hue2rgb 将色相转换为 RGB 分量
  4. 处理特殊情况:当饱和度为 0 时,RGB 三个分量都等于亮度值

代码实现

export const hslToRgb = (h: number, s: number, l: number): RGB => {
  h /= 360;
  s /= 100;
  l /= 100;
  let r, g, b;

  if (s === 0) {
    r = g = b = l;
  } else {
    const hue2rgb = (p: number, q: number, t: number) => {
      if (t < 0) t += 1;
      if (t > 1) t -= 1;
      if (t < 1/6) return p + (q - p) * 6 * t;
      if (t < 1/2) return q;
      if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
      return p;
    };
    const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
    const p = 2 * l - q;
    r = hue2rgb(p, q, h + 1/3);
    g = hue2rgb(p, q, h);
    b = hue2rgb(p, q, h - 1/3);
  }

  return {
    r: Math.round(r * 255),
    g: Math.round(g * 255),
    b: Math.round(b * 255)
  };
};

使用示例

hslToRgb(11, 100, 60);   // { r: 255, g: 87, b: 51 }
hslToRgb(0, 0, 100);     // { r: 255, g: 255, b: 255 } (白色)
hslToRgb(120, 100, 50);  // { r: 0, g: 255, b: 0 } (纯绿色)

算法要点

  • hue2rgb 函数实现了色相到 RGB 分量的非线性映射
  • 通过调整色相值(h + 1/3hh - 1/3)来分别计算 R、G、B 分量
  • 这是标准的 HSL 到 RGB 转换算法

对比色计算

5. getContrastColor:获取对比色

功能描述:根据 RGB 颜色值计算最佳对比色(黑色或白色),用于确保文本可读性。

实现原理: 使用 YIQ 颜色空间的相对亮度公式:

YIQ = (R × 299 + G × 587 + B × 114) / 1000
  • 系数基于人眼对不同颜色的敏感度
  • 如果 YIQ ≥ 128,返回黑色;否则返回白色

代码实现

export const getContrastColor = (r: number, g: number, b: number): string => {
  const yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
  return yiq >= 128 ? 'black' : 'white';
};

使用示例

getContrastColor(255, 255, 255); // 'black' (白色背景用黑字)
getContrastColor(0, 0, 0);       // 'white' (黑色背景用白字)
getContrastColor(255, 87, 51);   // 'black' (亮色背景用黑字)

应用场景

  • 动态文本颜色选择
  • 确保 UI 中的文字在任何背景色上都有良好的可读性
  • 主题切换时的自动适配

替代方案: 现代浏览器支持 CSS 的 color-contrast() 函数,但在需要 JavaScript 计算的场景中,YIQ 算法仍然是一个可靠的选择。

色阶生成

6. generateShades:生成阴影色阶

功能描述:根据给定的十六进制颜色,生成5个逐渐变暗的阴影色阶。

实现原理

  • 将 HEX 转换为 RGB
  • 对每个 RGB 分量按比例减少(每次减少 15%)
  • 生成 5 个色阶,从浅到深

代码实现

export const generateShades = (hex: string): string[] => {
  const rgb = hexToRgb(hex);
  if (!rgb) return [];
  const shades = [];
  for (let i = 1; i <= 5; i++) {
    const factor = 1 - (i * 0.15);
    shades.push(rgbToHex(
      Math.round(rgb.r * factor),
      Math.round(rgb.g * factor),
      Math.round(rgb.b * factor)
    ));
  }
  return shades;
};

使用示例

generateShades('#FF5733');
// [
//   '#db4a2b',
//   '#b73d24',
//   '#93301d',
//   '#6f2316',
//   '#4b160f'
// ]

视觉效果

原始色 → 阴影1 → 阴影2 → 阴影3 → 阴影4 → 阴影5
  ███      ███      ███      ███      ███      ███

7. generateTints:生成色调色阶

功能描述:根据给定的十六进制颜色,生成5个逐渐变亮的色调色阶。

实现原理

  • 将 HEX 转换为 RGB
  • 对每个 RGB 分量向 255(白色)方向混合
  • 每次混合比例增加 15%
  • 生成 5 个色阶,从深到浅

代码实现

export const generateTints = (hex: string): string[] => {
  const rgb = hexToRgb(hex);
  if (!rgb) return [];
  const tints = [];
  for (let i = 1; i <= 5; i++) {
    const factor = i * 0.15;
    tints.push(rgbToHex(
      Math.round(rgb.r + (255 - rgb.r) * factor),
      Math.round(rgb.g + (255 - rgb.g) * factor),
      Math.round(rgb.b + (255 - rgb.b) * factor)
    ));
  }
  return tints;
};

使用示例

generateTints('#FF5733');
// [
//   '#ff6b4d',
//   '#ff7f66',
//   '#ff9380',
//   '#ffa799',
//   '#ffbbb3'
// ]

视觉效果

原始色 → 色调1 → 色调2 → 色调3 → 色调4 → 色调5
  ███      ███      ███      ███      ███      ███

应用场景

  • 设计系统的基础色板生成
  • 主题颜色的深浅变化
  • UI 组件的 hover、active 状态颜色
  • 数据可视化的颜色映射

完整使用示例

以下是一个综合使用示例,展示如何组合使用这些函数:

// 1. 颜色格式转换
const hex = '#FF5733';
const rgb = hexToRgb(hex);           // { r: 255, g: 87, b: 51 }
const hsl = rgbToHsl(255, 87, 51);   // { h: 11, s: 100, l: 60 }
const backToHex = rgbToHex(255, 87, 51); // '#ff5733'

// 2. 动态文本颜色
const backgroundColor = { r: 255, g: 87, b: 51 };
const textColor = getContrastColor(backgroundColor.r, backgroundColor.g, backgroundColor.b);
// textColor = 'black'

// 3. 生成完整色阶
const baseColor = '#FF5733';
const shades = generateShades(baseColor);  // 5个阴影色
const tints = generateTints(baseColor);    // 5个色调色

// 4. 构建颜色主题
const theme = {
  primary: baseColor,
  shades: shades,
  tints: tints,
  textColor: getContrastColor(...Object.values(hexToRgb(baseColor)!))
};

性能优化建议

  1. 缓存计算结果:对于频繁使用的颜色转换,可以考虑添加缓存机制
  2. 批量处理:如果需要处理大量颜色,可以考虑使用 Web Workers
  3. 类型检查:在生产环境中添加更严格的输入验证

总结

本文详细介绍了一套完整的颜色工具函数库,涵盖了:

格式转换:HEX ↔ RGB ↔ HSL 的完整转换链
对比度计算:基于 YIQ 算法的智能文本颜色选择
色阶生成:自动生成阴影和色调,适用于设计系统

这些函数可以广泛应用于:

  • 🎨 颜色选择器组件
  • 🎯 主题切换功能
  • 📊 数据可视化
  • 🎭 UI 组件库
  • 🌈 设计工具

通过理解这些算法的实现原理,我们可以更好地在前端项目中处理颜色相关的需求,提升用户体验和开发效率。

RGB转十六进制 - 在线颜色代码转换工具 | 免费快速转换


参考资源