How to make wave backgrounds in CSS

Dr. Adam Nielsen
4 min readNov 4, 2022

--

I wanted to have some waves in the background of my content, like this:

This was the SVG that the designer handed to me (if you don’t have a wave SVG, you can generate one at https://getwaves.io/):

I thought it should be easy to implement and was surprised by the problems I would face. As it turned out, the given SVG background was leading me in the wrong direction.

Why using background-image is a bad idea for waves:

My first idea was to put the SVG wave as a background for a div container that contains the content, like this:

<div class="gradient-wave-bg">
<h1>Projekte</h1>
....
</div>

There is a tool https://yoksel.github.io/url-encoder/ which allows you to quickly convert an SVG to the required CSS background-image property.

Basically, I had to remove height from SVG, set width to 100%, and then make a CSS class like this:

.gradient-wave-bg{
padding:100px;
background-size:100%;
background-repeat: no-repeat;
background-image: url("data:image/svg+xml,%3Csvg width='100%' viewBox='0 0 1600 1262' ........");
}

But as I had dynamic content, I run into two major issues. For some content, the wave would not display at full height, showing a sudden end without gradient/opacity dissolving:

This could be solved by setting a min-height to the container, but it would create a large gap when a user had not enough content.

Another problem was, in case of large content, the wave was not recognized any longer:

In short, I was presented with those two issues:

If you don’t have dynamic content, and the SVG background works for desktop and mobile views, then this solution is good. But I had to look for something different.

Alternative: Split SVG wave into gradient and wave

The idea for this solution is to only use the SVG for the top wave, but use a CSS gradient for the content.

In my example, I had to reduce the SVG only to the top part. This can be done by simply changing the height of the SVG viewbox:

Next, I took the bottom color of the SVG box and created a CSS gradient using this tool: https://cssgradient.io/

The HTML was like this:

<div>
<svg ....>
<div class="my-gradient">
My content
</div>
</div>

But this is not working well, as the content is not overlaying the wave

To fix this, we could add a negative margin to the “my-gradient” box, but of course, this would break the gradient design, as it would also start higher:

The trick is, to let the gradient start after X pixels, where X the negative margin that you have to move up.

In principle, that is the solution to the problem, where the content is moved up 350px:

<style>
.my-gradient{
background: linear-gradient(0deg, rgba(255,255,255,1) 0%, rgba(254,226,226,0.8) 25%, rgba(254,226,226,1) calc(100% - 350px),rgba(255,255,255, 0) calc(100% - 349px), rgba(255,255,255,0) 100%);
margin-top:-350px;
}
</style>

This will now work:

Of course, the height of the SVG depends on the width and thus varies on the screen size (in the case of full width). This can be handled by adjusting negative margins (and the implicit gradient offset) with media queries.

Remark: This presented article only works if your SVG gradient is straight vertically or horizontally. If your gradient is inclined (for example 40 degree), you can use the same approach, but calculating the correct css-gradient is complex and depending on the screen-size. For this, its perhaps better to go with the first proposed solution, to use the SVG as background with the mentioned downsited. Otherwise, you could also use Inkscope to make the gradient straight. If these are no options, you can do it with math and JS, but its really complicated, see https://stackoverflow.com/questions/74251937/how-to-continue-gradient-from-svg-with-css/74256001#74256001

--

--