Recently, I had to work on a website heavily using tilted angles as part of its design guidelines. By “tilted angles”, I mean these sections whose top or bottom edge is not completely horizontal and rather a bit inclined.
There are quite a few ways to implement this. You could have base 64 encoded images applied as a background, but it makes it hard to customise (color, angle, etc.).
Another way would be to skew and/or rotate an absolutely positioned pseudoelement, but if there is one thing I don’t want to deal with, it’s the skew transform. God, no.
When using Sass, you could use the Angled Edges library that encodes dynamically generated SVG. It works super well, however it requires a fixed width and height expressed in pixels, which kind of bothered me.
I also really wanted to see if and how I could be able to implement this. I ended up with a solution that I am really proud of, even if it might be a bit overengineered for simple scenarios.
What’s the Idea?
My idea was to apply a half transparent, half solid gradient to an absolutelypositioned pseudoelement. The angle of the gradient defines the tilt angle.
backgroundimage: lineargradient($angle, $color 50%, transparent 50%);
This is packaged in a mixin that applies the background color to the container, and generates a pseudoelement with the correct gradient based on the given angle. Simple enough. You’d use it like this:
.container {
@include tilted($angle: 3deg, $color: rgb(255, 255, 255));
}
The main problem I faced with this was to figure which height the pseudoelement should have. At first, I made it an argument of the mixin, but I ended up going trialanderror at every new angle to figure out what would be the best height for the pseudo. Not ideal.
And just when I was about to table flip the whole thing, I decided to leave the laptop away, took a pen and paper and started doodling to figure out the formula behind it. It took me a while (and a few Google searches) to remember trigonometry I learnt in highschool, but eventually I made it.
To avoid having to guess or come up with good approximations, the height of the pseudoelement is computed from the given angle. This is, of course, all done with a bit of Sass and a lot of geometry. Let’s go.
Computing the Pseudoelement’s Height
Trust me when I’m telling you it won’t be too hard. The first thing we know is that we have a fullwidth pseudoelement. The gradient line will literally be the pseudo’s diagonal, so we end up with a rectangle triangle.
Let’s name it ABC, where C
is the right angle, B
is the known angle ($angle
argument) and A
is therefore C  B
. As shown on this diagram, we try to figure out what b
is.
To do that, we need to find the value of c
(the gradient line, aka the hypothenuse), which is the length of a
(the bottom side, 100%) divided by sine of the A
angle (with B = 5°
, A
would be 85° for instance).
c = a / sin(C  B)
From there, we have to use Pythagoras theorem:
The square of the hypotenuse (the side opposite the right angle) is equal to the sum of the squares of the other two sides.
Therefore, the square of one of the other side equals the square of the hypothenuse minus the square of the third side. So the square of b
equals the square of c
minus the square of a
.
b² = c²  a²
Finally, the length of b
equals the squared root of the square of c
minus the square of a
.
b = √(c²  a²)
That’s it. We can now build a small Sass function computing the height of the pseudoelement based on a given angle.
@function gettiltedheight($angle) {
$a: (100% / 1%);
$A: (90deg  $angle);
$c: ($a / sin($A));
$b: sqrt(pow($c, 2)  pow($a, 2));
@return (abs($b) * 1%);
}
Note: the pow()
, sqrt()
and sin()
functions can either come from SassyMath, Compass or custom sources.
Building the Tilted Mixin
We’ve done the hardest part, trust me! The last thing to do is build the actual tilted()
mixin. It accepts an angle and a color as argument and generates a pseudoelement.
@mixin tilted($angle, $color) {
$height: gettiltedheight($angle);
position: relative;
backgroundcolor: $color;
&::before {
content: '';
paddingtop: $height;
position: absolute;
left: 0;
right: 0;
bottom: 100%;
backgroundimage: lineargradient($angle, $color 50%, transparent 50%);
}
}
A few things to note here: the mixin applies position: relative
to the container to define a position context for the pseudoelement. When using this mixin on absolute or fixed elements, it might be worth considering removing this declaration from the mixin.
The mixin applies the background color to the container itself as well as pseudo’s gradient, as they have to be synced anyway.
Finally, the pseudoelement’s height has to be conveyed through paddingtop
(or paddingbottom
for that matter) instead of height
. Since the height is expressed in percentages based on the parent’s width, we cannot rely on height
(as it computes from the parent’s height).
Final Thoughts and Going Further
More from this author
For this article, I’ve chosen to go with a simple version of the mixin, which might lack flexibility and could, in theory, present the following problems:
 It is not possible to use it on an element already making use of its
::before
pseudoelement. This could be solved by adding an optional parameter to specify the pseudoelement, defaulting tobefore
.  It is not possible to display a tilted edge at the bottom of the container as
bottom: 0
is currently hardcoded in the mixin core. This could be solved by making it possible to pass an extra position to the mixin.
Also, my existing version uses Sassbased math functions as it was in a Jekyll project, not allowing me to extend the Sass layer. If using nodesass, you could easily pass these functions from JavaScript to Sass through Eyeglass or Sassport, which would be definitely much better.
I hope you liked it! If you can think of anything to improve it, please feel free to share in the comments. :)
See the Pen Tilted Angles in CSS by SitePoint (@SitePoint) on CodePen.

Craig Buckler

Alexander Futekov

Hugo Giraudel


willemvb

Hugo Giraudel

willemvb

Hellonico

Hugo Giraudel

Hellonico

René





René

Vladimir Dumitraskovic

René

Aleks Allianoff

Hugo Giraudel
