图像滑块(也称为轮播)无处不在。 有 很多 CSS 技巧来创建通用滑块 图像从左向右(或相反)滑动的位置。 这是同样的处理 那里有许多 JavaScript 库 创建带有复杂动画的精美滑块。 我们不会在这篇文章中做任何事情。
通过一系列小文章,我们将探索一些奇特且不常见的纯 CSS 滑块。 如果您厌倦了看到相同的经典滑块,那么您来对地方了!
CSS 滑块系列
对于第一篇文章,我们将从我称之为“圆形旋转图像滑块”的东西开始:
酷吧? 让我们剖析代码!
HTML 标记
如果你关注了我的系列 花哨的图像装饰 or CSS 网格和自定义形状,那么您就知道我的第一条规则是尽可能使用最小的 HTML。 在让我的代码变得混乱之前,我总是努力寻找 CSS 解决方案
s 和其他东西。
同样的规则也适用于此——我们的代码只不过是容器中的图像列表。
假设我们正在处理四张图片:
而已! 现在让我们转到代码中有趣的部分。 但首先,我们将深入了解滑块的工作逻辑。
我们如何运作?
这是我删除的视频 overflow: hidden
从 CSS 中我们可以更好地理解图像是如何移动的:
就好像我们的四张图片放在一个逆时针旋转的大圆圈上。
所有图像具有相同的大小(表示为 S
图中)。 请注意蓝色圆圈,它是与所有图像的中心相交且半径为(R
). 稍后我们的动画将需要这个值。 R
等于 0.707 * S
. (我将跳过给出该方程式的几何学。)
让我们写一些 CSS!
我们将使用 CSS网格 将所有图像放在彼此上方的同一区域中:
.gallery {
--s: 280px; /* control the size */
display: grid;
width: var(--s);
aspect-ratio: 1;
padding: calc(var(--s) / 20); /* we will see the utility of this later */
border-radius: 50%;
}
.gallery > img {
grid-area: 1 / 1;
width: 100%;
height: 100%;
object-fit: cover;
border-radius: inherit;
}
到目前为止没有什么太复杂的。 棘手的部分是动画。
我们谈到旋转一个大圆圈,但实际上,我们将单独旋转每个图像,从而产生一个大旋转圆圈的错觉。 所以,让我们定义一个动画, m
,并将其应用于图像元素:
.gallery > img {
/* same as before */
animation: m 8s infinite linear;
transform-origin: 50% 120.7%;
}
@keyframes m {
100% { transform: rotate(-360deg); }
}
主要技巧依赖于突出显示的行。 默认情况下,CSS transform-origin
财产等于 center
(或 50% 50%
) 这使得图像围绕其中心旋转,但我们不需要它来做那个。 我们需要图像围绕中心旋转 大圆圈 包含我们的图像因此新的价值 transform-origin
.
由于 R 等于 0.707 * S
,我们可以说 R
等于 70.7%
的图像大小。 这是一个图来说明我们是如何得到的 120.7%
值:
让我们运行动画看看会发生什么:
我知道我知道。 结果与我们想要的相去甚远,但实际上我们已经很接近了。 看起来那里可能只有一张图片,但不要忘记我们已经将所有图片堆叠在一起。 所有这些都在同时旋转,只有顶部图像是可见的。 我们需要的是延迟每个图像的动画以避免这种重叠。
.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 8s / 4 */
.gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 8s / 4 */
.gallery > img:nth-child(4) { animation-delay: -6s; } /* -3 * 8s / 4 */
情况已经好转了!
如果我们隐藏容器上的溢出,我们已经可以看到一个滑块,但我们将稍微更新动画,以便每个图像在移动之前在短时间内保持可见。
我们将更新我们的动画关键帧来做到这一点:
@keyframes m {
0%, 3% { transform: rotate(0); }
22%, 27% { transform: rotate(-90deg); }
47%, 52% { transform: rotate(-180deg); }
72%, 77% { transform: rotate(-270deg); }
98%, 100% { transform: rotate(-360deg); }
}
对于每一个 90deg
(360deg/4
,其中 4
是图像的数量)我们将添加一个小的停顿。 每个图像将保持可见 5%
在我们滑到下一个之前的总持续时间(27%-22%
, 52%-47%
, ETC。)。 我要更新 animation-timing-function
使用 cubic-bezier()
使动画更漂亮的功能:
现在我们的滑块完美了! 好吧,几乎是完美的,因为我们仍然缺少最后的润色:围绕我们的图像旋转的彩色圆形边框。 我们可以使用伪元素 .gallery
包装器制作它:
.gallery {
padding: calc(var(--s) / 20); /* the padding is needed here */
position: relative;
}
.gallery::after {
content: "";
position: absolute;
inset: 0;
padding: inherit; /* Inherits the same padding */
border-radius: 50%;
background: repeating-conic-gradient(#789048 0 30deg, #DFBA69 0 60deg);
mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
mask-composite: exclude;
}
.gallery::after,
.gallery >img {
animation: m 8s infinite cubic-bezier(.5, -0.2, .5, 1.2);
}
我创建了一个圆圈 重复圆锥渐变 为背景而使用 掩蔽技巧 只显示填充区域。 然后我将我们为图像定义的相同动画应用于它。
我们完了! 我们有一个很酷的圆形滑块:
让我们添加更多图像
使用四张图像很好,但如果我们可以将其缩放到任意数量的图像会更好。 毕竟,这是图像滑块的目的。 我们应该可以考虑 N
图像。
为此,我们将通过引入 Sass 使代码更通用。 首先,我们为图像数量定义一个变量($n
) 并且我们将更新我们硬编码图像数量的每个部分 (4
).
让我们从延迟开始:
.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 8s / 4 */
.gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 8s / 4 */
.gallery > img:nth-child(4) { animation-delay: -6s; } /* -3 * 8s / 4 */
延迟的公式是 (1 - $i)*duration/$n
,这给了我们以下 Sass 循环:
@for $i from 2 to ($n + 1) {
.gallery > img:nth-child(#{$i}) {
animation-delay: calc(#{(1 - $i) / $n} * 8s);
}
}
如果我们真的愿意,我们也可以将持续时间设为一个变量。 但是让我们继续看动画:
@keyframes m {
0%, 3% { transform: rotate(0); }
22%, 27% { transform: rotate(-90deg); }
47%, 52% { transform: rotate(-180deg); }
72%, 77% { transform: rotate(-270deg); }
98%, 100% {transform: rotate(-360deg); }
}
让我们简化它以更好地了解模式:
@keyframes m {
0% { transform: rotate(0); }
25% { transform: rotate(-90deg); }
50% { transform: rotate(-180deg); }
75% { transform: rotate(-270deg); }
100% { transform: rotate(-360deg); }
}
每个状态之间的步长等于 25%
—这是 100%/4
- 我们添加一个 -90deg
角度——这是 -360deg/4
. 这意味着我们可以像这样编写循环:
@keyframes m {
0% { transform: rotate(0); }
@for $i from 1 to $n {
#{($i / $n) * 100}% { transform: rotate(#{($i / $n) * -360}deg); }
}
100% { transform: rotate(-360deg); }
}
由于每张图片都需要 5%
的动画,我们改变这个:
#{($i / $n) * 100}%
…有了这个:
#{($i / $n) * 100 - 2}%, #{($i / $n) * 100 + 3}%
应当指出的是, 5%
是我为这个例子选择的任意值。 我们还可以使它成为一个变量来控制每个图像应该保持可见的时间。 为了简单起见,我将跳过它,但是对于家庭作业,您可以尝试这样做并在评论中分享您的实现!
@keyframes m {
0%,3% { transform: rotate(0); }
@for $i from 1 to $n {
#{($i / $n) * 100 - 2}%, #{($i / $n) * 100 + 3}% { transform: rotate(#{($i / $n) * -360}deg); }
}
98%,100% { transform: rotate(-360deg); }
}
最后一点是更新 transform-origin
. 我们需要一些几何技巧。 无论图像数量多少,配置始终相同。 我们将图像(小圆圈)放在一个大圆圈内,我们需要找到半径值, R
.
您可能不想要无聊的几何解释,所以这就是我们如何找到 R
:
R = S / (2 * sin(180deg / N))
如果我们将其表示为百分比,则可以得出:
R = 100% / (2 * sin(180deg / N)) = 50% / sin(180deg / N)
……这意味着 transform-origin
值等于:
transform-origin: 50% (50% / math.sin(180deg / $n) + 50%);
我们完成了! 我们有一个适用于任意数量图像的滑块!
让我们在那里扔九张图片:
添加任意数量的图像并更新 $n
图像总数的变量。
结束了
通过使用 CSS 转换和标准几何的一些技巧,我们创建了一个不需要大量代码的漂亮的圆形滑块。 这个滑块的妙处在于我们不需要复制图像来保持无限动画,因为我们有一个圆圈。 完整旋转后,我们将回到第一张图片!