How to create randomly generated backgrounds with the CSS Paint API
Tags: css, tutorial
Published: 2020-03-16 16:02:01

---
title: How to create randomly generated backgrounds with the CSS Paint API
published: true
date: 2020-03-03 14:00:05 UTC
tags: css,tutorial
canonical_url: https://blog.logrocket.com/how-to-create-randomly-generated-backgrounds-with-the-css-paint-api/
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/lhiq10ufyy84clhmoql8.png
---
**Written by [Supun Kavinda](https://blog.logrocket.com/author/supunkavinda/)**✏️

The CSS Paint API (aka CSS Custom Paint) enables developers to write JavaScript functions to draw images into CSS properties such as `background-image`, `border-image`, etc. In this article, we’ll discuss the basics of the CSS Paint API and, specifically, how to create randomly generated backgrounds.

## What is the CSS Paint API

The CSS Paint API is part of [CSS Houdini](https://drafts.css-houdini.org/), a set of low-level APIs that give developers direct access to the CSS Object Model (CSSOM). With Houdini, developers can create their own CSS features, even they are not implemented in the browsers.

Typically, we would add a background image to an element like this:

```jsx
body {
  background-image: url('path/to/image.jpg');
}
```

This image is static. If you think technically, when the browser parses this CSS code, it sends an HTTP request to the URL and fetches the image. It then displays the image as the background image of body.

Unlike static images, you can use the CSS Paint API to create dynamic backgrounds. Keep reading to see how.

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

## Getting started with the CSS Paint API

To begin using the CSS Paint API, start with the following steps.

1. Add the CSS `paint()` function
2. Write an external paint worklet file
3. Invoke the worklet in the main thread

Before creating a dynamic background, let’s start with a simple static background composed of bubbles.

![Static Background Composed of Bubbles](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2020/02/bubble-background-css-paint-api.png?resize=434%2C221&ssl=1)

First, we need to establish an element to style. We’ll use a simple `<div>` element.

```jsx
<!-- index.html -->
<div id="bubble-background"></div>
```

### Step 1: Add the CSS `paint()` function

To use CSS Paint API for the background, add the `paint()` function to the `background-image` property of an element.

```jsx
div#bubble-background {
  width:400px;
  height:200px;
  background-image: paint(bubblePaint);
}
```

`bubblePaint` is the worklet we’ll create in the next steps.

### Step 2: Write an external paint worklet file

We need to keep the worklets in an external JavaScript file — we’ll call it `bubble-paint.js`.

```jsx
// bubble-paint.js
registerPaint('bubblePaint', class {
  paint(ctx, geom) {
    const circleSize = 10; 
    const bodyWidth = geom.width;
    const bodyHeight = geom.height;

    const maxX = Math.floor(bodyWidth / circleSize);
    const maxY = Math.floor(bodyHeight / circleSize); 

    for (let y = 0; y < maxY; y++) {
      for (let x = 0; x < maxX; x++) {
        ctx.fillStyle = '#eee';
        ctx.beginPath();
        ctx.arc(x * circleSize * 2 + circleSize, y * circleSize * 2 + circleSize, circleSize, 0, 2 * Math.PI, true);
        ctx.closePath();
        ctx.fill();
      }
    }
  }
});
```

In this file, the `registerPaint()` function registers a paint worklet. The first parameter is the name of the worklet (same as the one we used in `paint(bubblePaint)`). The next parameter should be a class with the `paint()` method.

The `paint()` method is where we write the JavaScript code to render the image. Here we’ve used two arguments:

1. `ctx` is similar to `CanvasRenderingContext2D` (the return value of `canvas.getContext("2d")`), though not identical. According to [Google](https://developers.google.com/web/updates/2018/01/paintapi):  
"A paint worklet’s context is not 100% the same as a `<canvas>` context. As of now, text rendering methods are missing and for security reasons you cannot read back pixels from the canvas."

2. `geom` contains two elements: the `width` and `height` of the painting element

Inside the function, there is some logic to create the pattern. The `ctx.` functions are what we use to create canvases. If you are not familiar with canvases, I’d suggest you to go through this [Canvas API tutorial](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial).

### Step 3: Invoke the worklet in the main thread

The next step is to invoke the worklet in the main JavaScript thread (usually in the HTML file).

{% codepen https://codepen.io/SupunKavinda/pen/JjdbQZj %}

## Dynamic backgrounds with the CSS Paint API

Let’s make the color and size of the above bubbles dynamic. It’s pretty simple with [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties).

### Step 1: Add CSS variables

```jsx
div#bubble-background {
  --bubble-size: 40;
  --bubble-color: #eee;

  // other styles
}
```

### Step 2: Use CSS variables

To use those CSS variables in the `paint()` method, we must first tell the browser we’re going to use it. This is done by adding the `inputProperties()` static attribute to the class.

```jsx
// bubble-paint.js
registerPaint('bubblePaint', class {
  static get inputProperties() { return ['--bubble-size', '--bubble-color']; }

  paint() { /* */ }
});
```

We can access those properties from the third parameter of the `paint()` function.

```jsx
paint(ctx, geom, properties) {
    const circleSize = parseInt(properties.get('--bubble-size').toString());
    const circleColor = properties.get('--bubble-color').toString(); 

    const bodyWidth = geom.width;
    const bodyHeight = geom.height;

    const maxX = Math.floor(bodyWidth / circleSize);
    const maxY = Math.floor(bodyHeight / circleSize); 

    for (let y = 0; y < maxY; y++) {
      for (let x = 0; x < maxX; x++) {
        ctx.fillStyle = circleColor;
        ctx.beginPath();
        ctx.arc(x * circleSize * 2 + circleSize, y * circleSize * 2 + circleSize, circleSize, 0, 2 * Math.PI, true);
        ctx.closePath();
        ctx.fill();
      }
    }
}
```

![Dynamic Background Made With CSS Variables](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2020/03/dynamic-background-css-variables-3.gif?resize=700%2C392&ssl=1)

That’s how easy it is to create dynamic backgrounds using the CSS Paint API.

This example on [CodePen](https://codepen.io/SupunKavinda/full/abOBeVm) has two different backgrounds for desktop and mobile devices.

The trick is to change the variable values inside a [media query](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries).

```jsx
@media screen and (max-width:600px) {
  div#bubble-background {
    --bubble-size: 20;
    --bubble-color: green; 
  }
}
```

Isn’t that cool? Imagine having static images — you need to have two different images hosted on a server to create those backgrounds. With the CSS Paint API, we can create an endless number of beautiful graphics.

## Creating randomly generated backgrounds 

Now that you're comfortable using the CSS Paint API, let's explore how we can create randomly generated backgrounds using the CSS Paint API. 

The [Math.random()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random) function is the key to making randomly generated backgrounds.

```jsx
Math.random()
// returns a float number inclusive of 0 and exclusive of 1
```

Here we are carrying out roughly the same process as we did earlier; the only difference is that we are using the `Math.random` function in the `paint()` method. 

Let's create a background with a random gradient. 

```jsx
body {
  width:100%;
  height:100%;
  background-image: paint(randomBackground);
}


registerPaint('randomBackground', class {
  paint(ctx, geom) {
    const color1 = getRandomHexColor();
    const color2 = getRandomHexColor();

    const gradient = ctx.createLinearGradient(0, 0, geom.width, 0);
    gradient.addColorStop(0, color1);
    gradient.addColorStop(1, color2);

    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, geom.width, geom.height);
  }
})

function getRandomHexColor() {
  return '#'+ Math.floor(Math.random() * 16777215).toString(16)
}
```

The `getRandomHexColor` function does the math part to create a random hex color. See this [helpful tutorial](https://dev.to/akhil_001/generating-random-color-with-single-line-of-js-code-fhj) for more details about how this works. 

Here's the final result of our random background. If you reload the page, you'll see the random gradients, which you can use to make unique and interesting webpages. 

{% codepen https://codepen.io/SupunKavinda/pen/MWwEXaX %}

You'll also notice that the colors change when you resize the browser window. That's because the browser rerenders the background by calling the `paint()` method with different geom values upon resizing. 

Although `Math.random` merely generates a simple, random number, it's the most important function to know when creating any random background. The range of awesome things you can build using this method is limited only by your imagination.

## Browser compatibility

As amazing as the CSS Paint API is, browser compatibility can be an issue. Only the most recent browser versions support it. Here’s the browser compatibility data from [Is Houdini Ready Yet?](https://ishoudinireadyyet.com/) as of this writing.

![Houdini's Browser Compatibility](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2020/02/browser-compatibility-houdini-1.png?resize=730%2C67&ssl=1)

Therefore, it’s not a good idea to use it in production. However, the Google Chrome Labs team created a [polyfill](https://github.com/GoogleChromeLabs/css-paint-polyfill) that makes the CSS Paint API work in most browsers. Nevertheless, be sure to test dynamic backgrounds on all major browsers before using it in production.

### Detecting browser support

Here’s how to detect browser support in JavaScript:

```jsx
if ('paintWorklet' in CSS) {
  CSS.paintWorklet.addModule('bubble-paint.js');
}
```

And in CSS:

```jsx
@supports (background: paint(id)) {
  div#bubble-background {
    width:400px;
    height:200px;
    background-image: paint(bubblePaint);
  }
}
>
```

### Fallback

CSS fallback properties help improve browser support.

```jsx
aside {
  background-image: url('/path/to/static/image');
  background-image: paint(bubblePaint);
}
```

Browsers that don’t support the `paint()` function won’t recognize that syntax. Therefore, it will ignore the second one and load the URL. Browsers that support it will understand both syntaxes, but the second one will override the first.

## Other interesting use cases for CSS Paint API

Below are some other useful and exciting ways to use the CSS Paint API.

### Image placeholder

With the CSS Paint API, we can draw a placeholder to display while an image is loading. This requires both Houdini’s new CSS Properties and the CSS Paint API.

Note that only a few browsers support the `<image>` syntax for CSS Properties, so it might not work in your browser.

{% codepen https://codepen.io/SupunKavinda/pen/RwPKYBQ %}

### Brush stroke background

I’ve seen countless business websites that use brush strokes to emphasis their marketing keywords. While it’s possible to create brush strokes using canvas, it’s much easier with the CSS Paint API.

{% codepen https://codepen.io/SupunKavinda/pen/VwLPEmd %}

Since it’s only CSS, you can change the variable and reuse the brush stroke as needed.

```jsx
.another-brushstroke {
  --brush-color: #fff;
  background-image: paint(brushstroke);
}
```

## Conclusion

In this guide, we covered the basics of the CSS Paint API and explored how to use it with some examples. You should now have the background you need to create more creative and dynamic images with this new API. Although we focused on `background-image`, you can use the `paint()` function in other properties too (e.g., `border-image`). The CSS Paint API, along with the other CSS Houdini features, represents the future of CSS, so now’s the time to get started.

Once you’ve mastered the basics, learn more about [Houdini](https://css-houdini.rocks/) and check out this gallery of tweakable and downloadable [CSS Paint worklets](https://paintlets.herokuapp.com/).

* * *
## Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, [try LogRocket.](https://logrocket.com/signup/) 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/403rye2ptzx994uhktk1.png)

[LogRocket](https://logrocket.com/signup/) is like a DVR for web apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web apps — [Start monitoring for free.](https://logrocket.com/signup/)
* * *

The post [How to create randomly generated backgrounds with the CSS Paint API](https://blog.logrocket.com/how-to-create-randomly-generated-backgrounds-with-the-css-paint-api/) appeared first on [LogRocket Blog](https://blog.logrocket.com).