如何用双线性渐变模拟HTML meter,避免渐变水平压缩?
自定义阶梯渐变进度条(替代HTML )
原生HTML <meter> 元素的个性化样式定制难度极高,因此改用CSS模拟meter组件,需求如下:
渐变样式要求
- 未填充区域(右侧):阶梯状灰色线性渐变
background-image: linear-gradient( to right, #ddd 20%, #ccc 20%, #ccc 40%, #bbb 40%, #bbb 60%, #aaa 60%, #aaa 80%, #999 80%, #999 100% ); - 填充区域(左侧):阶梯状绿色线性渐变
background-image: linear-gradient( to right, #70f600 20%, #0e0 20%, #0e0 40%, #0d0 40%, #0d0 60%, #0c0 60%, #0c0 80%, #0b0 80%, #0b0 100% );
预期效果
- 0%填充时,仅显示灰色阶梯渐变
- 100%填充时,仅显示绿色阶梯渐变
- 填充比例为X%(0%<X<100%)时,组件左侧X%显示绿色渐变的对应区域,右侧剩余区域显示灰色渐变的对应区域
- 核心要求:两个渐变均不得被水平压缩,且支持任意相对尺寸适配
当前实现的问题
原方案通过嵌套绝对定位的negative-space元素覆盖灰色区域,但灰色渐变会被水平压缩以适配元素宽度,无法满足需求。
原HTML代码:
<div class="meter-gauge"> <div class="negative-space" style="width: calc(100% - 36%)"></div> </div>
原CSS代码:
.meter-gauge { position: relative; display: inline-block; height: 1em; min-width: 10em; background-image: linear-gradient( to right, #70f600 20%, #0e0 20%, #0e0 40%, #0d0 40%, #0d0 60%, #0c0 60%, #0c0 80%, #0b0 80%, #0b0 100% ); } .negative-space { position: absolute; top: 0; right: 0; height: inherit; width: 0; /* Overridden by style attribute */ background-image: linear-gradient( to right, #ddd 20%, #ccc 20%, #ccc 40%, #bbb 40%, #bbb 60%, #aaa 60%, #aaa 80%, #999 80%, #999 100% ); z-index: 1; }
解决方案
核心思路是让两个渐变均基于整个组件的尺寸渲染,通过裁剪上层渐变实现进度控制,避免渐变被压缩。使用CSS自定义属性结合clip-path实现,简洁且兼容性良好。
最终HTML结构
<div class="meter-gauge" style="--fill: 36%"></div>
最终CSS代码
.meter-gauge { position: relative; display: inline-block; height: 1em; min-width: 10em; /* 灰色未填充区域作为底层背景 */ background-image: linear-gradient( to right, #ddd 20%, #ccc 20%, #ccc 40%, #bbb 40%, #bbb 60%, #aaa 60%, #aaa 80%, #999 80%, #999 100% ); } .meter-gauge::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; /* 绿色填充区域作为上层背景 */ background-image: linear-gradient( to right, #70f600 20%, #0e0 20%, #0e0 40%, #0d0 40%, #0d0 60%, #0c0 60%, #0c0 80%, #0b0 80%, #0b0 100% ); /* 裁剪上层元素,仅保留左侧 --fill 比例的区域 */ clip-path: inset(0 calc(100% - var(--fill)) 0 0); }
方案说明
- 父容器设置灰色渐变作为底层背景,伪元素设置绿色渐变作为上层背景,两者均基于整个组件尺寸渲染,不会被压缩
- 使用CSS自定义属性
--fill动态控制填充比例,修改该属性值即可调整进度(例如--fill: 75%对应75%填充) clip-path: inset(0 calc(100% - var(--fill)) 0 0)通过裁剪伪元素,只显示左侧指定比例的绿色渐变区域,右侧自然露出底层的灰色渐变- 完全使用相对单位(
em),支持任意尺寸适配,无需绝对单位
内容的提问来源于stack exchange,提问作者Anders Rabo Thorbeck
相关产品推荐
相关产品推荐

