preface

This article is for the second part of “CSS Revealed” – Shape notes, introduces adaptive ellipses, parallelograms, prismatic images, corner effects, trapezoidal tabs, simple pie chart implementation principles, and in each section attached with personal code links. In this paper, various schemes are given for the realization of various shapes, and we have to sigh with the convenience brought by the emergence of new attributes (such as Clip-Path and Conic-gradient), in which Conic-gradient is absolutely excellent in the realization of pie charts, which is strongly recommended ~

The following is an overview of the brain map to help you comb through your knowledge. Its bid ♥ part for some better program, can focus on learning.

1. Adaptive ellipses

Background Basic usage of the border-radius attribute

The principle of

Three tips for border-radius:

  1. Border-radius can specify horizontal and vertical radii separately by separating the two values with a slash (/);
  2. Border-radius can accept both length and percentage values;
  3. Border-radius is the shorthand attribute, which can be written as four values separated by Spaces that are applied clockwise to each corner of the element starting at the top left corner.
border-radius: horizontal left upper horizontal right upper horizontal right lower horizontal left/vertical left upper vertical right upper vertical right lower vertical left;Copy the code

case

With that knowledge we can easily do adaptive ellipses. The following code details are here.

1. Adaptive ellipse:

Using percentage values resolves based on the size of the element for adaptive purposes.

.full {
    border-radius: 50%; 
}
Copy the code

2. X-axis left semi-ellipse

This shape, horizontally, has two rounded corners on the left that take up the entire width of the element, and there are no rounded corners on the right, so the horizontal border-radius value is 100%, 0, 0, 100%; In the vertical direction, the vertical radius of the upper left corner is the same as that of the lower left corner, both of which are 50%. Meanwhile, since the horizontal border-radius of the two rounded corners on the right is 0, the border-radius in the vertical direction of the two rounded corners on the right is not important and can be any value.

.x-semi {
    border-radius: 100% 0 0 100% / 50%;  /* Equivalent to 100% 00 100%/ 50% 50% 50% 50% */ ;
}
Copy the code

3. Quarter oval

.quarter {
    border-radius: 100% 0 0 0;  /* equivalent to 100% 00/100% 00 0; * /
}   
Copy the code

parallelogram

Skew of CSS deformation

To generate the parallelogram, it is natural to use the Skew property of transform to skew the rectangle.

transform: skewX(-45deg);
Copy the code

But by doing so, the contents of the parallelogram are also skewed. Here are two options for tilting the shape of the container while leaving its contents unchanged.

Nested element scheme

A layer of DOM elements is nested and the content is skew() in reverse.

The core code is as follows :(code link)

<div class="parallelogram-1">
    <div class="text">CLICK ME</div>
</div>
Copy the code
.parallelogram-1 {
     transform: skewX(-45deg);
}
.parallelogram-1>.text {
    transform: skewX(45deg);
}
Copy the code

Cons: Requires two layers of DOM tags

Pseudoelement scheme

Apply all the styles (backgrounds, borders, etc.) to the fake elements, and then deform the fake elements, because our content is not contained in the fake elements, so the content is not affected by the deformation. At this point, the square generated with the pseudo element is superimposed on the content, and once we set the background to it, the content will be obscured. We can set the pseudo element to z-index: -1 so that its stack level will be pushed behind the host element.

The final code is as follows :(code link)

.parallelogram-2 {
    position: relative;
}
.parallelogram-2::before {
    content: ' ';
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    /* The following is important code */
    transform: skewX(-45deg);
    z-index: -1;
}
Copy the code

Disadvantages: The deformation causes the click area of the event to differ from the actual element area seen

3. Prismatic images

CSS deformation, “parallelogram”

A scheme based on deformation

Based on the first solution discussed in “parallelograms,” you wrap the image around a div tag and apply the reverse rotate() transform to it, as follows:

<div class="diamond-1">
    <img src="nana.jpg" alt="">
</div>
Copy the code
.diamond-1 {
    width: 200px;
    height: 200px;
    background-color: yellow;
    overflow: hidden;
    transform: rotate(45deg);
}
.diamond-1>img {
    max-width: 100%;
    transform: rotate(-45deg);  
}
Copy the code

We wanted to get the right side of the image above, but we got the left side instead. The main problem is the statement max-width: 100%. 100% will be resolved to the side length of the container (.diamond-1), but we want the width of the image to be equal to the diagonal of the container, which is √2≈1.42√2≈ 1.42√2≈1.42 √2≈1.42√2≈ 1.42, so we can set max-width to 142%, but the effect is as shown below. This is because when you zoom in on an image using the Width property, you only zoom in from its top left corner.

Finally, we can use the scale() deformation style to enlarge the image by 1.42 times to achieve the effect. The final code is as follows :(code link)

.diamond-1 {
    width: 200px;
    height: 200px;
    background-color: yellow;
    overflow: hidden;
    /* The following is important code */
    transform: rotate(45deg);
}
.diamond-1>img {
     /* The following is important code */
    max-width: 100%;
    transform: rotate(-45deg) scale(1.42); 
}
Copy the code

Cons: Requires two layers of DOM tags

Cutting path scheme

The clip-path property is used to crop images, but it has limited browser support.

.diamond-2 {
    width: 200px;
    height: 200px;
    clip-path: polygon(50% 0.100% 50%.50% 100%.0 50%);
}
Copy the code

In addition to limited browser support, this property does more than that. It can also crop polygons via the polygon() function, circles via the Circle () function, and ellipse() function.

4. Angle cutting effect

CSS gradient, background-size, Stripe Background, border-image, clip-path

CSS gradient scheme

Cut a corner effect: take the lower right corner as an example. We can get there with just a linear gradient. This gradient requires placing a transparent color at the corner of the cut, then setting another color at the same position and setting it to the desired background color. (Code link)

    background: #58a;
    background: linear-gradient(-45deg, transparent 15px.#58a 0);
Copy the code

Note: In fact, the first line declaration is not required, plus it’s used as a fallback mechanism: if some browsers don’t support CSS gradients, the second line declaration will be discarded, and we’ll at least get a simple solid background.

Effect of cutting two corners: Take the lower left corner and the lower right corner as an example. We need to treat the figure as two parts, split in half from the middle, use a linear gradient of bottom right corner on the right and a linear gradient of bottom left corner on the left, and turn background-repeat off at the same time, the code is as follows:

  background: #58a;
  background:linear-gradient(-45deg, transparent 15px.#58a 0) right,/* Right refers to the background-position property, indicating that background-size*/ is calculated from the rightlinear-gradient(45deg, transparent 15px.# 655 0) left;/*left indicates background-position, indicating that background-size*/ is calculated from the left
  background-size: 50% 100%;
  background-repeat: no-repeat;
Copy the code

Cut four corners effect: understand the principle of cut two corners, cut four corners how difficult to get wit of us. The code is as follows:

    background: #58a;
    background: linear-gradient(135deg, transparent 15px.#58a 0) top left,
                linear-gradient(-135deg, transparent 15px.#58a 0) top right,
                linear-gradient(-45deg, transparent 15px.#58a 0) bottom right,
                linear-gradient(45deg, transparent 15px.#58a 0) bottom left;
    background-size: 50% 50%;
    background-repeat: no-repeat;
Copy the code

Arc Angle cutting: The arc Angle cutting principle cuts four corners, but changes the linear gradient to radial gradient. The code is as follows:

    background: #58a;
    background: radial-gradient(circle at top left, transparent 15px.#58a 0) top left, 
                radial-gradient(circle at top right, transparent 15px.#58a 0) top right,
                radial-gradient(circle at bottom right, transparent 15px.#58a 0) bottom right,
                radial-gradient(circle at bottom left, transparent 15px.#58a 0) bottom left;
    background-repeat: no-repeat;
    background-size: 50% 50%;
Copy the code

Inline SVG with the border-image scheme

In conventional design, the size of the four corners is usually the same. Since border-image will solve the scaling problem, and SVG can achieve perfect scaling regardless of size, apply the following SVG to border-image and set border-image-slice to 1, such as dotted line slice, to obtain a corner cutting effect.

<svg xmlns="http://www.w3.org/2000/svg" width="3" height="3" fill="#58a">
    <polygon points="0,1, 0,2,0, 3,1, 3,2, 2,3, 1,3, 0,2"/>
</svg>
Copy the code

The chamfering code is as follows:

border: 15px solid transparent;
border-image: 1 url('data: image/SVG + XML, < SVG XMLNS = "http://www.w3.org/2000/svg" width = "3" height = "3" the fill = "% 2358 a" > < polygon points = "0, 1, 1, 0 2,0, 3,1,2, 2,3, 0,2"/>
      ');
Copy the code

Through the above code, we found two problems, one is the background picture problem, the other is the size of the cut Angle is smaller than the original problem.

Let’s deal with the background image first. Either give the border-image attribute value a fill keyword after the border-image-slice so that it doesn’t lose the slice in the middle of the SVG; Or give it a background color and set it to background-clip:padding-content, which also provides a fallback effect.

The reason why the cutting Angle size is smaller than the original is shown in the picture below. Originally, 15px is measured along the gradient axis, which is the oblique distance shown in the following image. The 15px used in this method is the width of the border, which is the horizontal or vertical distance shown in the following image. Therefore, the oblique distance should be 15px. The width of border should be 15×√2≈21.21315×√2≈ 21.21315×√2≈21.213, approximately 20.

In addition, we add a background color to the border to provide a fallback scheme when the border-image property is not supported by the browser. So the final code looks like this (code link) :

    border: 20px solid #58a; /* Use the background color instead of transparent to provide a fallback option */ if the browser does not support border-image
    border-image: 1 url('data: image/SVG + XML, < SVG XMLNS = "http://www.w3.org/2000/svg" width = "3" height = "3" the fill = "% 2358 a" > < polygon points = "0, 1, 1, 0 2,0, 3,1,2, 2,3, 0,2"/>
      ');
    background: #58a;
    background-clip: padding-box;
Copy the code

Cutting path scheme

background: #58a;
clip-path: polygon(20px 0.calc(100% - 20px) 0.100% 20px.100% calc(100% - 20px),
            calc(100% - 20px) 100%.20px 100%.0 calc(100% - 20px), 0 20px);
Copy the code

A comparison of the three schemes

5. Trapezoidal TAB page

Background basic 3D deformation, “parallelogram”

Similar to the method we learned in the parallel quadrilateral section, we create a 3D deformation of the pseudo-element as follows:

.trapezoid {
    position: relative;
    display: inline-block;
    padding:.5em 1em .35em;
    color: white;
}
.trapezoid::before {
    content: ' '; /* Create a rectangle with a false element */
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    z-index: -1;
    background: #58a;
    transform: perspective(.5em) rotateX(5deg);
}
Copy the code

Figure 2 is the comparison before and after the deformation of Figure 1. It can be seen that the default deformation center transform-Orign increases the width of the element after rotation on the Central Line of the element itself, and the position occupied by the trapezoid will move down slightly and the height will be slightly reduced. One method mentioned in the article is shown in Figure 3, and the transform-Orign deformation center is set as bottom. At this time, we only need to compensate the height, and the vertical scaling degree is about 130%, so the final code is obtained as follows:

.trapezoid {
    position: relative;
    display: inline-block;
    padding:.5em 1em .35em;
    color: white;
}
.trapezoid::before {
    content: ' '; /* Create a rectangle with a false element */
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    z-index: -1;
    background: #58a;
    transform: scaleY(1.3) perspective(.5em) rotateX(5deg);
    transform-origin: bottom;
}
Copy the code

So you get a nice trapezoid.

Since we want to generate trapezoidal tags, we can easily get the following trapezoidal tag TAB style according to the above scheme, for reasons of space, please click here for the code.

6. Simple pie charts

CSS gradient, Basic SVG, CSS animation, “Stripe Background”, “Adaptive Ellipse”, Conic-gradient

Our case uses yellowgreen for the background color and brown (#655) for the ratio.

Transform-based scheme

The principle is as follows (the length is quite long) : We first used Linear-gradient to divide the circle into two parts, and then constructed a semi-circle cover with pseudo-elements, and decided how much sector to expose by rotating the pseudo-elements.

Construct a circle with two colors as follows:

.pie {
    width: 100px;
    height: 100px;
    border-radius: 50%;
    background: yellowgreen;
    background-image:linear-gradient(to right, transparent 50%.# 655 0);
}
Copy the code

Then use pseudo elements to construct a semi-dome on this element, and set the rotation center at the center of the circle.

pie::before {
    content: ' ';
    display: block;
    margin-left: 50%;
    height: 100%;
    border-radius: 0 100% 100% 0 / 50%;
    transform-origin: left;
}
Copy the code

To get a pie chart with a display rate of 0-50%, simply set the pseudo-element background to yellow-green and rotate the corresponding degree, let’s say 20%, Turn360deg ×0.2=72deg=0.2 Turn360deg ×0.2=72deg=0.2 TURN360deg ×0.2=72deg=0.2 TURN

pie::before {
    content: ' ';
    display: block;
    margin-left: 50%;
    height: 100%;
    border-radius: 0 100% 100% 0 / 50%;
    transform-origin: left;
    background-color: inherit; /* Inherits the parent element's yellow-green */
    transform: rotate(.2turn); /* Rotate 0.2 times */
}
Copy the code

To get a pie chart with a display rate greater than 50%, simply set the pseudo-element background to brown and rotate the corresponding degree. Let’s take 60%, Turn360deg x (0.6−0.5)=36deg=0.1 Turn360deg x (0.6−0.5)=36deg=0.1turn360deg x (0.6−0.5)=36deg=0.1turn

pie::before {
    content: ' ';
    display: block;
    margin-left: 50%;
    height: 100%;
    border-radius: 0 100% 100% 0 / 50%;
    transform-origin: left;
    background-color: # 655; / * * / brown
    transform: rotate(.1turn); /* Rotate 0.1 times */
}
Copy the code

Now that we know what’s going on, we need to encapsulate these two cases. Let’s start with an animation. The following code animates a pie chart that goes from 0 to 100%.

@keyframes spin {
    to { transform: rotate(.5turn); }}@keyframes bg {
    50% { background: # 655; }}.pie::before {
    content: ' ';
    display: block;
    margin-left: 50%;
    height: 100%;
    border-radius: 0 100% 100% 0 / 50%;
    background-color: inherit;
    transform-origin: left;
    animation: spin 3s linear infinite,
    bg 6s step-end infinite;
}
Copy the code

Let’s look at another specification for animation-delay.

“A negative delay value is legal. Similar to the delay of 0s, it means that the animation will start playing immediately, but will automatically advance to the absolute value of the delay value, as if the animation had played for a specified time in the past. So the effect is that the animation skips the specified time and starts in the middle.” CSS Animation (first edition) (w3.org/TR/css-anim…

Now that we know the animation and animation-delay specifications above, we will use the animation above to solve this encapsulation, but the animation must be paused, and it must be paused at the desired location. We’re going to use a negative animation delay to jump straight to any point in time in the animation and freeze there.

We set the total length of the animation to 100s. We can set the animation-delay property inline and then apply the animation-delay: Inherit property on the pseudo-elements. Combining the above elements, if the pie chart is to be displayed as 20% and 60%, the HTML structure code is:

<div class="pie" style="animation-delay: -20s"></div>
<div class="pie" style="animation-delay: -60s"></div>
Copy the code

Further optimize the HTML code structure, the optimized code is as follows:

<div class="pie">20%</div>
<div class="pie">60%</div>
Copy the code

In this case, we use a javascript script to write the animation-delay inline and use color: transparent to hide the text.

document.querySelectorAll('.pie').forEach(function (pie) {
    var p = parseFloat(pie.textContent);
    pie.style.animationDelay = The '-' + p + 's';
});
Copy the code

The code for the final improved CSS is as follows (click here for details) :

.pie {
    position: relative;
    width: 100px;
    line-height: 100px;
    border-radius: 50%;
    background: yellowgreen;
    background-image: linear-gradient(to right, transparent 50%.# 655 0);
    color: transparent;
    text-align: center;
}

@keyframes spin {
    to {
        transform: rotate(.5turn); }}@keyframes bg {
    50% {
        background: # 655; }}.pie::before {
    content: ' ';
    position: absolute;
    top: 0;
    left: 50%;
    width: 50%;
    height: 100%;
    border-radius: 0 100% 100% 0 / 50%;
    background-color: inherit;
    transform-origin: left;
    animation: spin 50s linear infinite, bg 100s step-end infinite;
    animation-play-state: paused;
    animation-delay: inherit;
}
Copy the code

SVG scheme

How it works: Let’s start with an SVG and draw a circle of radius 50.

<svg width="100" height="100">
    <circle r="30" cx="50" cy="50" />
</svg>
Copy the code

Add a base style and stroke to the circle, as shown in Figure 1 below.

circle {
    fill: yellowgreen;  /* Fill the color */
    stroke: # 655;  /* Stroke color */
    stroke-width: 30; /* Stroke width */
}
Copy the code

Append the following line to the above style to make the stroke a dotted line, as shown in Figure 2 below.

.stroke-dasharray: 20 10; /* The line segment length of the dashed line is 20 and the gap length is 10 */
Copy the code

When we specify the length of this imaginary line stroke as zero and set the length of the dotted line gap as equal to or greater than the length of the entire circle, which is 2π×30≈1892π×30≈ 189. As you can see, it completely removes the stroke effect, leaving only the green circle. When we start adding the first value, the entire circumference of the circle is covered by the exact length we gave it.

First, for the sake of calculation, let’s set the circumference of the circle to 100, so that the radius is 100/2π≈16100/2π≈ 16. Then we need to rotate the SVG by 90° counterclockwise to bring the starting point of the stroke to 0 o ‘clock. This gives us a 60% pie chart with the following code (click here for details) :

<svg viewBox="0 0 32 32">
    <circle class="circle" r="16" cx="16" cy="16" />
</svg>
Copy the code
svg {
    width: 100px; height: 100px;
    transform: rotate(-90deg);
    background: yellowgreen;
    border-radius: 50%;
}
.circle {
    fill: yellowgreen;  /* Fill the color */
    stroke: # 655;  /* Stroke color */
    stroke-width: 32; /* Stroke width */
    stroke-dasharray: 60 100; /* The line segment length of the dashed key code is 60 and the gap length is 100*/ 
}
Copy the code

Using this principle, we can also achieve a multi-color pie chart, we add a circle layer for each color, and the circle layer closer to the starting point is on the upper layer. The code is as follows (details here) :

<svg viewBox="0 0 32 32">
    <circle class="circle1" r="16" cx="16" cy="16" />
    <circle class="circle2" r="16" cx="16" cy="16" />
</svg>
Copy the code
svg {
    width: 100px; height: 100px;
    transform: rotate(-90deg);
    background: yellowgreen;
    border-radius: 50%;
}
.circle1 {
   fill: yellowgreen;
    stroke: # 655; 
    stroke-width: 32;
    stroke-dasharray: 60 100; 
}
.circle2 {
    fill: transparent;
    stroke: grey;
    stroke-width: 32;
    stroke-dasharray: 20 100; 
}
Copy the code

Conic – gradient scheme

Combining the previous learning of Linear-gradient knowledge, the use of conic-gradient cone to achieve a variety of color pie chart is too easy ~ wall cracks recommended! The code is as follows (details here) :

.conic {
    width: 100px;
    height: 100px;
    border-radius: 50%;
    background: conic-gradient(grey 0 20%.# 655 0 60%, yellowgreen 0 100%);
}
Copy the code

It can be seen from the three pie chart generation schemes that SVG scheme and ConIC-gradient scheme have simple code and can easily achieve a multi-color pie chart, which is highly recommended