原生可用但受限:仅输出7位hex(如"#ff0000"),不支持透明度、hsl/rgba、实时拖拽预览,safari等浏览器存在假支持或点击无响应问题,样式与弹窗完全不可定制,故需手写轻量级组件以满足设计需求。

原生 <input type="color"> 能用,但样式不可控、交互简陋、不支持透明度,面试时手写一个轻量级颜色选择器组件,重点不在炫技,而在理解 HSV/HSL 色彩空间映射、鼠标拖拽坐标转换、以及 input 事件与 UI 同步的边界处理。
为什么不用 input[type="color"]?
它在 Safari 上默认不支持 alpha 通道,Chrome/Firefox 的弹出面板无法定制样式,且无法响应 change 以外的实时输入(比如拖动色盘时预览)。面试中若直接用原生标签,会被追问“如果设计稿要求带透明度滑块和 HEX 实时编辑框,你怎么改?”——这时候就得自己画 Canvas 或用 DOM 模拟色盘了。
-
input[type="color"]只输出 7 位 HEX(如"#ff0000"),没有rgba()或 HSL 支持 - 移动端点击触发系统原生 picker,无法嵌入表单页或 Modal 中
- 无法监听鼠标移动过程中的中间值,只有最终确认才触发
change
用 Canvas 绘制 HSV 色盘的关键坐标转换
HSV 色盘本质是一个极坐标系:圆心是纯白(V=1, S=0),边缘是饱和色(S=1),半径代表饱和度 S,角度代表色相 H。Canvas 里画的是直角坐标,所以需要把鼠标 clientX/clientY 映射回极坐标:
const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left - centerX; const y = e.clientY - rect.top - centerY; const s = Math.min(Math.sqrt(x*x + y*y) / radius, 1); const h = (Math.atan2(y, x) + Math.PI) / (Math.PI * 2); // 归一化到 [0, 1]
注意三点:
- 必须用
Math.atan2(y, x),不是Math.atan(y/x),否则象限错乱 - 半径超出圆范围时要截断(
Math.min(..., 1)),否则拖到外面会算出非法 S 值 - Canvas 清空重绘前,记得调用
ctx.clearRect(0, 0, width, height),否则旧图残留
如何同步更新 HEX / RGB / HSL 显示并响应输入?
用户改 <input type="text"> 里的 HEX,要立刻解析并重定位色盘和滑块;反过来拖动色盘,也要实时更新所有文本框。关键在于统一数据源(比如存一个 hsl 对象)和防抖输入:
- HEX 输入校验用正则
/^#([0-9A-F]{3}|[0-9A-F]{6}|[0-9A-F]{8})$/i,支持 #RGB、#RRGGBB、#RRGGBBAA - 修改文本框时,用
input事件(非change),配合requestAnimationFrame防抖,避免高频重绘卡顿 - HSL 滑块(亮度 V 和饱和度 S)建议用两个
<input type="range">,min="0" max="100",绑定到hsl.l和hsl.s,注意单位统一(内部全用 0–1,DOM 层转为 0–100)
alpha 透明度的实现陷阱
HTML 颜色字符串本身不携带 alpha,rgba() 是函数式语法,hsla() 同理。但 Canvas 绘制色盘时,不能直接用 rgba(h, s, l, a)——因为 HSV 色盘本身不含 alpha 维度。正确做法是:
- 单独加一个透明度滑块,值域 0–1,存在独立变量
alpha - 最终输出时拼接:
`hsla(${h}, ${s}%, ${l}%, ${alpha})`或`rgba(${r}, ${g}, ${b}, ${alpha})` - 预览色块背景必须设为带网格的底纹(如
background-image: linear-gradient(45deg, #ccc 25%, transparent 25%), linear-gradient(-45deg, #ccc 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #ccc 75%), linear-gradient(-45deg, transparent 75%, #ccc 75%)),否则看不出半透效果
最易被忽略的一点:CSS color 属性不支持透明度,所以预览色块只能用 background-color,而文本颜色始终是实色——这恰恰是面试官想看你是否清楚渲染限制。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











