How to use CSS paint API to dynamically create resolution independent variable background

Time:2021-10-22

How to use CSS paint API to dynamically create resolution independent variable background

Modern web applications have a great demand for images, which occupy most of the bytes downloaded from the network. By optimizing them, you can make better use of their performance. If you happen to use geometry as a background image, there is an alternative: you can useCSS Paint APIGenerate the background programmatically.

In this tutorial, we will explore its functionality and explore how to use it to dynamically create a resolution independent dynamic background. This will be the output of this tutorial:

How to use CSS paint API to dynamically create resolution independent variable background

Set item

First, create a newindex.htmlFile and write the following code:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>🎨 CSS Paint API</title>
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <textarea class="pattern"></textarea>
    <script>
      if ('paintWorklet' in CSS) {
        CSS.paintWorklet.addModule('pattern.js');
      }
    </script>
  </body>
</html>

There are several things to note:

  • In line 13, we load a new paint portlet. At present, the global support rate is about 63%. Therefore, we must first check whether it is supportedpaintWorklet。
  • I’m usingtextareaSo we can see how resizing the canvas will redraw the pattern.
  • Finally, you need to create apattern.js(for registering painting workspaces) and astyles.css, we can define several styles in it.

What is a workflow?

Paint portlet is a class that defines what should be painted on the canvas. How they work andcanvasElements are similar. If you have this knowledge before, the code will look familiar. However, they are not 100% the same. For example, text rendering methods are not yet supported in worklets.

Here, we also define CSS styles. This is where we want to use worklets:

.pattern {
  width: 250px;
  height: 250px;
  border: 1px solid #000;

  background-image: paint(pattern);
}

I added a black border so that we can see it bettertextarea。 To reference a paint portlet, you need topaint(worklet-name)Passed as a value tobackground-imageProperties. howeverpatternWhere did it come from? We haven’t defined it yet, so let’s take it as our next step.

Define worklets

openpattern.jsAnd add the following:

class Pattern {
  paint(context, canvas, properties) {

  }
}

registerPaint('pattern', Pattern);

It can be used hereregisterPaintMethod registrationpaintWorklet。 You can reference the first parameter in the CSS defined here. The second parameter is to define the class that should be painted on canvas. It has a with three parameterspaintmethod:

  • context: this will return aPaintRenderingContext2DObject that implementsCanvasRenderingContext2D APISubset of.
  • canvas: This is our canvas, onePaintSizeObject has only two properties: width and height.
  • properties: this will return aStylePropertyMapReadOnlyObject, we can use this object to read CSS properties and their values through JavaScript.

draw rectangle

The next step is to show something, so let’s draw a rectangle. Add the following topaintMethod:

paint(context, canvas, properties) {
  for (let x = 0; x < canvas.height / 20; x++) {
    for (let y = 0; y < canvas.width / 20; y++) {
      const bgColor = (x + y) % 2 === 0 ? '#FFF' : '#FFCC00';

      context.shadowColor = '#212121';
      context.shadowBlur = 10;
      context.shadowOffsetX = 10;
      context.shadowOffsetY = 1;

      context.beginPath();
      context.fillStyle = bgColor;
      context.rect(x * 20, y * 20, 20, 20);
      context.fill();
    }
  }
}

What we do here is to create a nested loop to loop through the width and height of the canvas. Since the size of the rectangle is 20, we will divide the height and width of the rectangle by 20.

In line 4, we can use the modulus operator to switch between the two colors. I also added some shadows for the depth. Finally, we draw a rectangle on the canvas. If you open it in a browser, it should have the following:

How to use CSS paint API to dynamically create resolution independent variable background

Make the background dynamic

Unfortunately, in addition to adjustmenttextareaSize and a glimpse of how the paint API redraws everything, most of which are still static. So let’s make things more dynamic by adding custom CSS properties that we can change.

Open yourstyles.cssAnd add the following lines:

.pattern {
     width: 250px;
     height: 250px;
     border: 1px solid #000;

     background-image: paint(pattern);
+    --pattern-color: #FFCC00;
+    --pattern-size: 23;
+    --pattern-spacing: 0;
+    --pattern-shadow-blur: 10;
+    --pattern-shadow-x: 10;
+    --pattern-shadow-y: 1;
 }

You can add—To define custom CSS properties. These properties can bevar()Function use. But in our case, we will use it in our paint portlet.

Check support in CSS

To ensure that the paint API is supported, we can also check the support in CSS. To this end, we have two options:

  • use@supportsRules: Guardian rules.
  • Use a backup background picture.
/*First option*/
@supports (background: paint(pattern)) {
  /**
   *If this section is evaluated, it means paint API support
   **/
}

/**
 *Second option
 *If the paint API is supported, the latter rule overrides the first rule.
 *If not, CSS invalidates it and applies the rule of URL ().
 **/
.pattern {
  background-image: url(pattern.png);
  background-image: paint(pattern);
}

Accessing parameters in the drawing portlet

To readpattern.jsFor these parameters in, you need to add a new method to the class that defines the paint portlet:

class Pattern {
  //Anything returned by the 'inputproperties' method can be accessed by the paint worklet.
  static get inputProperties() { 
    return [
      '--pattern-color',
      '--pattern-size',
      '--pattern-spacing',
      '--pattern-shadow-blur',
      '--pattern-shadow-x',
      '--pattern-shadow-y'
    ]; 
  }
}

To be inpaintMethod to access these properties internally, you can useproperties.get:

paint(context, canvas, properties) {
  const props = {
    color: properties.get('--pattern-color').toString().trim(),
    size: parseInt(properties.get('--pattern-size').toString()),
    spacing: parseInt(properties.get('--pattern-spacing').toString()),
    shadow: {
      blur: parseInt(properties.get('--pattern-shadow-blur').toString()),
      x: parseInt(properties.get('--pattern-shadow-x').toString()),
      y: parseInt(properties.get('--pattern-shadow-y').toString())
    }
  };
}

For color, we need to convert it to a string. Everything else needs to be converted to numbers. that is becauseproperties.getreturnCSSUnparsedValue。

How to use CSS paint API to dynamically create resolution independent variable background

To make the content more readable, I created two new functions to handle parsing for us:

paint(context, canvas, properties) {
  const getPropertyAsString = property => properties.get(property).toString().trim();
  const getPropertyAsNumber = property => parseInt(properties.get(property).toString());

  const props = {
    color: getPropertyAsString('--pattern-color'),
    size: getPropertyAsNumber('--pattern-size'),
    spacing: getPropertyAsNumber('--pattern-spacing'),
    shadow: {
      blur: getPropertyAsNumber('--pattern-shadow-blur'),
      x: getPropertyAsNumber('--pattern-shadow-x'),
      y: getPropertyAsNumber('--pattern-shadow-y')
    }
  };
}

Now all we have to do is use the correspondingpropValue replaces everything in the for loop:

for (let x = 0; x < canvas.height / props.size; x++) {
  for (let y = 0; y < canvas.width / props.size; y++) {
    const bgColor = (x + y) % 2 === 0 ? '#FFF' : props.color;

    context.shadowColor = '#212121';
    context.shadowBlur = props.shadow.blur;
    context.shadowOffsetX = props.shadow.x;
    context.shadowOffsetY = props.shadow.y;

    context.beginPath();
    context.fillStyle = bgColor;
    context.rect(x * (props.size + props.spacing),
                 y * (props.size + props.spacing), props.size, props.size);
    context.fill();
  }
}

Now go back to your browser and try to change it.

How to use CSS paint API to dynamically create resolution independent variable background

summary

Why is the CSS paint API useful to us? What are the use cases?

Most obviously, it reduces the size of the response. By eliminating the use of images, you can save a network request and thousands of bytes. This improves performance.

For complex CSS effects using DOM elements, you can also reduce the number of nodes on the page. Because you can use the paint API to create complex animations, you don’t need additional empty nodes.

In my opinion, the biggest advantage is that its customizability is much higher than that of static background images. The API can also create resolution independent images, so you don’t have to worry about missing a single screen size.

If you choose to use CSS paint API today, please make sure you provide Polyfill, because it is still not widely used. If you want to adjust the completed project, you can start from thisGitHub warehouseClone it in.


Source:https://medium.com/better-programmingFerenc Almasi, translator: official account, front-end full stack developer.

This article starts with the official account.Front end full stack developer, ID: by zhangbing dev, read the latest articles for the first time, and give priority to publishing new articles for two days. After paying attention to the private letter reply: big gift bag, send a network of high-quality video course online disk materials, which will save you a lot of money!
How to use CSS paint API to dynamically create resolution independent variable background