
本文详解如何使用原生 css 动画 + javascript(或轻量库)实现类似 soto.shinfuji.co.jp 的平滑左→右背景滑动过渡,并叠加视差式缩放淡出效果,无需依赖重型框架。
要复现 soto.shinfuji.co.jp 那种极具沉浸感的背景轮播——即当前图从满屏略缩放+淡入,上一张图向左平滑滑出并同步缩小淡出——关键不在于更换 Slider 库,而在于精准控制 transform、scale、opacity 的组合动画时序。Slick Slider 本身完全支持该效果,但需深度定制 beforeChange 和 afterChange 回调 + 自定义 CSS 过渡类,而非仅靠 cssEase。
以下是一个轻量、高性能、无额外依赖的实现方案(兼容现代浏览器):
✅ 核心思路
- 使用 position: absolute 叠加多张背景图(推荐 3 张:prev / current / next)
- 每张图默认 transform: scale(1.05)(轻微放大以预留缩放空间),opacity: 1
- 切换时:
- 当前图 → 向左位移 + scale(1) + opacity: 1
- 下一张图 → 从右侧进入(translateX(100vw))→ scale(1.05) → opacity: 0 → 过渡为 translateX(0), scale(1), opacity: 1
- 上一张图 → 向左移出 + scale(0.95) + opacity: 0
? 示例代码(纯 CSS + 原生 JS)
/* CSS */
.bg-slider {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.slide {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
background-size: cover;
background-position: center;
opacity: 0;
transform: translateX(100vw) scale(1.05);
transition: transform 1.2s cubic-bezier(0.6, -0.28, 0.735, 0.045),
opacity 1.2s ease-out,
scale 1.2s cubic-bezier(0.6, -0.28, 0.735, 0.045);
}
.slide.active {
opacity: 1;
transform: translateX(0) scale(1);
}
/* 可选:添加 subtle parallax on scroll */
.slide::before {
content: '';
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
background: inherit;
background-size: cover;
z-index: -1;
transform: scale(1.1); /* subtle zoom layer */
}// JS 控制逻辑(自动轮播 + 手动切换)
const slider = document.getElementById('bgSlider');
const slides = Array.from(slider.querySelectorAll('.slide'));
let currentIndex = 0;
let isTransitioning = false;
function goToSlide(index) {
if (isTransitioning || index === currentIndex) return;
isTransitioning = true;
// 移除 active 类
slides.forEach(s => s.classList.remove('active'));
// 设置新 slide 为 active
slides[index].classList.add('active');
// 重置其他 slide 初始状态(右侧待入场)
slides.forEach((s, i) => {
if (i !== index) {
s.style.transform = 'translateX(100vw) scale(1.05)';
s.style.opacity = '0';
}
});
// 触发重排,确保 transition 生效
void slider.offsetWidth;
// 恢复状态
setTimeout(() => {
isTransitioning = false;
}, 1200);
}
// 自动轮播
setInterval(() => {
currentIndex = (currentIndex + 1) % slides.length;
goToSlide(currentIndex);
}, 5000);
// 手动导航示例(可扩展为按钮/键盘)
document.addEventListener('keydown', e => {
if (e.key === 'ArrowRight') {
currentIndex = (currentIndex + 1) % slides.length;
goToSlide(currentIndex);
} else if (e.key === 'ArrowLeft') {
currentIndex = (currentIndex - 1 + slides.length) % slides.length;
goToSlide(currentIndex);
}
});⚠️ 注意事项
- 性能优先:所有动画属性均基于 transform 和 opacity,确保 GPU 加速;
- 图片优化:使用 object-fit: cover 或 background-size: cover 并配合 srcset 响应式加载;
- 无障碍友好:添加 aria-live="polite" 和暂停轮播按钮(prefers-reduced-motion 检测);
- Slick 替代方案? 若坚持用 Slick,需禁用默认动画(fade: false, cssEase: 'none'),改用 beforeChange 手动添加 class 控制缩放/位移,复杂度反而更高;
- 移动端适配:建议禁用 touchMove 干扰,或监听 touchstart/touchend 实现手势滑动。
✅ 总结:真正流畅的“缩放+滑动”背景轮播,本质是多层 DOM + 精确时序的 CSS 过渡,而非库功能堆砌。上述方案体积










