本文将讲述如何通过CSS+JS,实现一个3D放映机轮播图,图片以放映机胶片卷轴的形式呈环形排列,模拟真实胶片转动效果,并详细讲解其中的原理和关键代码。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D放映机轮播图title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
background-color: #1a1a1a;
justify-content: center;
align-items: center;
height: 100vh;
}
.film-container {
position: relative;
width: 800px;
height: 500px;
perspective: 1000px;
}
.film-reel {
position: relative;
width: 100%;
height: 100%;
transform-style: preserve-3d;
animation: rotateFilm 20s linear infinite;
}
.film-frame {
position: absolute;
width: 520px;
height: 400px;
left: 50px;
top: 50px;
backface-visibility: hidden;
transform-origin: center;
display: flex;
justify-content: center;
align-items: center;
border: 10px solid #333;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
overflow: hidden;
background-color: #000;
}
.film-frame img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
filter: sepia(30%) contrast(1.2);
}
/* 控制每个胶片帧的位置 */
.film-frame:nth-child(1) {
transform: rotateY(0deg) translateZ(450px);
}
.film-frame:nth-child(2) {
transform: rotateY(60deg) translateZ(450px);
}
.film-frame:nth-child(3) {
transform: rotateY(120deg) translateZ(450px);
}
.film-frame:nth-child(4) {
transform: rotateY(180deg) translateZ(450px);
}
.film-frame:nth-child(5) {
transform: rotateY(240deg) translateZ(450px);
}
.film-frame:nth-child(6) {
transform: rotateY(300deg) translateZ(450px);
}
/* 电影胶片旋转动画 */
@keyframes rotateFilm {
0% {
transform: rotateY(0deg);
}
100% {
transform: rotateY(360deg);
}
}
/* 控制按钮样式 */
.controls {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
z-index: 30;
}
.controls button {
background-color: #333;
color: white;
border: none;
padding: 8px 15px;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
font-size: 14px;
}
.controls button:hover {
background-color: #555;
}
style>
head>
<body>
<div class="film-container">
<div class="film-reel">
<div class="film-frame"><img src="https://picsum.photos/800/400?random=1" alt="Film Frame 1">div>
<div class="film-frame"><img src="https://picsum.photos/800/400?random=2" alt="Film Frame 2">div>
<div class="film-frame"><img src="https://picsum.photos/800/400?random=3" alt="Film Frame 3">div>
<div class="film-frame"><img src="https://picsum.photos/800/400?random=4" alt="Film Frame 4">div>
<div class="film-frame"><img src="https://picsum.photos/800/400?random=5" alt="Film Frame 5">div>
<div class="film-frame"><img src="https://picsum.photos/800/400?random=6" alt="Film Frame 6">div>
div>
<div class="controls">
<button id="playBtn"><i class="fa fa-play">i> 播放button>
<button id="pauseBtn"><i class="fa fa-pause">i> 暂停button>
<button id="speedBtn"><i class="fa fa-tachometer">i> 加速button>
div>
div>
<script>
// 获取元素和变量
const filmReel = document.querySelector('.film-reel');
const playBtn = document.getElementById('playBtn');
const pauseBtn = document.getElementById('pauseBtn');
const speedBtn = document.getElementById('speedBtn');
let rotationSpeed = 20; // 默认速度
let isPlaying = true;
let rotationInterval;
// 更新动画
function updateAnimation() {
filmReel.style.animation = `rotateFilm ${rotationSpeed}s linear infinite`;
}
// 播放/暂停功能
playBtn.addEventListener('click', () => {
if (!isPlaying) {
filmReel.style.animationPlayState = 'running';
isPlaying = true;
}
});
pauseBtn.addEventListener('click', () => {
if (isPlaying) {
filmReel.style.animationPlayState = 'paused';
isPlaying = false;
}
});
// 调整速度功能
speedBtn.addEventListener('click', () => {
rotationSpeed = rotationSpeed > 5 ? rotationSpeed - 5 : 20;
updateAnimation();
});
// 初始化动画
updateAnimation();
script>
body>
html>
<div class="film-container">
<div class="film-reel">
<div class="film-frame"><img src="https://picsum.photos/800/400?random=1" alt="Film Frame 1">div>
<div class="film-frame"><img src="https://picsum.photos/800/400?random=2" alt="Film Frame 2">div>
<div class="film-frame"><img src="https://picsum.photos/800/400?random=3" alt="Film Frame 3">div>
<div class="film-frame"><img src="https://picsum.photos/800/400?random=4" alt="Film Frame 4">div>
<div class="film-frame"><img src="https://picsum.photos/800/400?random=5" alt="Film Frame 5">div>
<div class="film-frame"><img src="https://picsum.photos/800/400?random=6" alt="Film Frame 6">div>
div>
<div class="controls">
<button id="playBtn"><i class="fa fa-play">i> 播放button>
<button id="pauseBtn"><i class="fa fa-pause">i> 暂停button>
<button id="speedBtn"><i class="fa fa-tachometer">i> 加速button>
div>
div>
上述代码中:
film-container
为放映机容器,控制透视距离。.film-reel
作为图片切换放映的实际载体。.film-frame
代表一张图片(胶片)。<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
background-color: #1a1a1a;
justify-content: center;
align-items: center;
height: 100vh;
}
.film-container {
position: relative;
width: 800px;
height: 500px;
perspective: 1000px;
}
.film-reel {
position: relative;
width: 100%;
height: 100%;
transform-style: preserve-3d;
animation: rotateFilm 20s linear infinite;
}
.film-frame {
position: absolute;
width: 520px;
height: 400px;
left: 50px;
top: 50px;
backface-visibility: hidden;
transform-origin: center;
display: flex;
justify-content: center;
align-items: center;
border: 10px solid #333;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
overflow: hidden;
background-color: #000;
}
.film-frame img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
filter: sepia(30%) contrast(1.2);
}
/* 控制每个胶片帧的位置 */
.film-frame:nth-child(1) {
transform: rotateY(0deg) translateZ(450px);
}
.film-frame:nth-child(2) {
transform: rotateY(60deg) translateZ(450px);
}
.film-frame:nth-child(3) {
transform: rotateY(120deg) translateZ(450px);
}
.film-frame:nth-child(4) {
transform: rotateY(180deg) translateZ(450px);
}
.film-frame:nth-child(5) {
transform: rotateY(240deg) translateZ(450px);
}
.film-frame:nth-child(6) {
transform: rotateY(300deg) translateZ(450px);
}
/* 电影胶片旋转动画 */
@keyframes rotateFilm {
0% {
transform: rotateY(0deg);
}
100% {
transform: rotateY(360deg);
}
}
/* 控制按钮样式 */
.controls {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
z-index: 30;
}
.controls button {
background-color: #333;
color: white;
border: none;
padding: 8px 15px;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
font-size: 14px;
}
.controls button:hover {
background-color: #555;
}
style>
在上述代码中:
.film-container
通过 perspective: 1000px
建立 3D 透视效果。.film-reel
使用 transform-style: preserve-3d
保留子元素的 3D 变换。.film-frame
通过 backface-visibility: hidden
避免图片翻转时显示背面,并通过transform-origin: center
确保围绕中心旋转。.film-frame:nth-child
控制每个胶片帧的位置,子元素按60度递增,形成正六边形环形。<script>
// 获取元素和变量
const filmReel = document.querySelector('.film-reel');
const playBtn = document.getElementById('playBtn');
const pauseBtn = document.getElementById('pauseBtn');
const speedBtn = document.getElementById('speedBtn');
let rotationSpeed = 20; // 默认速度
let isPlaying = true;
let rotationInterval;
// 更新动画
function updateAnimation() {
filmReel.style.animation = `rotateFilm ${rotationSpeed}s linear infinite`;
}
// 播放/暂停功能
playBtn.addEventListener('click', () => {
if (!isPlaying) {
filmReel.style.animationPlayState = 'running';
isPlaying = true;
}
});
pauseBtn.addEventListener('click', () => {
if (isPlaying) {
filmReel.style.animationPlayState = 'paused';
isPlaying = false;
}
});
// 调整速度功能
speedBtn.addEventListener('click', () => {
rotationSpeed = rotationSpeed > 5 ? rotationSpeed - 5 : 20;
updateAnimation();
});
// 初始化动画
updateAnimation();
script>
上述代码中:
updateAnimation()
方法动态调整旋转速度。本文主要介绍了如何通过CSS+JS实现一个3D放映机轮播图,在后面的文章中,我会继续探讨其他类型的轮播图,你还知道哪些轮播图?欢迎在评论区留言分享!