27
头图

In this article, I will take a different approach and introduce a unique way to use filters to create rounded corners.

First, let's look at a graph like this:

A rectangle, nothing special, the code is as follows:

 div {
    width: 200px;
    height: 40px;
    background-color: #000;
}

If, we now need to add rounded corners to both ends of this rectangle, like this, how to do it:

So easy, just add border-radius just:

 div {
    width: 200px;
    height: 40px;
  + border-radius: 40px;
    background-color: #000;
}

Well, what if, instead of a straight line, it is a curve, and I want the two ends of the curve to have rounded corners, like this, what should I do:

image

At this point, the ceiling of traditional CSS has basically been touched, and it is impossible to get this effect through a property.

Of course, there is such a way to use two pseudo-elements at the beginning and end to realize two circles and superimpose them:

Emm, this is also a feasible solution, mainly because the positioning will be a little troublesome. So besides this way and using SVG directly, is there any other way to achieve curves with rounded corners?

Have! In CSS, we can also achieve this graphic by combining filter: contrast() with filter: blur() .

filter: contrast() filter: blur() The wonderful chemistry of ---a13ca597d44621c50c944138123b0047---

In the magic filter! In the article on cleverly implementing concave smooth rounded corners , an alternative usage of this combination has actually been introduced.

Friends who often read my articles must be familiar with the combination of filter: contrast() and filter: blur() . Here is a classic picture:

Take out the two filters separately, and their functions are:

  1. filter: blur() : Set the Gaussian blur effect on the image.
  2. filter: contrast() : Adjust the contrast of the image.

However, when they "fit", a wonderful fusion phenomenon occurs.

Look carefully at the process of the intersection of the two circles. When the edge is in contact with the edge, a boundary fusion effect will be produced. The blurred edge of the Gaussian blur is eliminated through the contrast filter, and the Gaussian blur is used to achieve the fusion effect.

Of course, here comes the point, the combination of blur and contrast filters can not only be used for this kind of fusion effect, but their special properties allow their combination to turn right angles into rounded corners!

Let's take a look at an example from earlier:

First, we just need to implement a graph like this:

 <div class="g-container">
    <div class="g-content">
        <div class="g-filter"></div>
    </div>
</div>
 .g-container {
    position: relative;
    width: 300px;
    height: 100px;
    
    .g-content {
        height: 100px;
        
        .g-filter {
            height: 100px;
            background: radial-gradient(circle at 50% -10px, transparent 0, transparent 39px, #000 40px, #000);
        }
    }
}

Get a simple graph like this:

Seeing this, you will definitely wonder why this graphic needs to be nested with 3 layers of divs? Wouldn't a div be enough?

Because we are going to use the magic combination of filter: contrast() and filter: blur() .

Let's simply transform the above code and carefully observe the similarities and differences with the above CSS:

 .g-container {
    position: relative;
    width: 300px;
    height: 100px;
    
    .g-content {
        height: 100px;
        filter: contrast(20);
        background-color: white;
        overflow: hidden;
        
        .g-filter {
            filter: blur(10px);
            height: 100px;
            background: radial-gradient(circle at 50% -10px, transparent 0, transparent 29px, #000 40px, #000);
        }
    }
}

.g-content e047cf88111ed471b37530cdeee1d9e8---添加了---6e3231fc0e052f882844699d8ba0538e filter: contrast(20) background-color: white ,给.g-filter添加了filter: blur(10px)

The magic happened, we got this effect:

Through the contrast filter, the blurred edges of the Gaussian blur are removed, and the original right angles are turned into rounded corners , Amazing.

A more intuitive feeling through a Gif image:

You can click here for the complete code: CodePen Demo - Smooth concave rounded corners By filter

Rounded corners and arcs through filters

At this point, you should know how to get rounded arcs from right-angled arcs. It is the combination of filter: contrast() and filter: blur() .

Go directly to the code:

 div {
    position: relative;
    width: 250px;
    height: 250px;
    filter: contrast(20);
    background-color: #fff;
    overflow: hidden;
}
div::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    filter: blur(7px);
    border: 25px solid transparent;
    border-bottom: 25px solid #000;
    border-radius: 50%;
}

The effect is as follows:

Looking through the Gif, it is more intuitive:

CodePen Demo -- Arc with rounded corners

Use filter: contrast() with filter: blur() to achieve wave effect

Well, with the above foreshadowing, let's look at another interesting one. Use filter: contrast() with filter: blur() to achieve wave effect.

Before, if we wanted to use pure CSS, it was very difficult to achieve the following wave effect:

This wave effect is usually used in coupons and other cuts:

How did we do it before? If you don't cut the image and use pure CSS, you need to use two layers of gradients to superimpose, which is probably like this, feel it:

bgg2

Its code is also more complicated, and it needs to continuously debug the gradient to make the two radial gradients match:

 div {
    position: relative;
    width: 400px;
    height: 160px;
    background: linear-gradient(90deg, #945700 0%, #f49714 100%);
    
    &::before,
    &::after {
        content: "";
        position: absolute;
        top: 0;
        right: 0;
        bottom :0;
    }
    &::before {
        width: 10px;
        background-image: radial-gradient(circle at -5px 10px, transparent 12px, #fff 13px, #fff 0px);
        background-size: 20px 20px;
        background-position: 0 15px;
    }
    &::after {
        width: 15px;
        background-image: radial-gradient(circle at 15px 10px, #fff 12px, transparent 13px, transparent 0px);
        background-size: 20px 40px;
        background-position: 0 15px;
    }
}

Then, if you use filter: contrast() with filter: blur() , the whole process will become very simple.

We just need to implement a graph like this:

This graph is easily obtained using gradients:

 div {
    background: radial-gradient(circle at 20px 0, transparent, transparent 20px, #000 21px, #000 40px);
    background-size: 80px 100%;
}

According to the techniques described above, you only need to apply filter: contrast() and filter: blur() to convert a sharp right angle into a rounded corner. Let's try:

 <div class="g-container">
    <div class="g-inner"></div>
</div>
 .g-container {
    position: relative;
    margin: auto;
    height: 200px;
    padding-top: 100px;
    filter: contrast(20);
    background-color: #fff;
    overflow: hidden;
}

.g-inner {
    position: relative;
    height: 200px;
    background: radial-gradient(circle at 20px 0, transparent, transparent 20px, #000 21px, #000 40px);
    background-size: 80px 100%;
    filter: blur(10px)
}
It can be written in one DIV (construct parent-child relationship through elements and its pseudo-elements), or two can be used, no problem.

Get a wavy pattern like this:

Where we want it to be wavy is indeed a wave, but where we don't want it, it also becomes rounded:

This is a problem with filter: blur() . Fortunately, we can use backdrop-filter() to avoid this problem. We simply modify the code:

 .g-container {
    position: relative;
    width: 380px;
    padding-top: 100px;
    filter: contrast(20);
    background-color: #fff;
    overflow: hidden;
    
    &::before {
        content: "";
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;
        backdrop-filter: blur(10px);
        z-index: 1;
    }
}
.g-inner {
    position: relative;
    width: 380px;
    height: 100px;
    background: radial-gradient(circle at 20px 0, transparent, transparent 20px, #000 21px, #000 40px);
    background-size: 80px 100%;
}

In this way, we have achieved a perfect wave effect:

Some students may have doubts about the above padding-top 100px . This is also a bug I have found so far. It has not been solved yet, and it does not affect the use. You can try to replace padding-top: 100px with height: 100px.

Based on the wave effect achieved in this way, we can even add animation to it to make it move, which is also very easy to do. Simply transform the code:

 .g-inner {
    position: relative;
  - width: 380px;
  + width: 480px;
    height: 100px;
    background: radial-gradient(circle at 20px 0, transparent, transparent 20px, #000 21px, #000 40px);
    background-size: 80px 100%;
  + animation: move 1s infinite linear; 
}

@keyframes move {
    100% {
        transform: translate(-80px, 0);
    }
}

With a simple displacement animation, and making the first and last frames consistent, it appears to be continuous:

For the complete code, you can click here: CodePen Demo -- Pure CSS Wave

SVG filters for easier use

Is this over? No! Although the combination of the above two filters is powerful, it is still a little troublesome.

With the addition of powerful group friends, an SVG filter solution is added. Here, for most scenarios, we can use SVG filters to introduce one line in CSS to achieve the same function.

Looking at such a DEMO, we have a triangle like this:

We want to get a rounded triangle through it:

With the help of SVG filters, it can actually be achieved quickly, eliminating the need to superimpose a filter: contrast() on the trouble:

 <div class="g-triangle"></div>
<svg width="0">
    <filter id="blur" color-interpolation-filters="sRGB">
      <feGaussianBlur stdDeviation="10" />
      <feComponentTransfer>
          <feFuncA type="table" tableValues="0 0 10"/>
      </feComponentTransfer>
    </filter>
</svg>
 div {
        border: 60px solid transparent;
        border-left: 120px solid #f48;
        filter: url(#blur);
}

The effect is as follows:

Yes, using filter: url(xxx) can quickly introduce a defined SVG filter. You can also do this, directly embedded in the URL:

 div {
        border: 60px solid transparent;
        border-left: 120px solid #f48;
        filter: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='blur' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='10'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='table' tableValues='0 0 10'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3C/svg%3E#blur");
}

The complete code, you can click here: CodePen Demo -- triangle with rounded corners and shadow

in conclusion

This article introduces a method of using filter: contrast() with filter: blur() to turn right-angled graphics into rounded graphics, which may be useful in some specific scenarios. At the same time, in many scenarios, SVG filters can be used to simplify operations.

However, this approach has several minor flaws:

  1. After using filter: contrast() , the size of the graphics may be reduced a little bit. To achieve the required fixed size, some debugging is required.
  2. After all, the graphics generated in this way have gone through once filter: blur() . When you zoom in on the graphics, there will be a certain amount of jaggedness. You can remove as much as possible by adjusting the size of contrast and blur, but it cannot be completely removed.

Of course, I think these two small shortcomings do not hide the advantages. In certain scenarios, this method still has a certain role.

at last

This concludes this article, I hope it helps 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.


chokcoco
12.3k 声望18.5k 粉丝