The picture slider (also known as a carousel) is available everywhere. There are a lot of CSS tricks to create common sliders where the picture slides from left to right (or vice versa). Many JavaScript libraries also create beautiful sliders with complex animations. In this article, we won't do any of these things.
We will explore some fancy and uncommon pure CSS sliders through a series of articles. If you're tired of seeing the same classic slider, you're in the right place!
In the first post, we will start with what I call the "loop rotation picture slider":
It's cool, right? Let's analyze the code!
If you've followed my series on beautiful picture decor or CSS grids and custom shapes, then you'll know that my first rule is to use as little HTML as possible. I always struggle to find a CSS solution and then mess up the code with a lot of <div> and other stuff. The same rules apply here - our code is nothing more than a series of images in the container.
<p>Suppose we use four pictures: </p>
<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false"><div>
<img alt="" src=""><img alt="" src=""><img alt="" src=""><img alt="" src="">
</div></pre><div class="contentsignin">Copy after login</div></div><div class="contentsignin">Copy after login</div></div><div class="contentsignin">Copy after login</div></div>
<p>That's it! Now let's get into the interesting part of the code. But first, we'll dig into it to understand the logic of how our sliders work. </p>
<h3>How to work? </h3>
<p> This is a video, from which I removed the <code>overflow: hidden
CSS so that we can better understand how the image moves: (The video should be embedded here, but since I can't handle the video, I will describe it in text) The video shows four images rotating counterclockwise over a large circle. All images are the same size (represented by S in the figure). Notice the blue circle, which is the circle that intersects the centers of all images and has a radius (R). We will need this value for our animation later. R equals 0.707 * S. (I will skip the geometric calculations given the equation.)
We will use a CSS grid to place all images in the same area above each other:
.gallery { --s: 280px; /* 控制大小 */ display: grid; width: var(--s); aspect-ratio: 1; padding: calc(var(--s) / 20); /* 我们稍后将看到它的用途 */ border-radius: 50%; } .gallery > img { grid-area: 1 / 1; width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
So far, nothing is too complicated. The tricky part is the animation.
We have discussed rotating a large circle, but in reality, we will rotate each image individually, creating the illusion of a large rotating circle. So let's define an animation m
and apply it to the image element:
.gallery > img { /* 与之前相同 */ animation: m 8s infinite linear; transform-origin: 50% 120.7%; } @keyframes m { 100% { transform: rotate(-360deg); } }
The main trick is to highlight the rows. By default, the CSS transform-origin
property is equal to the center (or 50% 50%), which makes the image rotate around its center, but we don't need to do so. We need the image to rotate around the center of the large circle containing our image, so the new value of transform-origin
.
S Since R is equal to 0.707 * S, we can say that R is equal to 70.7% of the image size. Here is a graph to illustrate how we get a value of 120.7%: (The image should be embedded here, but since I can't handle the image, I will describe it in text) The image shows the geometric relationship of calculating the transform-origin value.
Let's run the animation and see what happens: (The animation effect should be embedded here, but since I can't handle the animation, I'll describe it in text) The animation effect shows that only one image is visible because all images are superimposed together.
We need to delay the animation of each image to avoid this overlap.
<div> <img alt="" src=""><img alt="" src=""><img alt="" src=""><img alt="" src=""> </div>
The situation has improved!
If we hide overflow on the container, we can already see a slider, but we will update the animation slightly so that each image will be visible for a short time before moving.
We will update our animation keyframes to do this:
.gallery { --s: 280px; /* 控制大小 */ display: grid; width: var(--s); aspect-ratio: 1; padding: calc(var(--s) / 20); /* 我们稍后将看到它的用途 */ border-radius: 50%; } .gallery > img { grid-area: 1 / 1; width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
For each 90deg (360deg/4, where 4 is the number of images), we will add a small pause. Each image will remain 5% of the total duration of visible duration (27%-22%, 52%-47%, etc.) before sliding to the next image. I will update cubic-bezier()
with the animation-timing-function
function to make the animation more beautiful: (The animation effect should be embedded here, but since I can't handle the animation, I will omit it)
Now our slider is perfect! Well, almost perfect, because we are still missing the final touch-up: the colorful rounded borders that rotate around our image. We can create it using pseudo-elements on the .gallery
wrapper:
.gallery > img { /* 与之前相同 */ animation: m 8s infinite linear; transform-origin: 50% 120.7%; } @keyframes m { 100% { transform: rotate(-360deg); } }
I created a circle with repeated conical gradients as the background, while using a masking trick that only displays the fill area. Then I apply the same animation defined for the image to it. (Animation effects should be embedded here, but since I can't handle the animation, I will omit it)
We're done! We have a cool loop slider:
It's good to use four images, but it's even better if we can expand it to any number of images. After all, this is the purpose of the picture slider. We should be able to consider N pictures.
To do this, we will make the code more general by introducing Sass. First, we define a variable for the number of images ($n) and we will update each part of our hardcoded number of images (4).
Let's start with delay:
.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 */
The formula for delay is (1 - $i)*duration/$n, which gives us the following Sass loop:
@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); } }
We can also make duration a variable if we really want to. But let's keep on the animation:
.gallery { padding: calc(var(--s) / 20); /* 此处需要填充 */ position: relative; } .gallery::after { content: ""; position: absolute; inset: 0; padding: inherit; /* 继承相同的填充 */ 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); }
Let's simplify it to better view the pattern:
.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 */
The step size between each state is equal to 25%—that is, 100%/4—we add a -90deg angle—that is, -360deg/4. This means we can write the loop like this:
@for $i from 2 to ($n + 1) { .gallery > img:nth-child(#{$i}) { animation-delay: calc(#{(1 - $i) / $n} * 8s); } }
Since each image accounts for 5% of the animation, we change this:
@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); } }
…and this:
<div> <img alt="" src=""><img alt="" src=""><img alt="" src=""><img alt="" src=""> </div>
It should be noted that 5% is any value I selected for this example. We can also set it as a variable to control how long each image should remain visible. I'll skip this for simplicity, but as a homework you can try doing this and share your implementation in the comments!
.gallery { --s: 280px; /* 控制大小 */ display: grid; width: var(--s); aspect-ratio: 1; padding: calc(var(--s) / 20); /* 我们稍后将看到它的用途 */ border-radius: 50%; } .gallery > img { grid-area: 1 / 1; width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
The last point is to update transform-origin
. We will need some geometric skills. The configuration is always the same regardless of the number of images. We place the image (small circle) inside a large circle and we need to find the value of the radius R.
You may not want a boring geometric explanation, so here is how to find R:
.gallery > img { /* 与之前相同 */ animation: m 8s infinite linear; transform-origin: 50% 120.7%; } @keyframes m { 100% { transform: rotate(-360deg); } }
If we express this as a percentage, we get:
.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 */
…This means that the transform-origin
value equals:
@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); } }
We're done! We have a slider for any number of images!
Let's add nine pictures there: (The slider effect of nine pictures should be embedded here, but since I can't handle pictures and animations, I will omit it)
Add as many images and update the $n variable with the total number of images.
With several tricks of using CSS transformation and standard geometry, we created a nice loop slider without much code. The cool thing about this slider is that we don't have to bother copying the image to keep the infinite animation because we have a circle. After the full rotation, we will return to the first image!
The above is the detailed content of CSS Infinite and Circular Rotating Image Slider. For more information, please follow other related articles on the PHP Chinese website!