1. The train of thought

How do I draw a shaded triangle with CSS? There are many solutions on the Internet, but in fact, most of them are not perfectly implemented, there are some problems

Let’s say we make a downward triangular arrow and there are two common ways to do it

  1. With border control, set border-left and border-right to transparent, and border-top to a predetermined color
  2. Rotate the box by transform

Design of 2.

So let me draw the triangle

<body>
    <div class="box"></div>
</body>
Copy the code

CSS styles

.box {
    position: relative;
    width: 200px;
    height: 100px;
    background: #ff8605;
    box-shadow: 2px 2px 2px rgba(0, 0, 0, 2); }.box::after {
    content: ' ';
    position: absolute;
    bottom: -9px;
    left: 45px;
    border-left: 10px solid transparent;
    border-right: 10px solid transparent;
    border-top: 10px solid #ff8605;
}
Copy the code

The disadvantage is obvious, we can’t set the shadow by box-shadow, the shadow will be a box

2.1 frame method

If the shadow requirement is not so high, we can define another pseudo-element triangle, but it is similar to the shadow color, this shadow triangle is covered under our original triangle

.box::before {
    position: absolute;
    bottom: -10px;
    left: 45px;
    content: ' ';
    border-left: 10px solid transparent;
    border-right: 10px solid transparent;
    border-top: 10px solid rgba(0, 0, 0, 1); }Copy the code

As is shown in

The advantage is that compatibility is better, the requirements are not strict seems to be enough

But being a strict front end engineer! We still can’t tolerate this implementation

2.2 filter method

The correct posture is the drop shadow() in filter.

The drop-shadow attribute in filter is a real projection, which only projects the shadow of the real graph

Box-shadow only casts shadows on box models

.box::after {
    position: absolute;
    bottom: -9px;
    left: 45px;
    content: ' ';
    border-left: 10px solid transparent;
    border-right: 10px solid transparent;
    border-top: 10px solid #ff8605;
    filter: drop-shadow(2px 2px 2px rgba(0, 0, 0, .2));
}
Copy the code

Very perfect implementation of the effect, the disadvantage is that compatibility may be poor

Filter Compatibility

(The filter method was suggested by the kids in the comments section, thanks ~~)

2.3 the transform method

The idea of this method is to use the box model shadow for the triangle. Instead of drawing a triangle, we can directly draw a square box and rotate it 45 degrees by the Transform attribute

.box::before {
    position: absolute;
    bottom: -5px;
    left: 45px;
    content: ' ';
    width: 10px;
    height: 10px;
    background: #ff8605;
    transform: rotate(135deg);
    box-shadow: 1px -2px 2px rgba(0, 0, 0, 2); }Copy the code

We seem to have achieved what we wanted, however, there is a problem, but because our shadow area is not large enough, it doesn’t look obvious on the image

When we enlarge the area of the box-shadow, we see the problem

The box is sticking out. How do you fix it

Let’s make another box with the same color as the container and cover the top half.

/* transform method */
.box::before {
    position: absolute;
    bottom: -5px;
    left: 45px;
    content: ' ';
    width: 10px;
    height: 10px;
    background: #ff8605;
    transform: rotate(135deg);
    box-shadow: 1px -2px 5px rgba(0, 0, 0, 2); }.box::after {
    position: absolute;
    bottom: 0px;
    left: 40px;
    content: ' ';
    width: 20px;
    height: 20px;
    background: #ff8605;
}
Copy the code

Note that the triangle should be defined before and the overlying box should be defined after so that the box covers the triangle

Effect:

Of course, this approach could affect the contents of the box

3. Final solution code


      
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width" />
        <title>CSS implements Shadowed triangles</title>
        <style>
            .box {
                position: relative;
                width: 200px;
                height: 100px;
                background: #ff8605;
                box-shadow: 2px 2px 2px rgba(0, 0, 0, 2); }/ * * / border method
            .box::before {
                position: absolute;
                bottom: -10px;
                left: 45px;
                content: ' ';
                border-left: 10px solid transparent;
                border-right: 10px solid transparent;
                border-top: 10px solid rgba(0, 0, 0, 1); }/* drop-shadow */
            .box::after {
                position: absolute;
                bottom: -9px;
                left: 45px;
                content: ' ';
                border-left: 10px solid transparent;
                border-right: 10px solid transparent;
                border-top: 10px solid #ff8605;
                filter: drop-shadow(1px 3px 1px rgba(0, 0, 0, .2));
            }
            
            /* tranform */
            .box::before {
                position: absolute;
                bottom: -5px;
                left: 45px;
                content: ' ';
                width: 10px;
                height: 10px;
                background: #ff8605;
                transform: rotate(135deg);
                box-shadow: 1px -2px 5px rgba(0, 0, 0, 2); }.box::after {
                position: absolute;
                bottom: 0px;
                left: 40px;
                content: ' ';
                width: 20px;
                height: 20px;
                background: #ff8605;
            }
        </style>
    </head>
    <body>
        <div class="box"></div>
    </body>
</html>
Copy the code

If you have a better way to achieve, feel free to leave a message to me