如何使用CSS/JS实现动态双色环形图标效果
实现方案
我们可以用SVG配合少量JS实现该效果,完全不需要依赖图片资源,调整也很灵活。
核心思路
用SVG的<circle>元素绘制环形,通过stroke-dasharray、stroke-dashoffset属性控制环形的显示比例,不同状态的环形通过类名切换颜色/渐变即可。
完整代码示例
HTML
<!-- 环形容器,图标会动态插入到这里 --> <div class="icon-ring-container"></div> <!-- 提前定义环形用到的蓝色渐变,复用即可 --> <svg width="0" height="0" style="position: absolute;visibility: hidden;"> <defs> <linearGradient id="blueGradient" x1="0%" y1="0%" x2="100%" y2="0%"> <stop offset="0%" stop-color="#4285f4" /> <stop offset="100%" stop-color="#1a73e8" /> </linearGradient> </defs> </svg>
CSS
.icon-ring-container { display: flex; gap: 20px; padding: 20px; } .ring-item { position: relative; width: 60px; height: 60px; } .ring-svg { width: 100%; height: 100%; transform: rotate(-90deg); /* 让环形的起点在顶部 */ } .ring-circle { fill: none; stroke-width: 4; /* 环形的粗细,可自行调整 */ r: 26; /* 环形半径 = 容器宽度/2 - stroke-width,这里60/2-4=26 */ cx: 30; cy: 30; } /* 全灰状态 */ .ring-circle.gray { stroke: #e0e0e0; } /* 半完成状态的蓝色部分 */ .ring-circle.blue-part { stroke: #1a73e8; } /* 全完成渐变状态 */ .ring-circle.gradient-blue { stroke: url(#blueGradient); } /* 中间的图标占位,你可以换成自己的img或者iconfont */ .ring-icon { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 40px; height: 40px; border-radius: 50%; background: #f5f5f5; display: flex; align-items: center; justify-content: center; }
JS
// 环形周长 = 2 * π * r,r是上面定义的26 const RING_CIRCUMFERENCE = 2 * Math.PI * 26; /** * 生成单个环形图标 * @param {number} index 当前图标索引 * @param {number} total 总图标数量 */ function generateRingItem(index, total) { const item = document.createElement('div'); item.className = 'ring-item'; // 生成环形SVG const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.className = 'ring-svg'; // 先加底层全灰背景环 const bgCircle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); bgCircle.className = 'ring-circle gray'; svg.appendChild(bgCircle); if (index === total - 1) { // 最后一个图标:全蓝色渐变环形 const fullCircle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); fullCircle.className = 'ring-circle gradient-blue'; fullCircle.style.strokeDasharray = RING_CIRCUMFERENCE; fullCircle.style.strokeDashoffset = 0; svg.appendChild(fullCircle); } else if (index !== 0) { // 中间图标:灰蓝拼接,这里默认蓝色占50%,可以根据实际业务调整比例 const halfCircle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); halfCircle.className = 'ring-circle blue-part'; halfCircle.style.strokeDasharray = RING_CIRCUMFERENCE; halfCircle.style.strokeDashoffset = RING_CIRCUMFERENCE * 0.5; // 0.5就是蓝色占一半,改这个数值调整比例 svg.appendChild(halfCircle); } // 加中间的图标占位 const icon = document.createElement('div'); icon.className = 'ring-icon'; icon.innerText = index + 1; // 换成你的图标内容即可 item.appendChild(svg); item.appendChild(icon); return item; } /** * 初始化所有环形图标 * @param {number} total 要生成的图标总数量 */ function initRings(total) { const container = document.querySelector('.icon-ring-container'); container.innerHTML = ''; for(let i = 0; i < total; i++) { container.appendChild(generateRingItem(i, total)); } } // 示例:生成5个图标,要改数量直接传不同的参数就行 initRings(5);
需求匹配说明
- 图标数量动态可变:直接调用
initRings(数量)即可生成对应数量的图标,完全灵活 - 第一个图标全灰色:默认底层就是全灰环,第一个不叠加其他颜色环,自然就是全灰效果
- 中间图标灰蓝拼接:底层灰环+上层蓝色部分环,拼接效果自动实现,蓝色占比可以调整
strokeDashoffset的系数自行修改 - 最后一个图标蓝色渐变:直接使用预定义的SVG渐变填充环形即可
- 所有环形都是动态生成的SVG元素,没有嵌入到图片中,修改样式、调整比例都非常方便
内容的提问来源于stack exchange,提问作者Davina Leong
相关产品推荐
相关产品推荐

