DEV Community

pallade
pallade

Posted on • Updated on

Css: A rectangle with an oblique bottom border

Update: trigonometric functions are now available in all major browsers! No need for such tricks anymore!

My designer came up with a comp that has sections, and some of those sections have an oblique border. Moreover, they also have a drop shadow! And of course, this has to be responsive.

So I came up with some ideas on how to solve this.

Find the codepen at the bottom of this post!

All of the examples have a div that will host the content ("above-gradient"), and another div that will render the sloping bottom. This is to make things easier, and also most of those solutions require two divs because of the drop shadow.

Solution 1: svg triangle without shadow

The first solution is the easiest: just create an SVG triangle and stretch it.

<div class="above-gradient"></div>
<div class='gradient gradient1'>
  <svg viewBox='0 0 100 100' preserveAspectRatio='none' overflow="visible">
    <polygon points="0,100 100,0 0,0" class="main"/>
  </svg>
</div>
Enter fullscreen mode Exit fullscreen mode
.above-gradient {
  width: 100%;
  height: 150px;
  background-color: yellow;
}

.gradient {
  width: 100%;
  height: 100px;

  svg {
    height: 100%;
    width: 100%;
    .main {
      fill: yellow;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Notice that the angle is not preserved when the viewport width changes, so the angle will increase when the screen is narrower.

Advantages: quickest
Disadvantages: angle is not preserved, no shadow

Solution 2: svg triangle with shadow

We will be adding a shadow now. Call it gradient2 and apply this CSS:

.gradient2 {
  svg {
    filter: drop-shadow(0 0 5px rgba(0,0,0,.5));
  }
}
Enter fullscreen mode Exit fullscreen mode

Whoops: we will need to apply some z-indexes, otherwise the shadow will be also on the upper part of the triangle!

But look carefully: that shadow is inconsistent with the main shape! It is a shadow of a triangle, and not that of a trapezium. This is evident at the far right corner, where the shadow is zero (because near the edge there is nothing that could cast it).

Advantages: quickest
Disadvantages: angle is not preserved, inconsistent shadow

Solution 3: skewed rectangle with JS

So let's come up with something else. How can we fix the shadow problem? We'd need to cast it from a rectangle, that does not have the problem with the edges. And CSS has a filter that is skewY that would skew the entire rectangle to achieve exactly the effect we want.

Unfortunately there is a problem: the width of the screen is unknown, therefore we cannot both fix an angle and a height. One of the two has to be computed.

This means: trigonometry.

Unfortunately, CSS does not have trigonometric functions (yet), so the only possibility is to resort to some JS.

Since we need to do it the hard way, let's also solve the problem with the angle: let's try to keep the angle constant. We will therefore need to adjust its height.

    function updateTan() {
        let deg = 3 * Math.PI / 180;
        let adjacent = document.getElementById('main-wrapper').offsetWidth;
        let opposite = adjacent * Math.tan(deg);
        document.documentElement.style.setProperty('--len-at-3', opposite + 'px');
    }
    updateTan();

    window.addEventListener('resize', updateTan);
Enter fullscreen mode Exit fullscreen mode

Our JS will get the width of the containing element and compute the appropriate height of our div, given an angle of 3°.

The first line converts our 3 degrees into radiants, that is the unit expected by Math.tan.

We are setting a CSS variable here, called --len-at-3, which we will use later in the CSS. We could access the element directly, but it is clearer this way.

:root {
  --len-at-3: 0;
}
.gradient3 {
  height: var(--len-at-3);
  transform: skewY(-3deg);
  transform-origin: top left;
}
Enter fullscreen mode Exit fullscreen mode

If JS is disabled, the element will have a 0 width and no shadow. Since it will also have a z-index of -1 (see previous example) it should not get into our way.

Advantages: angle preserved
Disadvantages: requires JS

Solution 4: cheating with a PNG

There is a solution I used to employ widely which is just to get a triangular PNG file and stretch it edge to edge.

The shadow is consistent, and there are no problems at the edges. However, this feels a bit as a hack, since stretching an image much beyond its native size feels unnatural.

Advantages: compatible with ancient browsers, consistent shadow
Disadvantages: angle is not preserved, may lose quality when screen is larger

Conclusion

Did you come up with a better solution? Please, let me know.

Below is the codepen with all of them.

Top comments (0)