1 the introduction

This issue to share how to use only CSS3, to achieve a single label dynamic sunny, rainy and snow. The key technology is “single label” and “pure CSS”. Take a look at the final result:

<! - fine - >
<div class="weather sunny"></div>
<! - Yin - >
<div class="weather cloudy"></div>
<! Rain -- -- -- >
<div class="weather rainy"></div>
<! -- -- -- > snow
<div class="weather snowy"></div>
Copy the code

Yes, it is so capricious, each GIF has a label, and no image no JS! Let’s look at the technical implementation in detail.

Key CSS3 attributes involved:

  1. Transform: Used for shift, rotate, scale effect
  2. Box-shadow: Use projection to replicate images (key!)
  3. Clip-path: Masks elements based on drawn shapes
  4. Animation: Sets the animation of the element

And the implementation of single tags the most critical :before, :after pseudo-element use.

What can you learn from this sharing?

The biggest one: the alternative gameplay of box-shadow — “Shadow body”.

So let’s go through them one by one.

2 Basic Background

The blue background area in the picture, that’s pretty basic, I don’t need to talk about it.

Set the width and height of the area, background color, and rounded corner effect.

.weather {
    position: relative;
    display: inline-block;
    width: 180px;
    height: 240px;
    background: #23b7e5;
    border-radius: 8px;
}
Copy the code

3 a sunny day

The sunny day icon consists of two elements: the sun and the inner hexagonal sun.

:before, :after Two pseudo-elements can each “add” an element inside the element, and both take advantage of this.

3.1 Drawing the Sun

First, realize the sun with :before.

.sunny:before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(50%, 50%);width: 60px;
    height: 60px;
    background: #F6D963;
    border-radius: 50%;
    box-shadow: 0 0 20px #ff0;
    z-index: 2;
}
Copy the code

Content is used to generate an element.

Position, top, left, and Transform are used to center.

Box-shadow implements the external glow effect. This is just the most basic and most common use of box-shadow.

3.2 Drawing inner hexagons

Implement inner hexagons with :after.

The key to implementation is the use of masks. Draw an inner hexagon with clip-path. This becomes a simple junior high school geometry problem.

The inner hexagon is formed by combining two equilateral triangles.

After merging, we can divide the whole into several identical small equilateral triangles.

Make an auxiliary line in the vertical direction, connecting the top and bottom points in the middle. It is not difficult to find that the “maximum vertical length” is greater than the “maximum horizontal length”.

Given that the side length of a small equilateral triangle is 1 and the center of the inner hexagonal is the origin of the coordinates, the coordinates of each point can be calculated as follows:

To draw the image using clip-path percentage positioning, the next step is to convert the length coordinates to percentage coordinates.

Assume that the maximum length in the vertical direction is 100%, and the center of the inner hexagonal is still the origin of coordinates, and the coordinate values of each point are converted as follows:

Since the origin of clip-path is drawn in the upper left corner, it is positive to the right of the X axis and positive to the bottom of the y axis. I need to do a lower coordinate transformation. That is:

New x value = old x value + 50% New y value = (old y value -50%) * -1

Use the Clip-path polygon method to draw the inner hexagons. The coordinates have been calculated from the steps above.

The style code is as follows:

.sunny:after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    margin: -45px 0 0 -45px; 
    width: 90px;
    height: 90px;
    background: #FFEB3B;
    clip-path: polygon(50%, 0% and 64.43% 25%, 93.3%, 25% and 78.87% 50%, 75%, 93.3% 64.43% 75% and 50% 100%, 75%, 35.57% 6.7% 75% and 21.13% 50%, 6.7%, 25% and 35.57% 25%);z-index: 1;
    animation: sunScale 2s linear infinite;
}
@keyframes sunScale {
    0% {
        transform: scale(1); 50%} {transform: scale(1.1); 100%} {transform: scale(1); }}Copy the code

※ Note: Safari needs to change clip-path to -webkit-clip-path. Because the code takes up too much space, I won’t write it twice.

This is achieved by using clip-path to draw an inner hexagon mask, which turns the yellow background into the final inner hexagon.

Animation realizes the alternating action effect of “zoom in and zoom out” through keyframe animation.

End result:

4 it’s cloudy

Looking at the graph, there are two clouds: white clouds in front and black clouds behind. It seems to be implemented with :before and :after respectively. If you do this, the rain and snow elements in later chapters will have no more pseudo-elements to use. So you can only implement two clouds with one pseudo-element. Here we use the “shadow” of box-shadow!

Since the rain and snow days in the following chapters reuse the cloud style, they are written together, with the code as follows:

.cloudy:before..rainy:before..snowy:before {
    content: "";
    position: absolute;
    top: 50%;
    left: 25%;
    transform: translate(50%, 50%);width: 36px;
    height: 36px;
    background: #fff;
    border-radius: 50%;
    z-index: 2;
}
Copy the code

The real element is a circle. Through box-shodow, projections are used as “doppelgangers”.

Let’s look at the box-shadow properties first:

box-shadow: h-shadow v-shadow blur spread color inset; H-shadow: indicates the horizontal offset of the shadow. V-shadow: Indicates the vertical offset of the shadow. Blur: The distance between gradients (0 means no gradients). Spread: The size of the projection, which controls the size of the shadow body. Color: Projection color, through which to realize the dark clouds behind. Inset: Change to inner shadow. I don’t need it here.

Try making a shadow clone first:

box-shadow: #fff 22px -15px 0 6px;
Copy the code

Continue to copy multiple shadow incarnations, with the complete code of all shadow incarnations as follows:

.cloudy:before..rainy:before..snowy:before {
    content: "";
    position: absolute;
    top: 50%;
    left: 25%;
    transform: translate(50%, 50%);width: 36px;
    height: 36px;
    background: #fff;
    border-radius: 50%;
    box-shadow: 
    	#fff 22px -15px 0 6px.#fff 57px -6px 0 2px.#fff 87px 4px 0 -4px.#fff 33px 6px 0 6px.#fff 61px 6px 0 2px.#ccc 29px -23px 0 6px.#ccc 64px -14px 0 2px.#ccc 94px -4px 0 -4px;
    z-index: 2;
}
Copy the code

The white circles of the five doppelgons (# FFF) and the grey circles of the three doppelgons (# CCC) form two clouds.

Add a “bobbing” effect to the clouds:

.cloudy:before {
    animation: cloudMove 2s linear infinite;
}
@keyframes cloudMove {
    0% {
        transform: translate(50%, 50%); 50%} {transform: translate(50%, 60%); 100%} {transform: translate(50%, 50%); }}Copy the code

5 a rainy day

The cloud code is directly copied from the cloudy day in Chapter 4. Raindrops are implemented using the :after pseudo-element.

First implement a raindrop (temporarily hide the cloud for easy viewing) :

.rainy:after {
	content: "";
    position: absolute;
    top:50%;
    left: 25%;
    width: 4px;
    height: 14px;
    background: #fff;
    border-radius: 2px;
}
Copy the code

Then use box-shadow:

    .rainy:after {
	    content: "";
        position: absolute;
        top:50%;
        left: 25%;
        width: 4px;
        height: 14px;
        background: #fff;
        border-radius: 2px;
+ box-shadow:
+ #fff 25px -10px 0,
+ #fff 50px 0 0,
+ #fff 75px -10px 0,
+ #fff 0 25px 0,
+ #fff 25px 15px 0,
+ #fff 50px 25px 0,
+ #fff 75px 15px 0,
+ #fff 0 50px 0,
+ #fff 25px 40px 0,
+ #fff 50px 50px 0,
+ #fff 75px 40px 0;
    }
Copy the code

Then add the moving effect of rain and modify it as follows:

.rainy:after { ... (abbreviated)+ animation: rainDrop 2s linear infinite;
    }
+ @keyframes rainDrop {
{+ 0%
+ transform: translate(0, 0) rotate(10deg);
+}
{+ 100%
+ transform: translate(-4px, 24px) rotate(10deg);
+ box-shadow:
+ #fff 25px -10px 0,
+ #fff 50px 0 0,
+ #fff 75px -10px 0,
+ #fff 0 25px 0,
+ #fff 25px 15px 0,
+ #fff 50px 25px 0,
+ #fff 75px 15px 0,
+ rgba(255, 255, 255, 0) 0 50px 0,
+ rgba(255, 255, 255, 0) 25px 40px 0,
+ rgba(255, 255, 255, 0) 50px 50px 0,
+ rgba(255, 255, 255, 0) 75px 40px 0;
+}
+}
Copy the code

The animation adds a 10-degree rotation to tilt the raindrops, as well as vertical movement.

The key here is that, although the movement is vertical in nature, in order to look “circular”, you need to make the bottom drop transparent, and adjust the X and Y values so that the final position is exactly the same as the initial position, so that it does not appear “disconnected”.

What we generate are three rows of raindrops, the first row is obscured by clouds, and the next two rows are actually visible. When the first line moves to the second position, the third line is already transparent and invisible, just as the initial state, realizing seamless circular stitching.

Six snow

The difference between a snowy day and a rainy day is to replace the raindrops with circles and cancel the rotation Angle. The code is as follows:

.snowy:after {
    content: "";
    position: absolute;
    top:50%;
    left: 25%;
    width: 8px;
    height: 8px;
    background: #fff;
    border-radius: 50%;
    box-shadow:
        #fff 25px -10px 0.#fff 50px 0 0.#fff 75px -10px 0.#fff 0 25px 0.#fff 25px 15px 0.#fff 50px 25px 0.#fff 75px 15px 0.#fff 0 50px 0.#fff 25px 40px 0.#fff 50px 50px 0.#fff 75px 40px 0;
    animation: snowDrop 2s linear infinite; 
}
@keyframes snowDrop {
    0% {
        transform: translateY(0); 100%} {transform: translateY(25px);
        box-shadow:
        #fff 25px -10px 0.#fff 50px 0 0.#fff 75px -10px 0.#fff 0 25px 0.#fff 25px 15px 0.#fff 50px 25px 0.#fff 75px 15px 0.rgba(255, 255, 255, 0) 0 50px 0.rgba(255, 255, 255, 0) 25px 40px 0.rgba(255, 255, 255, 0) 50px 50px 0.rgba(255, 255, 255, 0) 75px 40px 0; }}Copy the code

7 All source code

The source code is as follows, easy to paste and save as HTML:


      
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>A single tag! Pure CSS dynamic rain and snow</title>
</head>

<body>
    <div class="weather sunny"></div>
    <div class="weather cloudy"></div>
    <div class="weather rainy"></div>
    <div class="weather snowy"></div>
</body>
<style>
.weather {
    position: relative;
    display: inline-block;
    width: 180px;
    height: 240px;
    background: #23b7e5;
    border-radius: 8px;
}
.sunny:before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(50%, 50%);width: 60px;
    height: 60px;
    background: #F6D963;
    border-radius: 50%;
    box-shadow: 0 0 20px #ff0;
    z-index: 2;
}
.sunny:after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    margin: -45px 0 0 -45px; 
    width: 90px;
    height: 90px;
    background: #FFEB3B;
    clip-path: polygon(50%, 0% and 64.43% 25%, 93.3%, 25% and 78.87% 50%, 75%, 93.3% 64.43% 75% and 50% 100%, 75%, 35.57% 6.7% 75% and 21.13% 50%, 6.7%, 25% and 35.57% 25%);z-index: 1;
    animation: sunScale 2s linear infinite;
}
@keyframes sunScale {
    0% {
        transform: scale(1); 50%} {transform: scale(1.1); 100%} {transform: scale(1); }}.cloudy:before..rainy:before..snowy:before {
    content: "";
    position: absolute;
    top: 50%;
    left: 25%;
    transform: translate(50%, 50%);width: 36px;
    height: 36px;
    background: #fff;
    border-radius: 50%;
    box-shadow: 
    	#fff 22px -15px 0 6px.#fff 57px -6px 0 2px.#fff 87px 4px 0 -4px.#fff 33px 6px 0 6px.#fff 61px 6px 0 2px.#ccc 29px -23px 0 6px.#ccc 64px -14px 0 2px.#ccc 94px -4px 0 -4px;
    z-index: 2;
}
.cloudy:before {
    animation: cloudMove 2s linear infinite;
}
@keyframes cloudMove {
    0% {
        transform: translate(50%, 50%); 50%} {transform: translate(50%, 60%); 100%} {transform: translate(50%, 50%); }}.rainy:after {
	content: "";
    position: absolute;
    top:50%;
    left: 25%;
    width: 4px;
    height: 14px;
    background: #fff;
    border-radius: 2px;
    box-shadow:
    	#fff 25px -10px 0.#fff 50px 0 0.#fff 75px -10px 0.#fff 0 25px 0.#fff 25px 15px 0.#fff 50px 25px 0.#fff 75px 15px 0.#fff 0 50px 0.#fff 25px 40px 0.#fff 50px 50px 0.#fff 75px 40px 0;
    animation: rainDrop 2s linear infinite;	
}
@keyframes rainDrop {
    0% {
        transform: translate(0, 0) rotate(10deg); 100%} {transform: translate(-4px, 24px) rotate(10deg);
        box-shadow:
        #fff 25px -10px 0.#fff 50px 0 0.#fff 75px -10px 0.#fff 0 25px 0.#fff 25px 15px 0.#fff 50px 25px 0.#fff 75px 15px 0.rgba(255, 255, 255, 0) 0 50px 0.rgba(255, 255, 255, 0) 25px 40px 0.rgba(255, 255, 255, 0) 50px 50px 0.rgba(255, 255, 255, 0) 75px 40px 0; }}.snowy:after {
    content: "";
    position: absolute;
    top:50%;
    left: 25%;
    width: 8px;
    height: 8px;
    background: #fff;
    border-radius: 50%;
    box-shadow:
        #fff 25px -10px 0.#fff 50px 0 0.#fff 75px -10px 0.#fff 0 25px 0.#fff 25px 15px 0.#fff 50px 25px 0.#fff 75px 15px 0.#fff 0 50px 0.#fff 25px 40px 0.#fff 50px 50px 0.#fff 75px 40px 0;
    animation: snowDrop 2s linear infinite; 
}
@keyframes snowDrop {
    0% {
        transform: translateY(0); 100%} {transform: translateY(25px);
        box-shadow:
        #fff 25px -10px 0.#fff 50px 0 0.#fff 75px -10px 0.#fff 0 25px 0.#fff 25px 15px 0.#fff 50px 25px 0.#fff 75px 15px 0.rgba(255, 255, 255, 0) 0 50px 0.rgba(255, 255, 255, 0) 25px 40px 0.rgba(255, 255, 255, 0) 50px 50px 0.rgba(255, 255, 255, 0) 75px 40px 0; }}</style>
</html>
Copy the code

More exciting portals:

CSS Comic Series tutorials (lectures 1-5)

CSS Comic Series tutorials (lecture 6-10)

CSS Comic Series tutorials (11-15)

Detailed instruction on SVG Interactive Development of wechat Official Account Body Page

Please follow my personal wechat official number to get the latest articles ^_^