Light Dark
Ahmad Nassri

CTO of npm, Inc. Founder of Tech Masters Community, Member of Node.js Foundation, Advocate of all things Open Source, Startup Advisor, Entrepreneur.

Previously: TELUS, Kong, CBC/Radio-Canada, BlackBerry

Homeblog

Ultimate Guide to Non-Rectangular Headers

Non-Rectangular Headers have recently been taken over the web. This “new” design trend seems simple and straightforward at first, but can be a little tricky to accomplish.
Originally Posted On CodePen.io
Translated into:

Non-Rectangular Headers have recently been taken over the web. This “new” design trend seems simple and straightforward at first, but can be a little tricky to accomplish.

Jon Moore recently put together a collection of some design styles he’s come across with non-rectangular headers.

As it happens, I’ve also been tinkering with diagonal headers over the holidays (what else do you do with all your free time?)

So, for some more fun, I’m going to tackle a variety of those design approaches, provide all the possible methods to achieve them (in pure CSS) along with a detailed comparison, comparing simplicity, portability, cross-browser support, and performance!

Part 1: Pure CSS Diagonal Separators

This is likely the most popular design choice for non-rectangular headers, and so there has been a large number of articles and posts that explore different methods to achieve this effect. However, most seem to focus on the end result, rather than providing a flexible approach that is both responsive and customizable.

The most common example, is perhaps demonstrated by Jon’s article’s own image:

example

We’re going to aim to build a separator that fits the following criteria:

✔ Simple CSS

Will the CSS styles be simple to construct in both vertical & horizontal flavours, and are they easily re-usable anywhere on the page (not just as a header)?

✔ Generated Content:

Can it be created with generated content (::before & ::after)? or does it require hardcoded HTML Elements?

✔ Cross Browser Support

Will it function across all browsers (desktop & mobile) Without any polyfills or JavaScript support?

✔ Performance

The most important criteria! we’re looking for painting time below 100ms as a benchmark.

Comparision Matrix

Method Simple CSS Generated Content Cross Browser Support Performance
Borders
Gradient Background Image
CSS Shapes
SVG Background Image
SVG Mask
CSS3 2D Transforms

Results

For more details, please consult the code repository on Github, which includes further examples.

Diagonal Separators are just one of many design styles, what should I tackle next? Tweet me with suggestions!


Notes:

  • CSS Variables are used in the code snippets blow for demonstration purposes and future prosperity, they are yet to be supported across all browsers and rendering engines!
  • reversed & vertical variants listed below are verbose for demonstration purposes
    • for simple multi directional classes, use the rotate() function as needed
    • inspect the styles used in each method for a detailed example_
  • Use with transparent colors (e.g. to overlay an image, or content) will require absolute or manual positioning:
    • see the repo for a detailed example

Borders

✔ Simple CSS

.separator {
  width: 0;
  height: 0;
  border-style: solid;
  border-width: var(--height) var(--width) 0 0;
  border-color: var(--top-color) var(--bottom-color) transparent transparent;
}
Reversed
.separator.reverse {
  border-width: var(--height) 0 0 var(--width);
  border-color: var(--top-color) transparent transparent var(--bottom-color);
}
Vertical
.separator.vertical {
  border-width: var(--height) var(--width) 0 0;
  border-color: var(--left-color) var(--right-color) transparent transparent;
}
Reversed Vertical
.separator.vertical.reverse {
  border-width: 0 var(--width) var(--height) 0;
  border-color: transparent var(--left-color) var(--right-color) transparent;
}

Notes:

✔ Generated Content

Can be used with the ::before and ::after pseudo-elements to generate HTML content for the separator without directly modifying your DOM.

Example
section {
  ...
}

section::after {
  content: '';
  display: block;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 50px 300px 0 0;
  border-color: yellow black transparent transparent;
}

✔ Cross Browser Support

Supported on all browsers

✖ Performance

Clocking in a paint time of 105ms , this doesn’t quite reach our benchmark, but is not a bad result!


Gradient Background Image

✔ Simple CSS

.separator {
  width: var(--width);
  height: var(--height);
  background-image: linear-gradient(to bottom right, var(--top-color), var(--top-color) 50%, var(--bottom-color) 50%, var(--bottom-color));
}
Reversed
.separator.reverse {
  background-image: linear-gradient(to bottom left, var(--top-color), var(--top-color) 50%, var(--bottom-color) 50%, var(--bottom-color));
}
Reversed Vertical
.separator.vertical.reverse {
  background-image: linear-gradient(to top right, var(--top-color), var(--top-color) 50%, var(--bottom-color) 50%, var(--bottom-color));
}

Notes:

✔ Generated Content

Can be used with the ::before and ::after pseudo-elements to generate HTML content for the separator without directly modifying your DOM.

Example
section {
  ...
}

section::after {
  width: 100%;
  height: 50px;
  background-image: linear-gradient(to bottom right, yellow, yellow 50%, black 50%, black);
}

✖ Cross Browser Support

Partial support

Supported in all major browsers, with the exception of Opera Mini.

✔ Performance

👑 The fastest result! 2.1ms


CSS Shapes

✖ Simple CSS

.separator {
  position: relative;
  width: var(--width);
  height: var(--height);
}

.separator::before {
  position: absolute;
  content: "";
  width: 100%;
  height: 100%;
  background-color: var(--top-color);
  clip-path: polygon(100% 0, 0 0, 0 100%);
}

.separator::after {
  position: absolute;
  content: "";
  width: 100%;
  height: 100%;
  background-color: var(--bottom-color);
  clip-path: polygon(100% 0, 0 100%, 100% 100%);
}
Reversed
.separator.reverse::before {
  clip-path: polygon(0 0, 100% 0, 100% 100%);
}

.separator.reverse::after {
  clip-path: polygon(0 0, 0% 100%, 100% 100%);
}
Reversed Vertical
.separator.vertical.reverse::before {
  clip-path: polygon(0 0, 0% 100%, 100% 100%);
}

.separator.vertical.reverse::after {
  clip-path: polygon(0 0, 100% 0, 100% 100%);
}

Notes:

✖ Generated Content

Cannot be used with the ::before and ::after pseudo-elements as it relies on them already to generate the HTML content for the separator.

✖ Cross Browser Support

Partial support

✖ Performance


SVG Background Image

Note: The Pen is only an example of embedded SVG DataURI, for more examples (external SVG file, SVG Shadow) check out the repo

❓ Simple CSS

This is not as straightforward to determine, here’s why:

  • ✔ Simple = using one variant and external SVG image
  • ✖ Not = embedded SVG as a Data URI requires character escaping and encoding
.separator {
  width: var(--width);
  height: var(--height);
  background-image: url(diagonal.svg);
  background-repeat: no-repeat;
  background-size: 100% 100%;
}
Reversed
.separator.reverse {
  transform: rotateY(180deg);
}
Reversed vertical
.separator.vertical.reverse {
  transform: rotateX(180deg);
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="none">
  <polygon fill="#f44336" points="100 0, 0 100, 0 0"/>
  <polygon fill="#2196F3" points="100 0, 0 100, 100 100"/>
</svg>

Notes:

✔ Generated Content

Can be used with the ::before and ::after pseudo-elements to generate HTML content for the separator without directly modifying your DOM.

Example
section {
  ...
}

section::after {
  content: '';
  display: block;
  width: 100%;
  height: 50px;
  background-image: url(diagonal.svg);
  background-repeat: no-repeat;
  background-size: 100% 100%;
}

✔ Cross Browser Support

Supported on all browsers

✔ Performance

👑 Surprisingly, this came in second to Gradients method in terms of paint speed, despite the page having more complex examples and varieties! (see repo)


SVG Mask

✖ Simple CSS

.separator {
  position: relative;
  width: var(--width);
  height: var(--height);
}

.separator::before {
  position: absolute;
  content: '';
  display: block;
  width: 100%;
  height: 100%;
  background-color: var(--top-color);
  mask-image: url(diagonal.svg#top);
  mask-size: cover;
}

.separator::after {
  position: absolute;
  content: '';
  display: block;
  width: 100%;
  height: 100%;
  background-color: var(--bottom-color);
  mask-image: url(diagonal.svg#bottom);
  mask-size: cover;
}
Reversed
.separator.reverse::before {
  mask-image: url(diagonal.svg#top-reverse);
}

.separator.reverse::after {
  mask-image: url(diagonal.svg#bottom-reverse);
}

Notes:

✖ Generated Content

Cannot be used with the ::before and ::after pseudo-elements as it relies on them already to generate the HTML content for the separator.

✖ Cross Browser Support

Partial support

Note:

✖ Performance

CSS3 2D Transforms

✖ Simple CSS

:root {
  --vertical-angel: 108.5deg;
  --horizontal-angel: 18.5deg;
}

.separator {
  width: var(--width);
  height: var(--height);
  overflow: hidden;
}

.separator::before {
  display: block;
  content: '';
  width: 100%;
  height: 100%;
  background-color: var(--top-color);
  transform: skewY(calc(-1 * var(--horizontal-angel)));
  transform-origin: bottom left;
}

.separator::after {
  display: block;
  content: '';
  width: 100%;
  height: 100%;
  background-color: var(--bottom-color);
  transform: skewY(calc(-1 * var(--horizontal-angel)));
  transform-origin: bottom left;
}
Reversed
.separator.reverse::before,
.separator.reverse::after {
  transform: skewY(var(--horizontal-angel));
  transform-origin: bottom right;
}
Vertical
.separator.vertical::before,
.separator.vertical::after {
  transform: skewY(var(--vertical-angel));
}
Reversed Vertical
.separator.vertical.reverse {
  position: relative;
}

.separator.vertical.reverse::before {
  position: absolute;
  transform: skewY(calc(-1 * var(--vertical-angel)));
  transform-origin: bottom left;
}

.separator.vertical.reverse::after {
  position: absolute;
  transform: skewY(calc(-1 * var(--vertical-angel)));
  transform-origin: top right;
}

Notes:

✖ Generated Content

Cannot be used with the ::before and ::after pseudo-elements as it relies on them already to generate the HTML content for the separator.

✖ Cross Browser Support

Partial support

Supported in all major browsers, with the exception of Opera Mini.

✖ Performance


Diagonal Separators are just one of many design styles, what should I tackle next? Tweet me with suggestions!

Comments
Contact