Recently I saw this interesting animation on CodePen:
The entire animation effect is within a tag, implemented with the help of SVG PATH. Its core lies in the ultimate use of Gradient .
You can see the complete code here -- CodePen DEMO -- to the future 🍻 By Jane Ori ]
The source code is still very, very complex, and superimposed with complex SVG PATH paths.
I tried breaking it down a bit into smaller pieces and re-implementing it in another direction using different advanced CSS techniques. Because the whole process still has a lot of interesting CSS skills, this article will share with you.
Realize the background of the upper part and the sunset
First, let's implement the background and sunset effect of the upper part:
<img width="581" alt="image" src="https://user-images.githubusercontent.com/8554143/187644739-3ea988df-6e78-4936-ad82-ecba5338d303.png">
Everyone can stop and think for a while, here let you do it, how will you do it? How many labels are required?
Ok, here, we use a DOM tag to complete the graph:
<div class="g-bg"><div>
The background color is easy to do, use a radial gradient or a linear gradient:
.g-bg {
background: radial-gradient(circle at 50% 100%, var(--color1), var(--color2));
}
So, to get a simple background:
Well, next, we use one of the pseudo-elements to achieve the effect of the sunset .
.g-bg {
position: absolute;
background: radial-gradient(circle at 50% 100%, var(--color1), var(--color2));
&::before {
content: "";
position: absolute;
bottom: 20%;
left: 10%;
right: 10%;
top: 10%;
background: radial-gradient(circle at 50% 100%, var(--color3), var(--color4) 55%, transparent 55.1%, transparent);
}
}
The effect is as follows:
<img width="585" alt="image" src="https://user-images.githubusercontent.com/8554143/187646274-4f1f070a-9b42-4f80-ac65-e4e2fd886a0a.png">
At this point, I think it is the first trick, which is this line of code background: radial-gradient(circle at 50% 100%, var(--color3), var(--color4) 55%, transparent 55.1%, transparent)
, which is used to achieve a semicircle in a rectangular element through a radial gradient from solid color to transparent color.
Tip 1: You can use radial gradients, in a rectangular DIV element, to achieve a semicircle through the radial gradient from solid color to transparent color .
Let's go ahead and cut this circle to get this effect:
<img width="851" alt="image" src="https://user-images.githubusercontent.com/8554143/187648068-97115342-e98d-4da9-a274-a02a5ae630d4.png">
Note that the place that needs to be cut here is not white, but transparent, which needs to reveal the background color behind.
Undoubtedly, we need to use a mask to do it here, we add a mask to the pseudo-element:
.g-bg {
position: absolute;
background: radial-gradient(circle at 50% 100%, var(--color1), var(--color2));
&::before {
content: "";
position: absolute;
bottom: 20%;
left: 10%;
right: 10%;
top: 10%;
background: radial-gradient(circle at 50% 100%, var(--color3), var(--color4) 55%, transparent 55.1%, transparent);
mask: linear-gradient(to top,
#000 0, #000 10%,
transparent 10%, transparent 13%,
#000 13%, #000 20%,
transparent 20%, transparent 22%,
#000 22%, #000 35%,
transparent 35%, transparent 36%,
#000 36%, #000 100%);
}
}
In this way, we achieve this effect:
<img width="529" alt="image" src="https://user-images.githubusercontent.com/8554143/187648493-be115a64-c57f-4697-98c3-5eff4c042409.png">
Here, leads to the second trick:
Tip 2: Use mask to crop the graphics, and the cropped area will become transparent.
Ok, next, we need to superimpose vertical black stripes on the whole shape. In fact, you can also use a mask, if there is a black background behind the entire graphic.
Of course, we can also use another pseudo-element here, and use it to achieve the vertical black stripes here through repeating-linear-gradient.
Take a look at the code:
.g-bg {
position: absolute;
background: radial-gradient(circle at 50% 100%, var(--color1), var(--color2));
&::before {
content: "";
// code of sun
}
&::after {
content: "";
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
background: repeating-linear-gradient(90deg, transparent 0, transparent 3px, rgba(0,0,0,.5) 4px, rgba(0,0,0,.5) 5px);
}
}
Here, we use repeating-linear-gradient
to quickly create a batch of vertical black stripes to get this effect:
<img width="548" alt="image" src="https://user-images.githubusercontent.com/8554143/187652524-f2aaba8e-08ba-427f-9144-52d07e6dc113.png">
Here, get tip 3.
Tip 3: When you encounter a large number of repeating and regular lines, or block graphics, you should think of using gradients in one DOM instead of multiple DOMs for the first time.
Well, at this point, we have achieved the entire first half.
Reflection using -webkit-box-reflect
With the above foundation, we need to get the complete background:
<img width="577" alt="image" src="https://user-images.githubusercontent.com/8554143/187654739-741fc449-9f95-4918-803a-3f896d7013bc.png">
How to do it? Change the color and re-implement it again? Of course not, here we use the reflection function provided by CSS to quickly complete this operation.
.g-bg {
position: absolute;
background: radial-gradient(circle at 50% 100%, var(--color1), var(--color2));
-webkit-box-reflect: below;
&::before {
content: "";
// ...
}
&::after {
content: "";
// ...
}
}
We add a ---f3d7222cd3fbcdd3219ffb9598b45ea0 .g-bg
to -webkit-box-reflect: below
, which means the reflection below:
<img width="575" alt="image" src="https://user-images.githubusercontent.com/8554143/187655575-acc52b7b-c75e-4861-8997-4f5546f8fd6a.png">
Although it is a copy of the exact same one .g-bg
, it is still very different from the effect we want. What should I do?
Don't worry, -webkit-box-reflect: below
also provides attributes such as reflection offset distance and reflection mask.
We need to add a mask to the reflection below and modify the code of -webkit-box-reflect
:
.g-bg {
position: absolute;
background: radial-gradient(circle at 50% 100%, var(--color1), var(--color2));
-webkit-box-reflect: below -50px linear-gradient(rgba(255, 255, 255, .2), transparent);
&::before {
content: "";
// ...
}
&::after {
content: "";
// ...
}
}
In this way, we get this kind of effect:
<img width="596" alt="image" src="https://user-images.githubusercontent.com/8554143/187661797-9035b246-1b9c-4e98-8589-1aa5b8f26251.png">
Here, the entire graphic is actually translucent. We superimpose a layer of the color gradient we want on the back, and we can use the pseudo element of the body:
body {
&::before {
position: absolute;
content: "";
top: 50%;
left: 0;
bottom: 0;
right: 0;
background: linear-gradient(var(--c5), var(--c6));
}
}
.g-bg {
position: absolute;
background: radial-gradient(circle at 50% 100%, var(--color1), var(--color2));
-webkit-box-reflect: below -50px linear-gradient(rgba(255, 255, 255, .2), transparent);
&::before {
content: "";
// ...
}
&::after {
content: "";
// ...
}
}
The reflection is superimposed with a translucent and gradient background behind it, so we have the overall background effect we want perfectly:
<img width="577" alt="image" src="https://user-images.githubusercontent.com/8554143/187654739-741fc449-9f95-4918-803a-3f896d7013bc.png">
Here, we can lead to tip 4.
Tip 4: -webkit-box-reflect
may come in handy when there are repeated symmetrical shapes.
Line animation with CSS 3D animation
Ok, the main body background is completed, let's try to achieve 3D line animation:
Using CSS 3D, we can achieve such an effect. Let's break it down step by step.
First, we need to implement such a grid effect:
<img width="525" alt="image" src="https://user-images.githubusercontent.com/8554143/187662899-16bb8ac1-1f8b-40b9-a5ee-5b039fa40aa1.png">
Remember tip 3 above? When you encounter a lot of repeating regular lines, or block graphics, you should think of using gradients in one DOM instead of multiple DOMs for the first time.
For this effect, in fact, it is enough to use a gradient with a label group:
<div class="grid"></div>
.grid {
background:
repeating-linear-gradient(var(--c1), var(--c1) 1px, transparent 1px, transparent 20px),
repeating-linear-gradient(90deg, var(--c1), var(--c1) 1px, transparent 1px, transparent 20px);
}
That's all, we get a grid graph.
Ok, next, you need to use transform to make him present a 3D vision:
body {
perspective: 300px;
}
.grid {
position: absolute;
width: 300vw;
height: 600px;
left: -100vw;
top: 55vh;
transform-style: preserve-3d;
background:
repeating-linear-gradient(var(--c1), var(--c1) 1px, transparent 1px, transparent 20px),
repeating-linear-gradient(90deg, var(--c1), var(--c1) 1px, transparent 1px, transparent 20px);
transform: translate3d(0, 0, 0) rotateX(90deg);
transform-origin: 50% 0;
}
The effect is as follows:
<img width="739" alt="image" src="https://user-images.githubusercontent.com/8554143/187663962-cbff25e5-89c1-42ec-a4c8-f2e337a396f9.png">
Since the whole is rotated 90° around the X axis, the top: 55vh
here is very important.
Since the center of rotation is 50% 0
, if it is top: 50vh
, it is equivalent to the whole graphic will be perpendicular to the screen, if top
value is less than 50vh, then the whole grid is Up flip effect:
Next, we need to make it move.
Let's try adding a translateZ motion animation:
.grid {
// ...
animation: move 10s infinite linear;
}
@keyframes move {
0% {
transform: translate3d(0, 0, -600px) rotateX(90deg);
}
100% {
transform: translate3d(0, 0, 600px) rotateX(90deg);
}
}
Take a look at the effect:
There is a very serious problem here, just a single animation, it is difficult to achieve infinite loop connection.
Therefore, we need to add a set of Grid, and the two sets of animations will start successively to realize the connection of the whole animation.
<div class="grid"></div>
<div class="grid"></div>
.grid {
// ...
animation: move 10s infinite linear;
}
.grid:nth-child(2) {
animation: move 10s infinite -5s linear;
}
@keyframes move {
0% {
transform: translate3d(0, 0, -600px) rotateX(90deg);
}
100% {
transform: translate3d(0, 0, 600px) rotateX(90deg);
}
}
We do it this way:
- Two sets of identical animations, the entire displacement length is 1200px, the entire animation lasts for 10s, and the easing is a linear animation
- After the first group started for 5s (just traveled 600px), the second group started again, and the infinite repeated
- The entire 3D animation looks like an infinite loop effect on the near-screen side
- The one used here is
-5s
, which means to start 5s in advance, the actual animation effect will not have a sense of waiting
As follows (here, in order to record GIF, I speed up the animation as a whole):
It can be seen that the animation near the screen is continuous, but there will be some flickering at the far end. Here, technique 5 can be obtained.
Tip 5: Using 2 sets of animations can achieve some continuous effects that cannot be achieved with animations that are effective in a single set
In this way, superimposing the above effect, we get such an effect:
As you can see, it's very close. Currently the line animation still has some jitter in the distance. It just so happens that we are still a little short of the effect of a mountain peak, which can block this flaw.
Mountains effect using box-shadow and SVG filters
OK, finally, we just superimpose a mountain in the middle of the screen.
Here, the original effect uses a long list of exported SVG paths. If we don't have this resource, we just want to simply simulate the effect. Here I give a possible solution.
I first use a rounded rectangle to rotate, and then match the container overflow: hidden
to get a small peak:
<div class="g-mountain"></div>
.g-mountain {
position: absolute;
left: 0;
right: 0;
top: 15%;
bottom: 42%;
overflow: hidden;
&::after {
content: "";
position: absolute;
top: 78%;
background: #011d3f;
width: 15vw;
height: 15vw;
transform: rotate(-45deg);
}
}
Probably something like this:
<img width="208" alt="image" src="https://user-images.githubusercontent.com/8554143/187668374-e2efecd3-6ee5-47f1-98d9-f273123d6734.png">
Well, what if we want to get multiple such graphs repeatedly? Multiple DOMs? No, here we can use box-shadow
to copy itself.
.g-mountain {
// ...
&::after {
content: "";
position: absolute;
top: 78%;
background: #011d3f;
width: 15vw;
height: 15vw;
transform: rotate(-45deg);
box-shadow:
-3vw -3vw, 5vw 5vw,
10vw 10vw 0 3vw, 15vw 20vw 0 4vw,
22vw 22vw 0 6vw, 25vw 30vw 0 12vw,
38vw 36vw 0 1vw, 41vw 39vw 0 3vw,
45vw 45vw 0 2vw, 52vw 52vw 0 4vh,
55vw 55vw 0 1.5vw, 61vw 61vw 0 0.5vw, 68vw 68vw 0 0;
}
}
In this way, we use a tag to implement a series of "mountains":
<img width="832" alt="image" src="https://user-images.githubusercontent.com/8554143/187669194-3dd2983a-bdf6-478a-9eb6-8a12d2d7630c.png">
Here, we get tip 6.
Tip 6: box-shadow
can effectively copy itself, and can use the fourth parameter, diffusion radius, to proportionally enlarge itself.
In fact, here, a relatively rough restoration is completed. Of course, there is a small problem that the peaks should obviously not be straight lines. Can it create a curved outer contour effect?
This is more difficult to achieve using pure CSS, of course, fortunately, here we can use the SVG filter mentioned many times before.
Using feTurbulence
can effectively achieve some wave texture effects. And can be quickly introduced through CSS filter.
<div class="g-mountain"></div>
<svg width="0">
<filter id="filter">
<feTurbulence id="turbulence" type="fractalNoise" baseFrequency=".03" numOctaves="20" />
<feDisplacementMap in="SourceGraphic" scale="30" />
</filter>
</svg>
.g-mountain {
// ...
filter: url('#filter');
&::after {
}
}
Here, what was originally a neat straight line immediately became messy, and it looked more like the outline of a mountain range:
<img width="801" alt="image" src="https://user-images.githubusercontent.com/8554143/187670726-b262c845-51b3-41e2-a49d-61bc66060228.png">
Here, we arrive at Tip 7.
Tip 7: SVG filters can be quickly introduced through CSS filters. SVG filters can achieve some things that CSS can't do, such as some special textures, ripples, smoke particles and other effects.
Ok, so far, we have re-implemented the above animation according to our own understanding, and then made some simple modifications. The final effect is as follows:
CodePen Demo -- Pure CSS to the future
at last
Today's content is a bit more, and the skills are also very fierce. All the techniques in this article have very frequent occurrences in my past articles. If you don't know the details of them, you can search them by keywords in iCSS and make up for them.
Well, this is the end of this article, I hope this article will help you :)
More wonderful CSS technical articles are summarized in my Github -- iCSS , which will be updated continuously. Welcome to click star to subscribe to the collection.
If you have any questions or suggestions, you can communicate more. Original articles are limited in writing and knowledge. If there are any inaccuracies in the article, please let me know.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。