这是为您生成的一个可直接运行的HTML文档,它实现了一个带有动画效果和交互控制的进度条案例。

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">进度条 · 灵活动画案例</title>
<!-- 使用优雅柔和的字体 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,400;14..32,500;14..32,600&display=swap" rel="stylesheet">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: linear-gradient(145deg, #f9fafc 0%, #eef2f7 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
font-family: 'Inter', system-ui, -apple-system, sans-serif;
padding: 1.5rem;
}
.card {
max-width: 720px;
width: 100%;
background: rgba(255, 255, 255, 0.75);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
box-shadow: 0 25px 45px -12px rgba(0, 20, 30, 0.15), 0 2px 8px rgba(0,0,0,0.02);
border: 1px solid rgba(255, 255, 255, 0.6);
border-radius: 36px;
padding: 2rem 2rem 2.2rem;
transition: all 0.2s ease;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 1.2rem;
flex-wrap: wrap;
gap: 0.75rem;
}
.card-header h2 {
font-weight: 600;
font-size: 1.5rem;
letter-spacing: -0.01em;
color: #1d2b3f;
display: flex;
align-items: center;
gap: 0.5rem;
}
.card-header h2 span {
background: #d9e2ef;
padding: 0.15rem 0.8rem;
border-radius: 100px;
font-size: 0.8rem;
font-weight: 500;
color: #24425c;
letter-spacing: 0.3px;
}
.percentage-badge {
background: #1d2b3f;
color: white;
padding: 0.4rem 1.2rem;
border-radius: 60px;
font-size: 1.4rem;
font-weight: 600;
box-shadow: 0 4px 12px rgba(29, 43, 63, 0.12);
letter-spacing: -0.5px;
line-height: 1;
display: flex;
align-items: center;
gap: 4px;
}
.percentage-badge small {
font-size: 0.9rem;
font-weight: 400;
opacity: 0.8;
}
/* 进度条主体 */
.progress-shell {
background: #e6ebf2;
border-radius: 200px;
height: 32px;
width: 100%;
padding: 4px;
box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(255,255,255,0.6);
transition: box-shadow 0.1s;
margin-bottom: 1.8rem;
cursor: pointer;
position: relative;
}
.progress-bar {
height: 100%;
width: 0%;
background: linear-gradient(90deg, #3b79c9, #62a0e8 70%, #77b7ff);
border-radius: 200px;
box-shadow: 0 2px 8px rgba(45, 110, 200, 0.25);
transition: width 0.25s cubic-bezier(0.2, 0.8, 0.3, 1);
position: relative;
overflow: hidden;
min-width: 8px;
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 2px;
}
/* 进度条光泽条纹效果 */
.progress-bar::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(180deg, rgba(255,255,255,0.45) 0%, rgba(255,255,255,0) 45%);
border-radius: inherit;
pointer-events: none;
}
/* 追踪点 (支持点击) */
.progress-rail {
position: relative;
margin-bottom: 1.4rem;
}
.track-dots {
display: flex;
justify-content: space-between;
font-size: 0.8rem;
font-weight: 500;
color: #4b5f75;
padding: 0 6px 0 2px;
margin-top: 6px;
user-select: none;
}
.track-dots span {
transition: color 0.2s, font-weight 0.2s;
background: transparent;
padding: 2px 8px;
border-radius: 40px;
}
.track-dots span.active {
color: #1d2b3f;
font-weight: 600;
background: rgba(29, 43, 63, 0.06);
}
/* 控制区域 */
.controls {
display: flex;
gap: 0.6rem;
flex-wrap: wrap;
align-items: center;
margin-top: 0.5rem;
}
button {
border: none;
background: white;
font-weight: 500;
font-size: 0.9rem;
padding: 0.65rem 1.4rem;
border-radius: 80px;
box-shadow: 0 4px 10px -4px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0,0,0,0.02);
display: inline-flex;
align-items: center;
gap: 6px;
color: #1d2b3f;
font-family: inherit;
letter-spacing: 0.2px;
transition: all 0.18s ease;
border: 1px solid rgba(255, 255, 255, 0.7);
cursor: pointer;
background: rgba(255,255,255,0.8);
backdrop-filter: blur(4px);
flex: 1 0 auto;
justify-content: center;
}
button:hover {
background: #ffffff;
box-shadow: 0 8px 16px -8px rgba(20, 80, 150, 0.2);
transform: translateY(-1px);
border-color: #c2d6ed;
}
button:active {
transform: translateY(1px);
box-shadow: inset 0 3px 8px rgba(0,0,0,0.04);
}
button.primary {
background: #1d2b3f;
color: white;
border: none;
}
button.primary:hover {
background: #2d3f57;
}
button.secondary {
background: rgba(29, 43, 63, 0.05);
}
.slider-box {
display: flex;
align-items: center;
gap: 0.8rem;
flex: 2 1 200px;
background: rgba(255,255,255,0.5);
padding: 0.2rem 0.6rem 0.2rem 1rem;
border-radius: 100px;
backdrop-filter: blur(4px);
border: 1px solid rgba(255,255,255,0.2);
}
.slider-box input[type="range"] {
flex: 1;
height: 6px;
-webkit-appearance: none;
background: #d2dbe7;
border-radius: 20px;
}
.slider-box input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 20px;
height: 20px;
background: white;
border-radius: 50%;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
border: 2px solid #1d2b3f;
cursor: pointer;
transition: 0.1s;
}
.slider-box input[type="range"]::-moz-range-thumb {
width: 20px;
height: 20px;
background: white;
border-radius: 50%;
border: 2px solid #1d2b3f;
cursor: pointer;
}
.slider-box span {
min-width: 3rem;
text-align: center;
font-weight: 600;
color: #1d2b3f;
font-size: 0.9rem;
}
.footer-actions {
display: flex;
justify-content: flex-end;
gap: 0.75rem;
margin-top: 0.5rem;
}
.footer-actions button {
flex: 0 1 auto;
padding: 0.5rem 1.2rem;
font-size: 0.85rem;
}
.label-hint {
color: #58718b;
font-size: 0.8rem;
margin-top: 0.8rem;
text-align: right;
opacity: 0.7;
letter-spacing: 0.3px;
}
/* 触摸友好 */
@media (max-width: 520px) {
.card {
padding: 1.5rem;
}
.controls button {
flex: 1 1 35%;
}
.slider-box {
flex: 1 1 100%;
order: 4;
}
}
</style>
</head>
<body>
<div class="card">
<!-- 头部 + 百分比 -->
<div class="card-header">
<h2>
⚡ 任务进度
<span>动态</span>
</h2>
<div class="percentage-badge" id="percentageDisplay">
0<small>%</small>
</div>
</div>
<!-- 进度条 (点击任意位置可按比例跳转) -->
<div class="progress-rail">
<div class="progress-shell" id="progressShell">
<div class="progress-bar" id="progressBar" style="width: 0%;"></div>
</div>
<!-- 刻度指示 -->
<div class="track-dots" id="trackDots">
<span data-value="0">0%</span>
<span data-value="25">25%</span>
<span data-value="50">50%</span>
<span data-value="75">75%</span>
<span data-value="100">100%</span>
</div>
</div>
<!-- 交互控件区 -->
<div class="controls">
<button class="secondary" id="decrBtn">− 10%</button>
<button class="primary" id="resetBtn">重置</button>
<button class="secondary" id="incrBtn">+ 10%</button>
<!-- 滑杆 -->
<div class="slider-box">
<input type="range" id="rangeSlider" min="0" max="100" value="0" step="1">
<span id="sliderValue">0%</span>
</div>
</div>
<!-- 底部辅助操作 -->
<div class="footer-actions">
<button id="loadAssistBtn">🎯 载入75%</button>
<button id="completeBtn">🚀 完成</button>
</div>
<div class="label-hint">
← 点击进度条快速定位 · 拖动滑杆精确控制 →
</div>
</div>
<script>
(function() {
// DOM 元素
const progressBar = document.getElementById('progressBar');
const percentageDisplay = document.getElementById('percentageDisplay');
const rangeSlider = document.getElementById('rangeSlider');
const sliderValue = document.getElementById('sliderValue');
const progressShell = document.getElementById('progressShell');
const trackDots = document.getElementById('trackDots');
const incrBtn = document.getElementById('incrBtn');
const decrBtn = document.getElementById('decrBtn');
const resetBtn = document.getElementById('resetBtn');
const loadAssistBtn = document.getElementById('loadAssistBtn');
const completeBtn = document.getElementById('completeBtn');
// 当前进度 (0-100)
let currentProgress = 0;
// 边界限制
function clamp(value, min = 0, max = 100) {
return Math.min(max, Math.max(min, value));
}
// 核心更新UI: 进度条宽度、百分比文本、滑杆、滑块数值、刻度高亮
function updateUI(progress) {
// 更新宽度
progressBar.style.width = progress + '%';
// 更新数字显示 (整数)
percentageDisplay.innerHTML = Math.round(progress) + '<small>%</small>';
// 更新滑杆值
rangeSlider.value = Math.round(progress);
sliderValue.textContent = Math.round(progress) + '%';
// 更新刻度高亮: 找到最近的刻度值
const dotSpans = trackDots.querySelectorAll('span[data-value]');
let activeValue = null;
let minDistance = Infinity;
dotSpans.forEach(span => {
const val = parseInt(span.dataset.value, 10);
const dist = Math.abs(progress - val);
if (dist < 20) { // 阈值 20,让当前进度附近的高亮更明显 (保留多区间)
if (dist < minDistance) {
minDistance = dist;
activeValue = span;
}
}
});
// 如果进度接近某个刻度 (25/50/75等) 高亮它,否则清空所有高亮
dotSpans.forEach(span => {
span.classList.remove('active');
});
if (activeValue && minDistance <= 10) { // 限制10以内高亮,更干净
activeValue.classList.add('active');
} else {
// 如果精确匹配不到高亮,但可能在25/50/75附近,取消高亮
}
}
// 统一设置进度并更新UI
function setProgress(newValue, updateSlider = true) {
currentProgress = clamp(Math.round(newValue));
updateUI(currentProgress);
}
// 增加/减少
function changeProgress(delta) {
setProgress(currentProgress + delta);
}
// 重置为0
function resetProgress() {
setProgress(0);
}
// 载入指定百分比 (示例: 75)
function loadPreset(value) {
setProgress(value);
}
// ---------- 进度条点击跳转 ----------
function handleProgressClick(event) {
const rect = progressShell.getBoundingClientRect();
const offsetX = event.clientX - rect.left;
const width = rect.width;
if (width <= 0) return;
// 计算百分比 (0-100)
let percent = (offsetX / width) * 100;
percent = clamp(Math.round(percent));
setProgress(percent);
}
// 绑定点击事件到进度条容器(点击空白/进度条都触发)
progressShell.addEventListener('click', handleProgressClick);
// 滑杆事件 (input)
rangeSlider.addEventListener('input', function(e) {
const val = parseInt(e.target.value, 10);
currentProgress = clamp(val);
updateUI(currentProgress);
});
// 按钮事件
incrBtn.addEventListener('click', () => changeProgress(10));
decrBtn.addEventListener('click', () => changeProgress(-10));
resetBtn.addEventListener('click', resetProgress);
loadAssistBtn.addEventListener('click', () => loadPreset(75));
completeBtn.addEventListener('click', () => loadPreset(100));
// 额外: 点击刻度也可以快速定位
trackDots.addEventListener('click', (e) => {
const span = e.target.closest('span[data-value]');
if (!span) return;
const val = parseInt(span.dataset.value, 10);
setProgress(val);
});
// 初始化显示
setProgress(0);
// 添加键盘无障碍: 可以按加减键(演示)
// 此时不加过多功能。
})();
</script>
</body>
</html>
进度条的核心交互与操作
您可以通过多种方式直观地控制进度,其核心交互逻辑清晰明了。
- 进度控制方式:您可以通过点击进度条任意位置直接跳转到对应百分比,或使用滑块进行精细调节,页面上的“+10%”、“-10%”、“重置”、“载入75%”和“完成”按钮则提供了快捷操作。
- 视觉反馈机制:进度条会以平滑动画过渡,且当进度接近25%、50%、75%、100%等刻度时,下方的刻度标记会高亮显示,帮助您快速定位进度。
- 状态同步显示:顶部的百分比数字、控制滑块旁的数值以及进度条本身会实时保持同步,让您对所控制的进度一目了然。