Skip to content

progress 进度条

<progress> 是 HTML5 引入的语义化元素,用于表示任务的完成进度。它有两种模式:确定进度(value + max)和不确定进度(无 value)。浏览器会根据这些属性渲染出不同样式的进度条,适用于文件上传、加载状态、任务完成度等场景。

前置知识

阅读本节前,建议先了解:output 输出元素

基础概念

什么是 progress 元素

<progress> 元素表示任务的完成进度。主要特点:

  • 语义化:明确表示"进度",屏幕阅读器可识别
  • 两种模式:确定进度(显示百分比)和不确定进度(显示加载动画)
  • 内置样式:浏览器自动渲染进度条外观
  • 属性简单:只需 valuemax 两个属性

浏览器渲染

不同浏览器对 <progress> 的默认样式有所不同:

浏览器外观
Chrome绿色进度条(扁条)
Firefox绿色进度条(较厚)
Safari灰色进度条
Edge蓝色进度条

语法

确定进度

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>progress 确定进度</title>
</head>
<body>
    <h2>文件上传进度</h2>
    <label for="upload">上传进度:</label>
    <progress id="upload" value="70" max="100">70%</progress>
    <p>已完成 <output for="upload">70</output>%</p>
</body>
</html>

不确定进度

当不设置 value 属性时,显示不确定进度动画(表示"正在进行中,但不知道进度"):

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>progress 不确定进度</title>
</head>
<body>
    <h2>加载中</h2>
    <!-- 不确定进度:无 value 属性 -->
    <progress>正在加载...</progress>
    <p>数据加载中,请稍候...</p>
</body>
</html>

属性说明

属性说明默认值
value当前进度值无(不确定进度)
max最大值1
form关联的表单 ID

详细说明

与 output 配合显示百分比

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>progress 百分比</title>
</head>
<body>
    <h2>任务进度</h2>
    <form>
        <label for="task-progress">任务完成度:</label>
        <input type="range" id="task-progress" name="progress" min="0" max="100" value="45"
               oninput="updateProgress(this.value)">
        <progress id="progress-bar" value="45" max="100" style="width: 300px;"></progress>
        <output name="percent" for="task-progress">45</output>%
    </form>

    <script>
        function updateProgress(val) {
            document.getElementById('progress-bar').value = val;
        }
    </script>
</body>
</html>

JavaScript 动态更新进度

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>progress 动态更新</title>
    <style>
        body { font-family: sans-serif; max-width: 600px; margin: 40px auto; }
        progress { width: 100%; height: 24px; }
        .controls { margin: 16px 0; display: flex; gap: 8px; }
        button {
            padding: 8px 20px;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
        }
        .btn-start { background: #4a90d9; color: #fff; }
        .btn-reset { background: #ddd; }
    </style>
</head>
<body>
    <h2>模拟任务进度</h2>
    <progress id="my-progress" value="0" max="100"></progress>
    <p><output id="progress-text" for="my-progress">0</output>%</p>

    <div class="controls">
        <button class="btn-start" type="button" id="start-btn">开始</button>
        <button class="btn-reset" type="button" id="reset-btn">重置</button>
    </div>

    <script>
        const progressBar = document.getElementById('my-progress');
        const progressText = document.getElementById('progress-text');
        let timer = null;

        document.getElementById('start-btn').addEventListener('click', function () {
            let value = parseInt(progressBar.value);
            if (timer) clearInterval(timer);

            timer = setInterval(() => {
                value += Math.floor(Math.random() * 5) + 1;
                if (value >= 100) {
                    value = 100;
                    clearInterval(timer);
                    timer = null;
                    this.textContent = '完成';
                    this.disabled = true;
                }
                progressBar.value = value;
                progressText.value = value;
            }, 200);
        });

        document.getElementById('reset-btn').addEventListener('click', function () {
            clearInterval(timer);
            timer = null;
            progressBar.value = 0;
            progressText.value = 0;
            const startBtn = document.getElementById('start-btn');
            startBtn.textContent = '开始';
            startBtn.disabled = false;
        });
    </script>
</body>
</html>

CSS 自定义样式

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>progress CSS 样式</title>
    <style>
        body { font-family: sans-serif; max-width: 600px; margin: 40px auto; }

        /* 默认样式 */
        .progress-default {
            width: 100%;
            height: 20px;
            margin-bottom: 16px;
        }

        /* 自定义颜色(WebKit/Chrome/Safari/Edge) */
        .progress-red {
            width: 100%;
            height: 24px;
            border-radius: 12px;
            overflow: hidden;
        }
        .progress-red::-webkit-progress-bar {
            background: #eee;
            border-radius: 12px;
        }
        .progress-red::-webkit-progress-value {
            background: linear-gradient(90deg, #e74c3c, #c0392b);
            border-radius: 12px;
            transition: width 0.3s ease;
        }

        /* Firefox 自定义 */
        .progress-red::-moz-progress-bar {
            background: linear-gradient(90deg, #e74c3c, #c0392b);
            border-radius: 12px;
        }

        /* 条纹动画 */
        .progress-striped {
            width: 100%;
            height: 24px;
            border-radius: 12px;
            overflow: hidden;
        }
        .progress-striped::-webkit-progress-bar {
            background: #ddd;
            border-radius: 12px;
        }
        .progress-striped::-webkit-progress-value {
            background: repeating-linear-gradient(
                -45deg,
                #4a90d9,
                #4a90d9 10px,
                #357abd 10px,
                #357abd 20px
            );
            border-radius: 12px;
            background-size: 28px 28px;
            animation: move 0.5s linear infinite;
        }
        @keyframes move {
            0% { background-position: 0 0; }
            100% { background-position: 28px 0; }
        }

        /* 不确定进度动画 */
        .progress-indeterminate {
            width: 100%;
            height: 6px;
        }
    </style>
</head>
<body>
    <h2>自定义进度条样式</h2>

    <h3>默认样式</h3>
    <progress class="progress-default" value="60" max="100"></progress>

    <h3>红色圆角</h3>
    <progress class="progress-red" value="75" max="100"></progress>

    <h3>条纹动画</h3>
    <progress class="progress-striped" value="55" max="100"></progress>

    <h3>不确定进度</h3>
    <progress class="progress-indeterminate"></progress>
    <p>加载中,请稍候...</p>
</body>
</html>

实战示例

多任务进度面板

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>多任务进度面板</title>
    <style>
        body { font-family: sans-serif; max-width: 600px; margin: 40px auto; }
        .task {
            margin-bottom: 16px;
            padding: 12px;
            background: #f8f9fa;
            border-radius: 8px;
        }
        .task-header {
            display: flex;
            justify-content: space-between;
            margin-bottom: 8px;
        }
        .task-name { font-weight: 600; }
        .task-percent { color: #4a90d9; font-weight: bold; }
        progress { width: 100%; height: 12px; }
    </style>
</head>
<body>
    <h2>任务进度面板</h2>

    <div class="task">
        <div class="task-header">
            <span class="task-name">文件上传</span>
            <span class="task-percent" id="task1-pct">0%</span>
        </div>
        <progress id="task1" value="0" max="100"></progress>
    </div>

    <div class="task">
        <div class="task-header">
            <span class="task-name">数据处理</span>
            <span class="task-percent" id="task2-pct">0%</span>
        </div>
        <progress id="task2" value="0" max="100"></progress>
    </div>

    <div class="task">
        <div class="task-header">
            <span class="task-name">生成报告</span>
            <span class="task-percent" id="task3-pct">0%</span>
        </div>
        <progress id="task3" value="0" max="100"></progress>
    </div>

    <button type="button" id="run-btn" style="padding: 10px 24px; background: #4a90d9; color: #fff; border: none; border-radius: 6px; cursor: pointer;">
        开始所有任务
    </button>

    <script>
        document.getElementById('run-btn').addEventListener('click', function () {
            this.disabled = true;

            // 模拟三个任务
            simulateTask('task1', 2000);
            setTimeout(() => simulateTask('task2', 3000), 500);
            setTimeout(() => simulateTask('task3', 1500), 1000);
        });

        function simulateTask(id, duration) {
            const bar = document.getElementById(id);
            const pct = document.getElementById(id + '-pct');
            let progress = 0;
            const interval = 50;

            const timer = setInterval(() => {
                progress += Math.random() * 10;
                if (progress >= 100) {
                    progress = 100;
                    clearInterval(timer);
                }
                bar.value = Math.min(progress, 100);
                pct.textContent = Math.round(bar.value) + '%';
            }, interval);

            setTimeout(() => {
                bar.value = 100;
                pct.textContent = '100%';
            }, duration);
        }
    </script>
</body>
</html>

注意事项

不用于度量值

<progress> 表示任务进度(0 到 max),不应表示度量值(如磁盘使用率、分数等)。度量值应使用 <meter> 元素。

内容为降级文本

<progress> 标签之间的内容在不支持该元素的浏览器中显示:

html
<!-- 支持 progress 的浏览器显示进度条 -->
<!-- 不支持的浏览器显示 "60%" 文字 -->
<progress value="60" max="100">60%</progress>

position 属性

通过 JavaScript 可以读取进度百分比:

javascript
const progress = document.getElementById('my-progress');
console.log(progress.value);     // 当前进度值
console.log(progress.max);       // 最大值
// position 属性返回 0-1 之间的比率
console.log(progress.position); // 0.6(表示 60%)

最佳实践

  1. 确定 vs 不确定:明确知道进度时使用确定模式,否则使用不确定模式
  2. 提供文本降级:在标签内放置百分比文本作为降级方案
  3. 配合 output:使用 <output> 显示精确的百分比数字
  4. 自定义样式:使用 CSS 让进度条与页面风格统一
  5. 圆角与动画:添加 border-radius 和过渡动画提升视觉效果

下一节

继续学习:meter 度量元素

参考链接