用 标签可纯 HTML 实现语义化技能条,需显式设 max 值(如 ),CSS 可定制样式;SVG 环形图适合视觉场景,通过 stroke-dasharray 与 stroke-dashoffset 控制进度,配合 transform="rotate(-90)" 使进度从顶部开始;技能数据推荐用 data-* 属性存储,便于 JS 提取与扩展。

用 做技能条最省事
纯 HTML 实现技能展示, 是唯一原生支持的语义化标签,不用 JS 就能渲染进度值,且默认可访问、适配高对比度模式。浏览器兼容性从 Chrome 6、Firefox 16、Edge 10 开始都支持,IE 完全不支持——如果必须兼容 IE,得换方案。
常见错误是直接写 却没设 max,结果条永远只显示四分之一(因为默认 max=1)。正确写法必须显式声明:
样式可直接用 CSS 控制颜色和高度,比如:
progress { height: 8px; }
progress::-webkit-progress-bar { background-color: #eee; }
progress::-webkit-progress-value { background-color: #4a90e2; }
progress::-moz-progress-bar { background-color: #4a90e2; }- Chrome/Safari 用
::-webkit-progress-value控制已填充部分 - Firefox 用
::-moz-progress-bar,不能混用 - IE 不识别
,会降级为内联元素,需加display: block防止错位
SVG 技能环形图适合“视觉优先”场景
环形图本质是 SVG 的 + stroke-dasharray 动画技巧,比 Canvas 轻量、可缩放不失真、支持 CSS 过渡。但别用 手算贝塞尔曲线——太容易算错起止角度。
立即学习“前端免费学习笔记(深入)”;
核心逻辑是:用一个圆描边长度代表 100%,再通过 stroke-dashoffset 截取显示比例。例如画一个半径 45 的环,总周长 = 2 * π * 45 ≈ 283,要显示 80% 就设 stroke-dasharray="283" 和 stroke-dashoffset="56.6"(283 × 0.2)。
实际编码时建议封装成函数生成 SVG 字符串,避免硬编码数值:
function skillRing(percent) {
const radius = 45;
const circumference = 2 * Math.PI * radius;
const offset = circumference - (percent / 100) * circumference;
return `
`;
}-
transform="rotate(-90 ...)"是为了让进度从顶部开始,否则默认从 3 点钟方向起始 - 百分比传入前务必校验范围(0–100),否则
offset可能为负,导致环逆向绘制 - 若需动画效果,直接对
stroke-dashoffset加 CSS transition,不要用 JS 逐帧修改
用 data- 属性驱动技能列表更灵活
把技能名称、熟练度、工具链都存在 HTML 属性里,后续想加筛选、排序或导出 JSON 都方便。别把数据写死在文本节点里,比如 —— 这种写法没法被 JS 安全提取数值。
推荐结构:
这样 JS 可以直接读取:
document.querySelectorAll('[data-skill]').forEach(el => {
const name = el.dataset.skill;
const level = Number(el.dataset.level);
const tools = el.dataset.tools.split(', ').map(t => t.trim());
});-
dataset自动转小写并用驼峰命名,data-tools-list→el.dataset.toolsList - 百分比值存数字而非字符串,避免后续计算时意外拼接成字符串
- 如果技能项超过 10 个,建议加
aria-live="polite"支持屏幕阅读器动态播报更新
响应式技能图表要注意断点重绘
技能条在手机上横向排列会挤出滚动条,但简单加 flex-wrap 又会导致环形图尺寸错乱。真正要处理的是容器尺寸变化后 SVG 的 viewBox 缩放和 的高度重置。
关键不是媒体查询改宽度,而是监听容器变化:
const container = document.querySelector('.skills-container');
const resizeObserver = new ResizeObserver(() => {
// 重新计算 SVG 尺寸或重设 progress height
document.querySelectorAll('progress').forEach(p => {
p.style.height = window.innerWidth < 768 ? '6px' : '8px';
});
});
resizeObserver.observe(container);- 别用
window.onresize,它触发太频繁且不感知元素尺寸变化 - 环形图 SVG 内部尺寸靠
viewBox控制,外部容器用width: 100%+aspect-ratio: 1保正方形 - 如果用了第三方图标字体(如 Font Awesome)标注技能,确保图标字号随容器缩放,否则小屏下图标可能比文字大一倍
技能图表最难的不是画出来,而是让不同设备下数值准确、语义清晰、交互不卡顿。多数人卡在 SVG 坐标系理解偏差或 dataset 类型误判上,多打两次 console.log(typeof el.dataset.level) 能省半天调试时间。










