/* perf-progress-bar 组件样式 * 所有 class 以 ppb- 为前缀,避免与页面样式冲突 */ /* ── 外层容器:为刻度留出底部空间 ── */ .ppb-wrap { position: relative; padding-bottom: 10rpx; /* 为刻度行留空间 */ } /* ── 进度条轨道 ── */ .ppb-track { position: relative; width: 100%; height: 14rpx; border-radius: 9rpx; overflow: visible; } /* 底轨背景 */ .ppb-track-bg { position: absolute; top: 0; left: 0; right: 0; bottom: 0; border-radius: 9rpx; background: var(--ppb-track-bg-color, rgba(255, 255, 255, 0.15)); } /* 填充条:控制裁剪宽度 */ .ppb-fill { position: absolute; top: 0; left: 0; bottom: 0; border-radius: 9rpx; overflow: hidden; transition: width 0.4s cubic-bezier(0.34, 1.2, 0.64, 1); box-shadow: 0 0 14rpx rgba(239, 68, 68, 0.45); } /* 全宽渐变层 */ .ppb-gradient-bar { position: absolute; top: 0; left: 0; bottom: 0; width: 100vw; background: linear-gradient( 90deg, #fde68a 0%, #fbbf24 20%, #f97316 45%, #ef4444 70%, #910a0a 100% ); } /* 分隔竖线 */ .ppb-divider { position: absolute; top: 0; width: 8rpx; height: 100%; background: var(--ppb-divider-color, #5381D9); transform: translateX(-50%); pointer-events: none; z-index: 2; } /* ══════════════════════════════════════════════════════ * 高光动画 * ★ 外观旋钮: * --ppb-shine-width : 光束宽度(固定 rpx,不随进度变化) * --ppb-shine-opacity: 峰值亮度 0~1 * --ppb-shine-color : RGB颜色,如 255,220,100=暖黄 * ══════════════════════════════════════════════════════ */ .ppb-shine { --ppb-shine-width: 120rpx; --ppb-shine-opacity: 1.0; --ppb-shine-color: 255, 255, 255; position: absolute; top: 0; left: -130rpx; width: var(--ppb-shine-width); height: 100%; background: linear-gradient( 90deg, transparent 0%, rgba(var(--ppb-shine-color), 0.08) 20%, rgba(var(--ppb-shine-color), var(--ppb-shine-opacity)) 50%, rgba(var(--ppb-shine-color), 0.08) 80%, transparent 100% ); animation: none; pointer-events: none; } .ppb-shine--active { animation: ppbShine 1s linear 1 forwards; } @keyframes ppbShine { 0% { left: -130rpx; opacity: 0; } 5% { opacity: 1; } 95% { opacity: 1; } 100% { left: calc(100% + 10rpx); opacity: 0; } } /* ══════════════════════════════════════════════════════ * 导火索效果 * ★ 外观旋钮: * --ppb-spark-scale : 整体缩放 * --ppb-spark-pole-h: 光柱高度 * ══════════════════════════════════════════════════════ */ .ppb-edge-glow { --ppb-spark-scale: 0.7; --ppb-spark-pole-h: 30rpx; position: absolute; top: 50%; transform: translate(-50%, -50%) scale(var(--ppb-spark-scale)); transform-origin: center center; width: calc(var(--ppb-spark-pole-h) / 2); height: var(--ppb-spark-pole-h); border-radius: 999rpx; background: rgba(255, 255, 255, 1); opacity: 0.25; box-shadow: 0 0 4rpx 2rpx rgba(255, 200, 80, 0.35); animation: none; pointer-events: none; overflow: visible; z-index: 10; transition: opacity 0.1s, box-shadow 0.1s; } .ppb-edge-glow--active { animation: ppbEdgePulse 1s ease-out 1 forwards; } @keyframes ppbEdgePulse { 0% { opacity: 1; box-shadow: 0 0 22rpx 12rpx rgba(255, 255, 255, 0.95); } 15% { opacity: 1; box-shadow: 0 0 26rpx 14rpx rgba(255, 220, 80, 0.90); } 55% { opacity: 0.6; box-shadow: 0 0 12rpx 6rpx rgba(255, 160, 40, 0.60); } 85% { opacity: 0.25; box-shadow: 0 0 4rpx 2rpx rgba(255, 200, 80, 0.35); } 100% { opacity: 0.25; box-shadow: 0 0 4rpx 2rpx rgba(255, 200, 80, 0.35); } } /* 火星粒子基础 */ .ppb-spark { position: absolute; border-radius: 999rpx; pointer-events: none; opacity: 0; top: 50%; left: 50%; animation: none; } .ppb-spark--active { animation-iteration-count: 1; animation-fill-mode: forwards; } /* 粒子1:右上,亮白 */ .ppb-spark-1 { width: 10rpx; height: 10rpx; background: #ffffff; } .ppb-spark-1.ppb-spark--active { animation-name: ppbSpark1; animation-timing-function: linear; } @keyframes ppbSpark1 { 0% { opacity: 0; transform: translate( 0rpx, 0rpx) scale(0.0); } 8% { opacity: 1; transform: translate( 8rpx, -16rpx) scale(1.6); } 25% { opacity: 0.9; transform: translate( 16rpx, -30rpx) scale(1.2); } 45% { opacity: 0.7; transform: translate( 22rpx, -40rpx) scale(0.9); } 62% { opacity: 0.5; transform: translate( 27rpx, -48rpx) scale(0.7); } 76% { opacity: 0.3; transform: translate( 31rpx, -53rpx) scale(0.5); } 87% { opacity: 0.15; transform: translate( 34rpx, -57rpx) scale(0.3); } 100% { opacity: 0; transform: translate( 36rpx, -60rpx) scale(0.1); } } /* 粒子2:右下,橙色 */ .ppb-spark-2 { width: 12rpx; height: 12rpx; background: #fb923c; } .ppb-spark-2.ppb-spark--active { animation-name: ppbSpark2; animation-timing-function: linear; } @keyframes ppbSpark2 { 0% { opacity: 0; transform: translate( 0rpx, 0rpx) scale(0.0); } 12% { opacity: 1; transform: translate( 10rpx, 14rpx) scale(1.5); } 28% { opacity: 0.8; transform: translate( 19rpx, 24rpx) scale(1.1); } 46% { opacity: 0.6; transform: translate( 26rpx, 32rpx) scale(0.8); } 62% { opacity: 0.4; transform: translate( 31rpx, 38rpx) scale(0.6); } 76% { opacity: 0.25; transform: translate( 35rpx, 43rpx) scale(0.4); } 88% { opacity: 0.1; transform: translate( 38rpx, 47rpx) scale(0.25); } 100% { opacity: 0; transform: translate( 42rpx, 56rpx) scale(0.1); } } /* 粒子3:正上,黄色 */ .ppb-spark-3 { width: 8rpx; height: 8rpx; background: #fde68a; } .ppb-spark-3.ppb-spark--active { animation-name: ppbSpark3; animation-timing-function: linear; } @keyframes ppbSpark3 { 0% { opacity: 0; transform: translate( 0rpx, 0rpx) scale(0.0); } 6% { opacity: 1; transform: translate( 4rpx, -22rpx) scale(1.8); } 20% { opacity: 0.9; transform: translate( 7rpx, -36rpx) scale(1.3); } 38% { opacity: 0.7; transform: translate( 9rpx, -48rpx) scale(1.0); } 55% { opacity: 0.5; transform: translate( 10rpx, -57rpx) scale(0.7); } 70% { opacity: 0.3; transform: translate( 11rpx, -63rpx) scale(0.5); } 84% { opacity: 0.15; transform: translate( 11rpx, -68rpx) scale(0.3); } 100% { opacity: 0; transform: translate( 12rpx, -74rpx) scale(0.1); } } /* 粒子4:右斜上,红橙,拖尾 */ .ppb-spark-4 { width: 16rpx; height: 6rpx; background: #ef4444; } .ppb-spark-4.ppb-spark--active { animation-name: ppbSpark4; animation-timing-function: linear; } @keyframes ppbSpark4 { 0% { opacity: 0; transform: translate( 0rpx, 0rpx) rotate( 0deg) scale(0.0); } 10% { opacity: 1; transform: translate( 14rpx, -10rpx) rotate(-20deg) scale(1.4); } 26% { opacity: 0.8; transform: translate( 24rpx, -16rpx) rotate(-30deg) scale(1.0); } 44% { opacity: 0.6; transform: translate( 32rpx, -21rpx) rotate(-38deg) scale(0.75); } 60% { opacity: 0.4; transform: translate( 39rpx, -26rpx) rotate(-45deg) scale(0.55); } 74% { opacity: 0.25; transform: translate( 44rpx, -30rpx) rotate(-50deg) scale(0.4); } 87% { opacity: 0.1; transform: translate( 48rpx, -33rpx) rotate(-53deg) scale(0.25); } 100% { opacity: 0; transform: translate( 58rpx, -40rpx) rotate(-55deg) scale(0.1); } } /* 粒子5:正右,黄白 */ .ppb-spark-5 { width: 10rpx; height: 10rpx; background: #fbbf24; } .ppb-spark-5.ppb-spark--active { animation-name: ppbSpark5; animation-timing-function: linear; } @keyframes ppbSpark5 { 0% { opacity: 0; transform: translate( 0rpx, 0rpx) scale(0.0); } 5% { opacity: 1; transform: translate( 18rpx, 2rpx) scale(1.7); } 20% { opacity: 0.85; transform: translate( 30rpx, 3rpx) scale(1.2); } 38% { opacity: 0.65; transform: translate( 40rpx, 4rpx) scale(0.9); } 55% { opacity: 0.45; transform: translate( 47rpx, 5rpx) scale(0.7); } 70% { opacity: 0.3; transform: translate( 52rpx, 6rpx) scale(0.5); } 84% { opacity: 0.15; transform: translate( 56rpx, 7rpx) scale(0.3); } 100% { opacity: 0; transform: translate( 60rpx, 8rpx) scale(0.1); } } /* 粒子6:右下斜,淡橙 */ .ppb-spark-6 { width: 14rpx; height: 14rpx; background: #fed7aa; } .ppb-spark-6.ppb-spark--active { animation-name: ppbSpark6; animation-timing-function: linear; } @keyframes ppbSpark6 { 0% { opacity: 0; transform: translate( 0rpx, 0rpx) scale(0.0); } 15% { opacity: 0.9; transform: translate( 6rpx, 18rpx) scale(1.5); } 30% { opacity: 0.75; transform: translate( 10rpx, 28rpx) scale(1.1); } 47% { opacity: 0.55; transform: translate( 14rpx, 36rpx) scale(0.85); } 62% { opacity: 0.4; transform: translate( 17rpx, 43rpx) scale(0.65); } 75% { opacity: 0.25; transform: translate( 19rpx, 48rpx) scale(0.5); } 87% { opacity: 0.1; transform: translate( 21rpx, 53rpx) scale(0.35); } 100% { opacity: 0; transform: translate( 24rpx, 64rpx) scale(0.1); } } /* ── 刻度 ── */ .ppb-ticks { position: absolute; width: 100%; top: 100%; margin-top: 6rpx; height: 24rpx; } .ppb-tick { position: absolute; font-size: 16rpx; color: var(--ppb-tick-color, rgba(255, 255, 255, 0.55)); transition: color 0.3s ease, font-weight 0.3s ease; } .ppb-tick--done { color: var(--ppb-tick-done-color, rgba(255, 255, 255, 0.95)); font-weight: 600; } .ppb-tick--highlight { color: rgba(255, 255, 255, 0.85); font-weight: 500; }