preface
It’s interview season again, so here I am… Hey! ? Sorry, digress… I don’t know what to read when I open the nuggets. I have no choice.
Last week I was reading a lot about plane composition and I drew something like a background pattern with CSS. Here are 12 choices, from easy to hard, from the observer’s point of view. This article contains a lot of pictures and code, so it is long.
⚠ early warning, this article has no detailed explanation of the basic knowledge, but it is recommended to read the article practice while learning, more efficient.
⚠ alert, surprise at the end of the article.
Renderings are displayed
Analysis sequence Introduction
After a rough look at the effect, we give an order to the section of the article according to the number of pattern elements and the degree of element variation, the degree of difficulty of animation, whether there is a clue and other factors. See the following figure for the order. Each section has the source code, you can jump directly to the pattern you want to see through the title.
1. The ring is deformed
<div class="card">
<div class="node" v-for="item in 100"></div>
</div>
<style>// All other card tags use this style. To reduce the length of the article, skip below. .card { width: 200px; height: 200px; display: flex; flex-wrap: wrap; justify-content: center; align-items: center; }</style>
Copy the code
Through the picture animation effect, we can roughly get the animation change mode.
-
Some of the rings change to the length of the two rings and change the background color.
By observing the order of the variable length rings, we can find the rule of “getting longer every three”, and speculate that the nTH-Child (3) selector is used.
Here is the CSS source code.
.card {
justify-content: flex-start;
overflow: hidden;
cursor: pointer;
// Every three elements, then execute the animation, source code and our analysis of the animation order is the opposite, the circle from the length of the shortening, but does not affect
.node {
border: solid 5px #F29338;
border-radius: 50%;
&:nth-child(3n) {
width: 40px;
flex-basis: 40px;
background: #F8C798;
animation: change-circle-width 2s ease alternate infinite;
}
}
}
@keyframes change-circle-width {
from {
width: 40px;
flex-basis: 40px;
background: #F8C798; 60%} {width: 20px;
flex-basis: 20px;
background: transparent;
}
// 60% to 100% of the animation time, the properties are not changed, so the pattern appears to be still.
to {
width: 20px;
flex-basis: 20px;
background: transparent; }}Copy the code
2. Tile in the toilet
<div class="card">
<div class="node" v-for="item in 100"></div>
</div>
Copy the code
It’s the same idea as the previous picture, but with a few more rounded balls.
-
The animation of the ball should include position offsets and color and transparency changes.
-
When the mouse is hovering (note the mouse gesture in the bottom right corner of the image), there is an extra row of small balls that look and behave almost like the previous row of balls.
It is speculated that the second row of balls used the animation-delay effect.
-
Look at the number of balls, okay? There seems to be a problem. The number of balls doesn’t match the number of tiles. There must be some special treatment for the order of the balls.
Here is the CSS source code.
.card {
cursor: pointer;
// Display the second row of small round balls when the mouse hover
&:hover {
.node {
&:nth-child(2n)::after {
visibility: unset; }}}.node {
background: #71A2DB;
outline: solid 1px white;
// 3n+1 is equivalent to 3n when used together
&:nth-child(3n-1),
&:nth-last-child(3n+1) {
background: #C2D7F0;
}
// Remove the last line and the end of each line
&:nth-child(10n)::after,
&:nth-last-child(-n+10)::after {
display: none;
}
&::after {
left: 75%;
top: 75%;
width: 50%;
height: 50%;
border-radius: 50%;
background: white;
animation: card-4-circle-move 1s linear alternate infinite;
}
&:nth-child(2n)::after {
animation: card-4-circle-move-delay 1s linear alternate infinite;
animation-delay:.3s;
visibility: hidden;
}
}
}
@keyframes card-4-circle-move {
from {
left: 45%;
top: 45%;
opacity: 1;
background: white;
}
to {
left: 130%;
top: 130%;
opacity: 0;
background: #F2C07D;
}
}
@keyframes card-4-circle-move-delay {
from {
left: 45%;
top: 45%;
opacity: 1;
background: #F2C07D;
z-index: 2;
}
to {
left: 130%;
top: 130%;
opacity: 0;
background: white; }}Copy the code
3. Triangle and ball prints
<div class="card">
<div class="node" v-for="item in 100"></div>
</div>
Copy the code
At first glance, drawing a circle and a triangle with the pseudo-elements of each node completes the diagram.
That’s not true. Before you scroll down the answer, think about why.
Answer the dividing line, beware of crossing the line:
Observe patterns and HTML code:
-
In terms of each row, each row has 10 triangles, but each row has 9 circles +2 semicircles.
The circle is supposed to be assembled by semicircles, and combined with longitudinal observations, it can be inferred that the circle is composed of four quarter circles.
But you can’t draw a quarter circle with pseudo-elements. If you’re thinking wrong, change your mind.
We guessed that the fake element was a whole circle, and used box-shadow to make 4 copies, which were placed in the four corners of the square. .card or.node use overflow to crop out redundant elements.
-
Let’s look at the triangle.
The drawing method of triangle is more common, and can be drawn with transparent Border + colored Border.
The Angle of the triangle changes regularly, and it can be roughly inferred that the rotation Angle is related to the number of columns.
.card {
overflow: hidden;
cursor: pointer;
// Determine the rotation Angle according to the serial number of the triangle and the modulus of 10
@for $i from 0 through 9 {
.node:nth-child(10n - #{$i})::before {
transform: rotate((-19 + $i) + unquote('deg')); }}// The above list of functions is compiled to form the following list
// .node:nth-child(10n)::before {
// transform: rotate(-19deg);
// }
// .node:nth-child(10n-1)::before {
// transform: rotate(-18deg);
// }
// .node:nth-child(10n-2)::before {
// transform: rotate(-17deg);
// }
// .node:nth-child(10n-3)::before {
// transform: rotate(-16deg);
// }
// .node:nth-child(10n-4)::before {
// transform: rotate(-15deg);
// }
// .node:nth-child(10n-5)::before {
// transform: rotate(-14deg);
// }
// .node:nth-child(10n-6)::before {
// transform: rotate(-13deg);
// }
// .node:nth-child(10n-7)::before {
// transform: rotate(-12deg);
// }
// .node:nth-child(10n-8)::before {
// transform: rotate(-11deg);
// }
// .node:nth-child(10n-9)::before {
// transform: rotate(-10deg);
// }
.node {
background: #F5C1CB;
filter: saturate(1.6);
// The triangle drawn with the pseudo-element Border
&::before {
left: 0;
top: -8px;
border: solid 10px transparent;
border-bottom-color: #D2F3BF;
z-index: 1;
}
// Use the box-shadow property to make three extra copies of the circle
&::after {
left: -5px;
top: -5px;
width: 9px;
height: 9px;
border-radius: 50%;
background: #FBF5C5;
z-index: 0;
box-shadow: 20px 0 #FBF5C5.20px 20px #FBF5C5.0 20px #FBF5C5; }}}Copy the code
4. Tile variation
<div class="card">
<div class="node" v-for="item in 100"></div>
</div>
Copy the code
This diagram should be basically simple. Extra attention should be paid to the placement of the specially colored circles.
-
By looking at the zoom of the grid as the mouse moves, you can infer that each grid consists of four quarter circles and a cross.
The cross is easy to handle, made up of 2*2 pixel pseudo-elements copied by box-shadow.
Based on a quarter circle, it can be inferred that each cell has overflow: hidden style.
-
There are several possible implementations of a particular colored circle.
First, when Scss is compiled, call a random function to change the color of these random position circles.
Second, use the cicada principle or similar to implement CSS pseudo-randomness.
Third, write to death.
Harm ~ here directly on the source code.
.card {
.node {
background: #EE92A5;
overflow: hidden;
transition:.3s;
cursor: pointer;
// Zoom when the mouse hovers over the grid
&:hover {
transform: scale(1.4);
}
// Create a crosshair
&::before {
left: 8px;
top: 8px;
width: 2px;
height: 2px;
background: white;
z-index: 0;
box-shadow: 0 2px white, 2px 0 white, -2px 0 white, 0 -2px white;
}
// Circle structure
&::after {
left: -8px;
top: -8px;
width: 15px;
height: 15px;
border-radius: 50%;
background: #F8C798;
z-index: 0;
box-shadow: 20px 0 #F8C798.20px 20px #F8C798.0 20px #F8C798;
}
// CSS pseudo-randomly sets specific colors for specific elements. In practice, you can adjust the following parameters to achieve the desired effect.
&:nth-child(2n)::after {
background: #E03A5C;
}
&:nth-child(3n-1)::after,
&:nth-child(3n)::after,
&:nth-child(5n)::after,
&:nth-child(6n)::after,
&:nth-child(7n-3)::after {
background: #F8C798}}}Copy the code
5. Mountains and clouds
<div class="card">
<div class="node" v-for="item in 100"></div>
</div>
Copy the code
This pattern, well… Be reasonable, who can tell what this is! In fact, I thought to myself, if the toy was not painted by myself, I guess I could not understand the pattern ~~ (world of mortals) ~~, but I still have a serious scratch.
-
Triangles, easy to do, pseudo elements. As for the color, you can copy the CSS pseudo-random idea of the previous image. As for the mountain animation, it’s hard to determine if the mountain is moving or if the mountain is moving with other elements.
-
Now look at the horizontal line. No, there are so many horizontal lines and vertical lines in this diagram. Which one is a fake element and which one is not?
Guess, horizontal and vertical lines are the Outline of the grid. No, the Outline can only be a square.
Could that be Border? It can be seen from the observation that the edges of these horizontal lines are semi-transparent pixels, and the triangle can be drawn with Border. It is speculated that the horizontal lines and vertical lines are the Border of the rounded rectangular lattice, which is partially obscured by the white Border of the pseudo-element forming the triangle.
-
Continue to look at the lines and find that some horizontal lines will disappear, some horizontal lines will only shorten but will not disappear, and all vertical lines will only shorten but will not disappear.
From the fact that the lengthening of the vertical line must be accompanied by the shortening or disappearance of the horizontal line, it is speculated that the lattice is experiencing a change in height, not displacement. Further speculation that the triangle may be following the lattice.
Furthermore, according to the vertical direction of the horizontal line between the two mountains and the movement trend of the mountain is the same, it is speculated that the horizontal line in the picture is the upper part of the grid rather than the lower part, which is covered.
The mountain supposedly hides the bottom of the grid, but this is not consistent with observation, because as the mountain moves upward, the vertical line expands and shrinks. The disappearance of part of the edge of the grid is not obscured by the Border of the pseudo-element that makes up the mountain, but by another pseudo-element, also roughly rectangular.
-
The grid is tied to the Flex layout of align-items: Center, and the triangle and another pseudo-element that looks like a rectangle move with the grid.
… Breathe a sigh of relief, if the above do not understand the words, or look at the following picture. This is what it looks like without the white mask.
(Somebody give me a name)
Here is the CSS source code.
.card {
cursor: pointer;
// The horizontal and vertical lines are not the Border of the node, but the background color + mask
// The grid will change in height according to the animation
.node {
background: #A45963;
border-radius: 90%;
animation: card-1 .4s ease alternate infinite;
// Grid animation delay processing
&:nth-child(2n) {
animation-delay:.2s;
}
&:nth-child(3n) {
animation-delay:.3s;
}
&:nth-child(4n) {
animation-delay:.3s;
}
// Mountain color processing
&:nth-child(2n)::before {
border-bottom-color: #F5CB6C;
}
&:nth-child(3n)::before {
border-bottom-color: #F5856C;
}
&:nth-child(4n)::before,
&:nth-child(5n)::before,
&:nth-child(6n)::before,
&:nth-child(7n)::before,
&:nth-child(8n)::before,
&:nth-child(9n)::before,
&:nth-child(10n)::before {
border-bottom-color: #D2F3BF;
}
// The composition of the mountain
&::before {
left: 0;
top: -5px;
border: solid 10px transparent;
border-bottom-color: #D2F3BF;
z-index: 2;
}
// White mask
&::after {
left: 1px;
top: 1px;
width: 19px;
height: 18px;
background: white;
}
// This is a special treatment to reduce the length of the white mask by 1 pixel to show the last column of pixels of the background color for each row of cells
&:nth-child(10n)::after {
width: 18px;
}
}
}
@keyframes card-1 {
from {
height: 19px;
}
to {
height: 8px; }}Copy the code
Cactus growing on ice cliffs
<div class="card">
<div class="node" v-for="item in 100"></div>
</div>
Copy the code
This is an easy picture.
-
The recognizable grid consists of horizontal and dashed lines and background colors.
It is easy to know that the cylindrical “cactus” is cut from each grid individually.
Animations that change from semicircle to square can be cropped by clip-path property, and vertical lines and horizontal lines are presumed to be pseudo-element drawings respectively.
Here is the CSS source code.
.card {
.node {
background: #71A2DB;
// Add animation for some cactuses
&:nth-child(3n)::after,
&:nth-child(3n+2)::after,
&:nth-child(5n-3)::after,
&:nth-child(6n-2)::after,
&:nth-child(7n+1)::after {
animation: card-7-grow .6s ease alternate infinite;
}
// Some cactuses do not need to be animated
&:nth-child(3n-1)::after,
&:nth-child(3n)::after,
&:nth-child(5n)::after,
&:nth-child(6n)::after,
&:nth-child(7n-3)::after {
clip-path: circle(75% at 0 50%);
animation: none;
}
// The background color + box-shadow is used. You can also use Border + box-shadow to draw lines
&::before {
top: 1px;
left: 0px;
width: 100%;
height: 1px;
background: white;
box-shadow: 0 2px white, 0 4px white, 0 6px white, 0 8px white, 0 10px white, 0 12px white, 0 14px white, 0 16px white, 0 18px white;
}
&::after {
top: 0;
left: 1px;
width: 1px;
height: 100%;
background: white;
box-shadow: 2px 0 white, 4px 0 white, 6px 0 white, 8px 0 white, 10px 0 white, 12px 0 white, 14px 0 white, 16px 0 white, 18px 0 white;
transition:.6s; }}// All lines are displayed when the mouse is hovering.
&:hover {
.node {
&::after {
animation: none;
clip-path: circle(150% at 0% 50%);
}
}
}
}
@keyframes card-7-grow {
from {
clip-path: circle(50% at 0 50%); 50%} {clip-path: circle(50% at 0 50%);
}
to {
clip-path: circle(150% at 0 50%); }}Copy the code
7. No Name 2
This trick is an updated version of the previous diagram, and the trick might be to guess that the pseudo-element is a point, not a line, and then use the empty pseudo-element to construct something else in the rhombus.
.card:nth-child(8) {
.node {
border: solid 8px #71A2DB;
border-top: 0;
border-left: 0;
background: #71A2DB;
clip-path: polygon(50% 0.100% 50%.50% 100%.0% 50%);
transition:.3s;
cursor: pointer;
// Remove the Border from a section of the grid
&:nth-child(3n-1),
&:nth-child(3n),
&:nth-child(5n),
&:nth-child(6n),
&:nth-child(7n-3) {
border: none;
clip-path: circle(50%);
&:hover {
clip-path: circle(30%); }}// Cut a portion of the grid into diamond areas. The four clip-path values correspond to the four vertex positions of the diamond.
&:nth-child(2n),
&:nth-child(3n) {
border: solid 8px #CCDDF2;
clip-path: polygon(50% 0.100% 50%.50% 100%.0% 50%);
}
&::before {
top: 1px;
left: 0px;
width: 100%;
height: 1px;
background: white;
box-shadow: 0 2px white, 0 4px white, 0 6px white, 0 8px white, 0 10px white, 0 12px white, 0 14px white, 0 16px white, 0 18px white;
}
&::after {
top: 0;
left: 1px;
width: 1px;
height: 100%;
background: white;
box-shadow: 2px 0 white, 4px 0 white, 6px 0 white, 8px 0 white, 10px 0 white, 12px 0 white, 14px 0 white, 16px 0 white, 18px 0white; }}}Copy the code
8. Squeeze ice cream
﹏⊙, I don’t mean to be so gross, because he is using the CSS Contrast filter, which increases contrast and brightening.
The blending effect works like this: Apply a Contrast filter on the parent element and a blur filter on the child element, and you will find that the child elements will merge when they are close to each other.
In addition, “CSS Secret” also mentioned a way to use Background gradient overlay to create an Image border, you can also try the following (advertising: Come to Lionad’s all-dry communication group 805392878, where you can find all kinds of books and interesting things)
So let’s just give it to the code.
// You can see that the parent element uses the filter: Contrast
.card {
position: relative;
box-sizing: border-box;
flex-direction: column;
justify-content: flex-end;
align-items: center;
border: solid .5em transparent;
border-image: 8 repeating-linear-gradient(-45deg.#F5E66C 0.#F5E66C .5em, transparent 0, transparent 1em.#DA60D2 0.#DA60D2 1.5 em, transparent 0, transparent 2em);
background: white;
cursor: pointer;
filter: contrast(10);
// Set the background color and animation delay for each grid
$background: (#DA60D2.#E7667E.#E7667E.#F5866C.#F5866C.#F5E66C);
@for $i from 1 through 6 {
.node:nth-child(#{$i{})width: (80- (10 * ($i - 1)))+unquote('px');
animation: card-6 .8s ease-in (0.1*$i)+unquote('s') alternate infinite, card-6-margin .8s ease-in alternate infinite;
background: nth($background.$i); }}// Add a blur filter to the grid
.node {
flex-basis: 30px;
margin-top: -15px;
width: 30px;
height: 50px;
filter: blur(5px);
}
// Pause the animation while the mouse is hovering. I need to make the font thicker due to the melting effect of the child elements
&:hover {
&::before {
content: "Paused";
position: absolute;
left: 5px;
top: 5px;
font-weight: bolder;
}
.node {
animation-play-state: paused;
}
}
@keyframes card-6 {
from {
border-radius: 50%;
}
to {
width: 80px;
border-radius: 0;
}
}
@keyframes card-6-margin {
from {
margin-top: -13px;
}
to {
margin-top: 0px; }}}Copy the code
9. Lionad
The end is near. Hang in there! W (゚ д ゚) W
<div class="card 5">
<div class="node" />
</div>
Copy the code
This is the first time we’ve seen a moving background, but this image is simple to compose. Here’s the analysis.
-
All Background movement is done by CSS Animation + Background-*. The Background gradient of this figure is a simple 45deg of two texture gradients. It is assumed that the Background is shifted by Animation + background-position.
-
Looking at the Text section, easy to get Text is made up of a background with a gradient of 180deg + text-shadow.
Can text use gradient background? Yes, the function of clipping text to the Background pattern can be realized through background-clip.
Since the text-shadow color is darker than the gradient, but the observation shows that the text-shadow is not clipped into the font, it is inferred that the Text should consist of two pseudo-elements. Pseudo-elements with background-clip attributes have a higher hierarchy than those with text-shadow.
-
Finally, there are two horizontal lines below the text. Border-image: border-image; background-image: border-image; box-shadow: border-image; border-image: border-image
Look at the source code.
.card {
background: linear-gradient(45deg.#F5CB6C 0%.#F5CB6C 20%.#F5856C 20%.#F5856C 45%.#F5CB6C 45%.#F5CB6C 70%.#F5856C 70%.#F5856C 95%.#F5CB6C 95%.#F5CB6C 100%);
background-size:30px 30px;
background-position:0 0;
animation: card-5 1s infinite linear;
cursor: pointer;
.node {
// Use background-clip pseudo-elements
&::before {
content: "Lionad";
left: -1.5 em;
top: -.7em;
font-size: 50px;
font-family: didot;
font-weight: bolder;
color: transparent;
background: linear-gradient(180deg.#F5CB6C.#F5856C);
background-size: 1px 2px;
background-clip: text;
-webkit-background-clip: text;
z-index: 2;
}
// Produce a pseudo-element for text-shadow
&::after {
content: "Lionad";
left: -1.5 em;
top: -.7em;
font-size: 50px;
font-family: didot;
font-weight: bolder;
color: transparent;
text-shadow: 4px 4px 0px #F5856C;
box-shadow: 0 5px 0px #F5CB6C.0 12px 0px #F5856C;
}
}
@keyframes card-5 {
0%{
background-position: 0 0;
}
100%{
background-position: 30px 0; }}}Copy the code
10. & 11. A kaleidoscope
<div class="card 10"></div>
<div class="card 11"></div>
Copy the code
The idea behind putting these two together is the same. To be honest, the first time I saw this pattern, I was also confused by the inexplicable color changes, so here is the principle.
-
Both images are painted with gradients. If you look closely, you can see that the patterns on the left and right are stacked with three gradients.
The difference is that the smallest Gradient on the left is the Radial Gradient, while the one on the right is the conic-gradient, which can be used to draw pie charts.
-
Baffling color transformations (left center) use the CSS Blending-mode effect, which computes the resulting color when two colors are stacked together, and is understood as a filter.
-
Change background-position (left) and background-size (right)
Here is the source code.
// The style code on the right
.card {
// There are three background gradients, two taper gradients and one radiation gradient
background-image:
repeating-conic-gradient(red 50%.#E1F5C4 60%),
repeating-conic-gradient(red 50%.#E1F5C4 60%),
radial-gradient(
gold 0%, gold 35%,
red 35%, red 40%,
orangered 40%, orangered 50%,
gold 50%, gold 60%,
yellowgreen 60%, yellowgreen 70%,
skyblue 70%, skyblue 80%,
steelblue 80%, steelblue 90%,
violet 90%
);
// Set blend mode for each layer of gradient separately
background-blend-mode:
lighten,
overlay,
lighten;
// Set the background size for each layer of gradient separately (40px because it is exactly divisible by the 200px box)
background-size:
40px 40px.6em 6em.8em 8em;
background-position: 50% 50%;
transition:.45s ease-in;
cursor: pointer;
// When the mouse hover, change the gradient size
&:hover {
background-size:
40px 40px.4em 4em.12em 12em; }}Copy the code
12. ト raijin-sauce (Tiger)
It’s a whole picture. What’s the big deal?
No, it’s not a picture.
You think there’s an outer chain? No, there isn’t. This is ト raimsauce drawn only with box-shadow.
Its CSS code looks like this:
/ / gray Border
.card {
justify-content: flex-start;
align-items: flex-start;
border: solid 10px #eee;
box-sizing: border-box;
overflow: hidden;
/ / ト ラ sauce
.node {
width: 1px;
height: 1px;
box-shadow:??????? You guess, try to guess how long it goes back here}}Copy the code
As for the specific principle, harm, see my nuggets last article.
exercises
Finally, here are a few exercises that need a little thought for those of you who still have a fighting spirit. ~ ~.
- ト raimjam, use box-shadow + CSS Animation to play GIF
- Cactus growing on ice Cliff, can you make these cactus grow longer than two grids?
Oh, and don’t ask me what these exercises are for.
These exercises are just like the patterns I drew — I don’t know what they are for, just for fun.
On the other hand, the old guys on the Nuggets are all technical players, and the daily interview articles are too rigid. All don’t whole some fancy things, no wonder can’t find female ticket ~~ (if have the same, please take a seat, manual dog head ( ̄ε(# ̄)) ~~.
LAST BUT IMPORTANT
Like, pay attention to, comment three times, three days later from the nuggets article comments lucky draw a copy of “beyond ordinary Layout design”
This is a good case study for typography.
Front end engineers also learn to design yo ~ ω ̄(ω ̄ “)ゝ
To read more
Relevant websites or reference materials used in writing this article
- CSS Doodle: The ultimate solution to CSS Patterns
- NIPPON COLORS: A great Japanese color matching site
- OXXO STUDIO: A very high quality front-end blog, which is where the effect in Squeeze Ice Cream comes from
- Code Pen@jiaqiankOH: This page has various gradients
- Patternify: Interesting pixel background generation site, finally not having to write code harm…
- CSS3 Patterns: “CSS Secrets” by the author of CSS Patterns website, I don’t have to say more…
My Blog has source code Lionad’s Blog.
Reprint at will, indicate the source of nuggets and name Lionad.