Saw-tooth banners with CSS

Taking advantage of CSS background gradients

The idea of exploiting the background property of CSS to create dazzling patterns is not new. Accomplished designer and coder, Lea Verou, curates a mind-boggling collection of background patterns that are crafted solely by manipulating the very property itself, and rendered with the help of standards compliant modern browsers.

I was browsing through iFixit’s manual yesterday (had to replace an old iPhone 4 battery, but that’s another story itself), and came across the following banner:

It may look fine on a regular, non-retina display, but it surely looks fuzzy on my MBP’s retina display. The reason is because the designer have chosen to use an image banner instead of a CSS and text-based one. However, I realized that it is not exceptionally hard to achieve the same effect with the help of CSS backgrounds alone:

The advantage of using a CSS-only method is that it is pixel density agnostic — you do not have to create multiple versions of the same image to cater to different display pixel densities. Also, by using CSS you are saving yourself the hassle of making additional HTTP requests for images, and downsizing the amount of bandwidth consumed for the same visual appearance.

Do note that browser support for multiple backgrounds as well as the modern syntax of background linear gradients is an absolute must. Of course, there are plentyofservices out there that generates the necessary CSS code to ensure that background gradients display appropriately on majority of browsers, but for the sake of brevity I have chosen to leave that out.

The actual implementation

My first intuition is to rely on pseudo-elements positioned absolutely at the top and the bottom, and then I realised that I do not have to do so since we can specify where each background image is positioned by declaring the background-position property for each individual image/gradient.

We have to use several gradients in order to accomplish this task. The top and bottom jagged edges require two gradients each — imagine that you need two mirrored triangles per jagged edge—while the two grey bars on the extreme left and right can be easily done with a horizontal gradient.

The choice of the word ‘gradient’ might be a misnomer here, since there is no gradual transition of colours. By specifying two colour stops sharing the same position along the gradient line, we tell the browser to render the transition as a sharp border.

Also, the start and end positions (0% and 100%) are implicitly implied by the renderer, so we can leave them out.

The top and bottom jagged edges

As mentioned before, you can imagine the jagged edges are being assembled from a mirrored set of triangles — one positioned on the top/bottom-left, the other positioned on the top/bottom-right.

Perhaps an easier way to visualise this issue is with a gif animation below. You can see that the building block of the jagged edges is made up from two horizontally-mirrored triangles. They are created by specifying a linear gradient starting from the top left and right respectively, with two colour stops at the 50% mark.

A gif animation showing the building block of the top jagged edges.

After the basic building block has been made, we declare it’s background size and allow it to repeat along the x-axis. Also, we want to make sure that the position of the jagged edges are horizontally centered. This is done by manipulating the background-size, background-repeat and background-position properties respectively, as enumerated below:

The reason why I chose not to declare a universal background-size is because we still have to add one more gradient later, which will have a different size. In the case of non-uniform CSS properties like this, you will have to specify the individual values for each, comma-separated of course.

Other gradients: Drop shadow

If you want to add a drop shadow to the jagged edges, you can do it by generating a top and bottom vertical gradient. This should be appended to the background-image property. If you don’t and declare a new backgrond-image property, CSS will work as it is intended (cascading, that is), which will overwrite all your previous background image declaration and only honouring the last occuring instance.