构建一个交互式的3D旋转轮播图,使用CSS 3D转换和JavaScript增强网页图像或内容的动态展示效果。本文将逐步指导您如何创建这个组件。
我最初研究这个主题时,并不需要一个3D轮播图,而更关注其具体的实现细节。核心技术当然是来自CSS Transforms Module Level 1,但在此过程中,将应用许多其他前端开发技术,涉及CSS、Sass和客户端JavaScript的各个方面。
这个CodePen展示了不同版本的组件,我将向您展示如何构建它们。
为了说明CSS 3D转换的设置,我将向您展示组件的纯CSS版本。然后,我将向您展示如何使用JavaScript增强它,开发一个简单的组件脚本。
关键要点
轮播图的标记
对于标记,组件内的图像被包装在一个<figure></figure>
元素中,它提供了一个基本的框架:
<div class="carousel"> <figure> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> ... <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> </figure> </div>
这将是我们的起点。
轮播图的几何结构
在查看CSS之前,让我们概述一下将在以下部分开发的计划。
<img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/000/173967151412585.jpg" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /></p>
<p>因此,这种多边形的边数与轮播图中的图像数量相同:三个图像的多边形是等边三角形;四个图像是正方形;五个是五边形;等等:</p>
<p>如果轮播图中的图像少于三个怎么办?多边形无法定义,以下过程无法按原样应用。无论如何,只有一个图像的情况相当没用;两个图像稍微更可能,它们可以放置在圆圈上两个直径相对的点上。为简单起见,这些特殊情况未处理,并假定至少有三个图像。但是,相关的代码修改并不难。</p><p>这个虚构的参考多边形将位于3D空间中,垂直于视口的平面,并且其中心向屏幕后推,距离等于其旁心距(多边形的一条边到其中心的距离),如下图所示:</p>
<p><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/000/173967151540038.jpg" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /></p>
<p>这样,当前面向观看者的边将位于屏幕平面z = 0处,而前部图像不受透视缩短的影响,将具有其普通的2D大小。图片中的d字母代表CSS perspective属性的值。</p>
<p><strong>构建轮播图几何结构</strong></p>
<p>在本节中,我将向您展示关键的CSS规则,我将逐步讲解。</p>
<p>在以下代码片段中,使用一些Sass变量来使组件更易于配置。我将使用<code>$n
表示轮播图中的图像数量,使用$item-width
指定图像的宽度。
<figure>
元素是第一个图像的包含框,也是其他图像围绕其定位和转换的参考元素。假设现在轮播图只有一个图像要展示,我可以从大小和对齐开始:
<div class="carousel"> <figure> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> ... <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> </figure> </div>
<figure>
元素具有规定的轮播项目宽度,并且具有与图像相同的高度(它们可以具有不同的尺寸,但必须具有相同的纵横比)。这样,轮播容器高度会根据图像高度自动调整。此外,<figure>
在轮播容器中水平居中。
第一个图像不需要额外的转换,因为它已经在其目标位置,即轮播图的正面。
可以通过对<figure>
元素应用旋转变换来在3D空间中旋转轮播图。此旋转必须围绕多边形的中心进行,因此我将更改<figure>
的默认transform-origin:
.carousel { display: flex; flex-direction: column; align-items: center; > * { flex: 0 0 auto; } .figure { width: $item-width; transform-style: preserve-3d; img { width: 100%; &:not(:first-of-type) { display: none /* Just for now */ } } } }
此值取反,因为在CSS中,z轴的正方向是离开屏幕,朝向观看者。需要括号以避免Sass语法错误。多边形旁心距的计算将在后面解释。
转换了<figure>
元素的参考系统后,整个轮播图可以通过其(新的)y轴旋转来旋转:
.carousel figure { transform-origin: 50% 50% (-$apothem); }
我稍后将返回此旋转的详细信息。
让我们继续进行其他图像的转换。使用绝对定位,图像堆叠在<figure>
内部:
.carousel figure { transform: rotateY(/* some amount here */rad); }
z-index值被忽略,因为这只是后续转换的初步步骤。事实上,现在每个图像都可以围绕轮播图的y轴旋转一个角度,该角度取决于分配图像的多边形边。首先,与<figure>
元素一样,修改图像的默认transform-origin,将其移动到多边形的中心:
<div class="carousel"> <figure> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> ... <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> </figure> </div>
然后,图像可以围绕其新的y轴旋转一个量,该量由($i - 1) * $theta
弧度给出,其中$i
是图像的索引(从1开始),$theta = 2 * $PI / $n
,其中$PI
表示数学常数π。因此,第二个图像将旋转$theta
,第三个旋转2 * $theta
,依此类推,直到最后一个图像旋转($n - 1) * $theta
。
由于嵌套CSS转换的层次性质,在轮播图旋转(即围绕<figure>
修改后的y轴旋转)期间,图像的这种相对排列将被保留。
可以使用Sass @for
控制指令分配此每个图像的旋转量:
.carousel { display: flex; flex-direction: column; align-items: center; > * { flex: 0 0 auto; } .figure { width: $item-width; transform-style: preserve-3d; img { width: 100%; &:not(:first-of-type) { display: none /* Just for now */ } } } }
这是使用for...through
结构而不是for...to
,因为对于for...to
,分配给索引变量$i
的最后一个值将是n-1而不是n。
请注意Sass的#{}
插值语法的两个实例。在第一个实例中,它用于:nth-child()
选择器的索引;在第二个实例中,它用于设置旋转属性值。
计算旁心距
多边形旁心距的计算取决于边数和边的宽度,即取决于$n
和$item-width
变量。公式是:
.carousel figure { transform-origin: 50% 50% (-$apothem); }
其中tan()
是正切三角函数。
这个公式可以通过一些几何和三角学推导出来。在笔的源代码中,此公式未按原样实现,因为正切函数在Sass中不可用,因此使用了硬编码值。相反,该公式将在JavaScript演示中完全实现。
间隔轮播项目
此时,轮播图像并排“缝合”,形成所需的多边形形状。但是在这里,它们紧密地堆积在一起,而在3D轮播图中,它们之间通常会有空间。这种距离增强了3D空间的感知,因为它允许您看到轮播图背面朝后的图像。
可以通过引入另一个配置变量$item-separation
并将其用作每个<img alt="用CSS和JavaScript构建3D旋转的轮播" >
元素的水平填充来可选地添加图像之间的此间隙。更准确地说,取此值的一半作为左填充和右填充:
.carousel figure { transform: rotateY(/* some amount here */rad); }
最终结果可以在以下演示中看到:(此处应插入CodePen链接,展示间隔轮播项目)
图像使用opacity
属性变为半透明以更好地说明轮播结构,并且轮播根元素上的flex布局用于将其在视口中垂直居中。
旋转轮播图
为了方便测试轮播图旋转,我将添加一个UI控件来在图像之间来回导航。(此处应插入CodePen链接,展示旋转轮播图)
我们使用一个currImage
整数变量来指示哪个图像位于轮播图的前面。当用户与上一个/下一个按钮交互时,此变量会增加或减少一个单位。
更新currImage
后,轮播图旋转将通过以下方式执行:
<div class="carousel"> <figure> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> ... <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> </figure> </div>
(此处以及以下代码片段中,使用ES6模板字面量在字符串中插入表达式;如果您愿意,可以使用传统的“ ”连接运算符)
其中theta
与之前相同:
.carousel { display: flex; flex-direction: column; align-items: center; > * { flex: 0 0 auto; } .figure { width: $item-width; transform-style: preserve-3d; img { width: 100%; &:not(:first-of-type) { display: none /* Just for now */ } } } }
旋转是-theta
,因为要导航到下一个项目,需要逆时针旋转,并且这种旋转值在CSS转换中为负值。
请注意,currImage
值不受限于[0, numImages – 1]
范围,而是可以无限增长,在正方向和负方向上都可以。事实上,如果前面的图像是最后一个(所以currImage == n-1
),并且用户单击下一个按钮,如果我们将currImage
重置为0以前进到第一个轮播图像,则旋转角度将从(n-1)*theta
转换为0,这将使轮播图在所有之前的图像上向相反方向旋转。当单击上一个按钮时,如果前面的图像是第一个,则会出现类似的问题。
为了挑剔,我甚至应该检查currentImage
的潜在溢出,因为Number
数据类型不能取任意大的值。这些检查未在演示代码中实现。
使用JavaScript增强
在看到构成轮播图核心的基本CSS之后,现在可以使用JavaScript以多种方式增强组件,例如:
首先,我从样式表中删除与转换原点和旋转相关的变量和规则,因为这些将使用JavaScript完成:(此处应插入更新后的CSS代码)
接下来,脚本中的carousel()
函数负责实例的初始化:
.carousel figure { transform-origin: 50% 50% (-$apothem); }
root
参数指的是保存轮播图的DOM元素。
通常,此函数将是一个构造函数,为页面上的每个轮播图生成一个对象,但在这里我没有编写轮播库,因此简单的函数就足够了。
为了在同一页面上实例化多个组件,代码等待所有图像加载,为window
对象注册load
事件的侦听器,然后为每个具有carousel
类的元素调用carousel()
:
.carousel figure { transform: rotateY(/* some amount here */rad); }
carousel()
执行三个主要任务:
在检查转换设置代码之前,我将介绍一些关键变量以及如何根据实例配置初始化它们:
<div class="carousel"> <figure> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> ... <img src="/static/imghw/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Building a 3D Rotating Carousel with CSS and JavaScript " /> </figure> </div>
图像数量(n)根据<figure>
元素的子元素数量初始化。幻灯片之间的间距(gap)从HTML5 data-gap
属性(如果设置)初始化。背面可见性标志(bfc)使用HTML5的dataset
API读取。这将在稍后用于确定轮播图背面的图像是否可见。
设置CSS转换
设置CSS转换相关属性的代码封装在setupCarousel()
中。此嵌套函数有两个参数。第一个是轮播图中的项目数量,即上面介绍的n变量。第二个参数s是轮播图多边形的边长。正如我前面提到的,这等于图像的宽度,因此可以使用getComputedStyle()
读取其中一个的当前宽度:
.carousel { display: flex; flex-direction: column; align-items: center; > * { flex: 0 0 auto; } .figure { width: $item-width; transform-style: preserve-3d; img { width: 100%; &:not(:first-of-type) { display: none /* Just for now */ } } } }
这样,图像宽度可以使用百分比值设置。
为了保持轮播图自适应,我注册了一个窗口大小调整事件的侦听器,该侦听器再次使用(可能已修改的)图像大小调用setupCarousel()
:
.carousel figure { transform-origin: 50% 50% (-$apothem); }
为简单起见,我没有去抖动大小调整侦听器。
setupCarousel()
做的第一件事是使用传递的参数和前面讨论的公式计算多边形的旁心距:
.carousel figure { transform: rotateY(/* some amount here */rad); }
然后,此值用于修改<figure>
元素的transform-origin
,以获得轮播图的新旋转轴:
.carousel figure img:not(:first-of-type) { position: absolute; left: 0; top: 0; }
接下来,应用图像的样式:
.img:not(:first-of-type) { transform-origin: 50% 50% (-$apothem); }
第一个循环为轮播项目之间的空间分配填充。第二个循环设置3D转换。最后一个循环处理背面,如果在轮播图配置中指定了相关标志。
最后,调用rotateCarousel()
以将当前图像移到前面。这是一个小的辅助函数,给定要显示的图像的索引,它会围绕其y轴旋转<figure>
元素以将目标图像移动到前面。导航代码也使用它来回移动:
.carousel figure img { @for $i from 2 through $n { &:nth-child(#{$i}) { transform: rotateY(#{($i - 1) * $theta}rad); } } }
这是最终结果,一个演示,其中实例化了几个轮播图,每个轮播图都有不同的配置:(此处应插入最终CodePen链接)
来源和结论
在结束之前,我只是想感谢一些用于研究本教程的来源:(此处应列出参考来源)
如果您对代码或轮播图的功能有任何疑问或意见,请随时在下面留言。
关于使用CSS和JavaScript构建3D旋转轮播图的常见问题解答(FAQ)
使您的3D旋转轮播图自适应涉及在CSS中使用媒体查询。媒体查询允许您根据设备的屏幕尺寸为不同的设备应用不同的样式。您可以调整轮播图元素的大小和位置以适应较小的屏幕。此外,还要考虑移动设备的触摸事件,因为它们不像台式机那样具有悬停状态。
是的,您可以向轮播图添加更多幻灯片。在HTML结构中,您可以在无序列表中添加更多列表项。每个列表项代表一个幻灯片。请记住调整CSS中每个幻灯片的旋转角度以正确地在3D空间中定位它们。
可以使用HTML和JavaScript向轮播图添加导航按钮。在您的HTML中,添加两个用于上一个和下一个导航的按钮。在您的JavaScript中,向这些按钮添加事件侦听器。单击时,它们应该更新轮播图的旋转以显示上一个或下一个幻灯片。
当然,您可以使用图像作为幻灯片。不要在CSS中设置背景颜色,而是可以为每个幻灯片设置背景图像。确保图像具有正确的大小和分辨率,以获得最佳视觉效果。
可以使用JavaScript添加自动播放功能。您可以使用setInterval
函数在一段时间后自动更新轮播图的旋转。请记住在用户与轮播图交互时清除间隔,以防止出现意外行为。
是的,您可以使用CSS向轮播图添加过渡效果。transition
属性允许您在指定持续时间内动画化CSS属性的变化。您可以将其应用于transform
属性以动画化轮播图的旋转。
使轮播图无限循环涉及一些JavaScript。当轮播图到达最后一个幻灯片时,您可以将其旋转重置为第一个幻灯片。这给人一种无限循环的错觉。
是的,您可以在幻灯片上添加文本。在您的HTML中,您可以在每个列表项中添加文本元素。在您的CSS中,根据幻灯片的位置定位文本元素并根据需要对其进行样式设置。
可以使用CSS添加淡入淡出效果。您可以将opacity
属性与transition
属性结合使用以动画化淡入淡出效果。根据幻灯片在轮播图中的位置调整其opacity
以创建所需的效果。
是的,您可以使用不同的形状作为轮播图。轮播图的形状由CSS中的transform
属性确定。通过调整transform
属性的值,您可以创建立方体、圆柱体或任何其他3D形状的轮播图。
以上是用CSS和JavaScript构建3D旋转的轮播的详细内容。更多信息请关注PHP中文网其他相关文章!