为何CSS中opacity需应用于预乘颜色?求标准依据
CSS opacity 与预乘颜色的处理逻辑
测试代码
CSS
#div1 { opacity: 0.6; background-color: rgba(155, 66, 200, 0.5); width: 200px; height: 200px; } #div2 { background-color: rgba(0, 77, 100, 0.8); width: 200px; height: 200px; }
HTML
<div id="div1"> <div id="div2"></div> </div>
颜色合成计算
先计算div2与div1的合成预乘颜色(Cs/as为div2的RGB值/alpha值,Cb/ab为div1的RGB值/alpha值):
co = Cs * as + Cb * ab * (1 - as) ao = as + ab * (1 - as)
代入数值计算:
co = (0, 77/255, 100/255) * 0.8 + (155/255, 66/255, 200/255) * 0.5 * (1 - 0.8) co = (0.06, 0.267, 0.392) ao = 0.8 + 0.5 * (1 - 0.8) ao = 0.9
得到预乘RGBA:(0.06, 0.267, 0.392, 0.9)
应用opacity后结果与截图取色一致,但核心疑问是:为何要对预乘颜色应用opacity?
两种方案对比
方案一
- 混合、合成内部元素
- 得到合成后的预乘颜色值
(r,g,b,a) - 对预乘值应用opacity:
(r * opacity, g * opacity, b * opacity, a * opacity) - 提取非预乘颜色分量:
(r * opacity / (a * opacity), g * opacity / (a * opacity), b * opacity / (a * opacity), a * opacity) = (r/a, g/a, b/a, a * opacity)
方案二
- 混合、合成内部元素
- 得到合成后的预乘颜色值
(r,g,b,a) - 提取非预乘颜色分量:
(r/a, g/a, b/a, a) - 对非预乘颜色应用opacity:
(r/a * opacity, g/a * opacity, b/a * opacity, a * opacity)
为何选择方案一?
1. 符合CSS渲染的预乘alpha管线
CSS渲染引擎内部全程采用预乘alpha进行颜色计算,这是为了避免半透明元素渲染时出现色偏或边缘失真。opacity的作用是统一降低整个元素(包括内部已合成内容)的透明度,直接对预乘颜色值乘以opacity,能保证RGB分量与alpha的比例始终一致,维持预乘关系的正确性。
2. 减少数值计算误差
虽然从纯数学角度看,两种方案的最终非预乘结果看似相同,但实际浮点运算中,方案二先提取非预乘颜色再缩放,可能导致RGB与alpha的比例失衡,出现细微的颜色偏差。方案一直接操作预乘值,全程保持RGB与alpha的绑定关系,计算更稳定。
3. 规范依据
根据CSS Color Module Level 4的定义,opacity属性会作用于元素的完整预乘颜色值:设置opacity时,元素所有绘制内容的预乘RGB和alpha值都会被乘以该opacity系数,之后再参与与页面背景的合成流程。
内容的提问来源于stack exchange,提问作者oceanGermanique
相关产品推荐
相关产品推荐

