使用 Lightbox 实现 CSS 和 JS 中的无限圆周运动动画

63 阅读4分钟

概述: 此动画创建了图像以旋转木马形式排列的无限循环运动效果。图像围绕屏幕上的固定点旋转,模拟圆形路径。导航按钮可平滑滚动图像。点击图像可在灯箱中打开放大查看。

HTML结构

容器:包裹整个旋转木马和控件。 导航按钮:两个按钮(上一个和下一个)用于向左或向右旋转旋转木马。 轮播:包含多个 .image-wrapper 元素,每个元素包含一张图片和一个标题。 顶部中心文本:显示当前最接近顶部中心的图像的标题。 灯箱:一种模式覆盖,以较大的形式显示点击的图像,并带有关闭按钮。

⇠ ⇢
× 转存失败,建议直接上传图片文件
CSS 样式

主体使用 flexbox 居中,背景为深色,文字为白色。 轮播和图像使用绝对定位来实现圆周旋转。 平滑变换(0.5秒轻松变换)可实现动画旋转。 导航按钮固定在侧面,背景为半透明。 灯箱默认隐藏,活动时显示为固定覆盖。 默认情况下,除顶部中心附近的标题外,其他标题都是隐藏的。 body { margin: 0; font-family: Arial, sans-serif; display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh; background: #222; overflow: hidden; color: #fff; } .container { position: relative; text-align: center; } .carousel { position: relative; width: 800px; height: 400px; margin-bottom: 20px; } .image-wrapper { position: absolute; top: 150px; left: 350px; width: 100px; height: 100px; transition: transform 0.5s ease; cursor: pointer; } .image-wrapper img { width: 100%; height: 100%; object-fit: cover; border-radius: 10px; } .image-wrapper span { display: none; position: absolute; bottom: -25px; left: 50%; transform: translateX(-50%); background: rgba(0, 0, 0, 0.6); padding: 2px 6px; border-radius: 4px; font-size: 0.9em; } .nav-button { display: flex; align-items: center; position: absolute; top: 50%; transform: translateY(-50%); background: rgba(0, 0, 0, 0.5); border-radius: 10px; font-size: 20px; color: #fff; border: none; padding: 10px 15px; cursor: pointer; z-index: 10; } #prev { left: 10px; } #next { right: 10px; } #top-center-text { text-align: center; font-size: 1.2em; color: #fff; margin-bottom: 20px; } #lightbox { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.8); z-index: 1000; justify-content: center; align-items: center; } #lightbox img { max-width: 50%; max-height: 50%; } #close { position: absolute; top: 20px; right: 20px; color: #fff; font-size: 30px; cursor: pointer; }

JavaScript 功能 关键变量

半径:图像圆形路径的半径(以像素为单位)。 angleStep:圆上每个图像之间的度数步长(30 度)。 currentRotation:旋转木马的当前旋转角度偏移。 规范化旋转 辅助函数确保角度在 -180 度和 180 度之间,以便进行正确的可见性计算 updateCarousel();

此函数: updateCarousel();

计算每个图像的角度加上当前的旋转。 使角度正常化。 根据角度范围设置可见性(-90° 到 90° 可见)。 使用 CSS 变换围绕圆圈旋转每个图像:rotate + translateY 进行径向定位。 跟踪哪个图像最接近顶部中心(角度接近 0°)以更新顶部中心文本中显示的标题。 导航事件监听器 下一个按钮将 currentRotation 减少 angleStep 以顺时针旋转。 上一个按钮将 currentRotation 增加 angleStep 以逆时针旋转。 两者都通过平滑的变换动画触发 updateCarousel()。 灯箱功能

单击图像即可打开包含该图像源的灯箱。 单击关闭按钮或图像外部即可关闭灯箱。 const prevButton = document.getElementById("prev"); const nextButton = document.getElementById("next"); const topCenterText = document.getElementById("top-center-text"); const images = Array.from(document.querySelectorAll(".image-wrapper")); const lightbox = document.getElementById("lightbox"); const lightboxImg = document.getElementById("lightbox-img"); const closeButton = document.getElementById("close");

const radius = 250; const angleStep = 30; let currentRotation = -90;

function normalizeRotation(rotation) { rotation = (rotation + 180) % 360; if (rotation < 0) rotation += 360; return rotation - 180; }

function updateCarousel() { let closestAngle = 180; let topImage = null;

images.forEach((img, index) => { let angle = index * angleStep + currentRotation; angle = normalizeRotation(angle);

const visible = angle >= -90 && angle <= 90;
img.style.visibility = visible ? "visible" : "hidden";
img.style.transform = `rotate(${angle}deg) translate(0, -${radius}px)`;

if (Math.abs(angle) < closestAngle) {
  closestAngle = Math.abs(angle);
  topImage = img;
}

});

// Hide all spans images.forEach((img) => (img.querySelector("span").style.display = "none"));

if (topImage) { const spanText = topImage.querySelector("span").textContent; topCenterText.textContent = spanText; // topImage.querySelector('span').style.display = 'block'; } }

// Next button nextButton.addEventListener("click", () => { currentRotation -= angleStep; images.forEach((img) => (img.style.transition = "transform 0.5s ease")); updateCarousel(); });

// Prev button prevButton.addEventListener("click", () => { currentRotation += angleStep; images.forEach((img) => (img.style.transition = "transform 0.5s ease")); updateCarousel(); });

// Lightbox functionality images.forEach((img) => { img.addEventListener("click", () => { lightbox.style.display = "flex"; lightboxImg.src = img.querySelector("img").src; }); }); closeButton.addEventListener("click", () => (lightbox.style.display = "none")); lightbox.addEventListener("click", (e) => { if (e.target === lightbox) lightbox.style.display = "none"; });

// Initialize updateCarousel();

这种结构允许图像无限循环动画,具有直观的用户控制和可访问的灯箱,以增强观看效果。作者www.lglngy.com