small icon of Elian

Elian.codes

Article

๐ŸŽ‰ Write less code by using CSS Houdini

Some time ago I started looking into CSS Houdini. Today was finally the day that I wrote a package to replace some of my shitty code with some CSS Houdini magic

10/13/2021 Elian Van Cutsem

← Back to blog

Write less code by using CSS Houdini

Some time ago I started looking into CSS Houdini. It was awesome already, you could do a lot of cool things with it, but I didnโ€™t really see a use of the available things at the time. Today was the day that I looked back at CSS Houdini and refactored some of my code to use CSS Houdini.

Writing the package

The thing I wanted to create in Houdini is my background gradient. This isnโ€™t hard to do in CSS or anything, but 1. it was a good practice to learn CSS Houdini 2. required less code 3. now supports CSS custom properties out of the box.

Writing a package for Houdini isnโ€™t that hard (at least, this was a simple one, I imagine some are way harder).

You start by defining what your package should do:

class ElianCodesBg {
  static get inputProperties() {
    return ["--color-for-bg"];
  }
  static get inputArguments() {
    return ["<color>"];
  }

  paint(ctx, size, props) {
    ctx.fillStyle = props.get("--color-for-bg");
    ctx.fillRect(size.width / 2, 0, size.width, size.height);
  }
}
registerPaint("eliancodes-bg", ElianCodesBg);

here we defined that the Worklet should use one input property called --color-for-bg, which is a color type. Next we define that it should draw a rectangle with half of the width of the element and the same height.

At last, the Paint get registered as eliancodes-bg so you can use that in your CSS like:

background-image: paint(eliancodes-bg);

Thatโ€™s basically it!

The package is available on NPM, although it should be fine to load it over CDN.

Using the package

add this code to your html as a <script> or add it in an already linked JS-file.

CSS.paintWorklet.addModule("https://unpkg.com/eliancodes-bg@0.0.1/index.js");

using that javascript, we could just set a custom color in the CSS file

.bg {
  --color-for-bg: lightgreen;
  background-image: paint(eliancodes-bg);
}

depending on the element you set the class="bg" on, half of the background will be filled with the --color-for-bg color.

Check the codepen here: https://codepen.io/elianvancutsem/pen/wvqaXQV

Refactoring the old code

Now that the package was published I only needed to rewrite some of my older Astro & TypeScript code to use regular CSS and Houdini instead of a lot of TypeScript code.

The index background

If you look at my website, one of the first things people notice, is that the background on the homepage has a 50% white, 50% random color gradient. Prevously, the background was generated by a lot of shitty TypeScript code that looked at the class in the <html> element and would add style="background: linear-gradient(90deg, #FFF 50%, ${color.code} 50%)" to the element in the case that the dark (TailwindCSS darkmode) class wasnโ€™t there. This was the code before:

const setBgColor = (color) => {
  if (
    document.querySelector("html").getAttribute("class") != undefined &&
    !document.querySelector("html").getAttribute("class").includes("dark") &&
    document.querySelector("html").getAttribute("class").includes("index-bg")
  ) {
    document
      .querySelector("html")
      .setAttribute(
        "style",
        `background: linear-gradient(90deg, #FFF 50%, ${color.code} 50%)`,
      );
  } else if (
    document.querySelector("html").getAttribute("class").includes("dark")
  ) {
    document
      .querySelector("html")
      .setAttribute(
        "style",
        `background: linear-gradient(90deg, #000 50%, #000 50%)`,
      );
  } else {
    document.querySelector("html").setAttribute("style", "");
  }
};

after upgrading to houdini, it got replaced by:

document.documentElement.style.setProperty(
  "--color-for-bg",
  document.documentElement.classList.contains("dark") ? "black" : color.code,
);

The --color-for-bg custom property gets used by the Houdini package and will make the background work without any other code!

Adding a polyfill

One of the things you notice when playing around with CSS Houdini, is that itโ€™s not supported (yet) in all browsers. The Paint API already shipped in chrome, but is still under review in Firefox for example. Luckilly, the guys at Houdini created a polyfill that will make it work with all browsers and itโ€™s very easy to add.

Just add this line in your body to use the polyfill on not-supported browsers:

<script src="https://unpkg.com/css-paint-polyfill"></script>

The use-color class

The use-color class is the class I custom set to change the textcolor of different elements to the active accent-color. Also this got extremely refactored! Before I would manually find all elements with the use-color class and add a tailwind text-color-${color.class} class, so that Tailwind would render it correctly.

To do this, I wrote some code:

const color = getNewColor();
document.querySelectorAll(".use-color").forEach((element) => {
  colors.forEach((color) => element.classList.remove(`text-${color.class}`));
  element.classList.add(`text-${color.class}`);
});

The getNewColor() in above example would return a random color from an array with the tailwind class and color code as values.

const color = { class: "primary-green", code: "#86EFAC" };

This got refactored to a very simple method where a CSS custom property would get changed from TypeScript:

:root {
  --random-color: lightgreen;
}

.use-color {
  color: var(--random-color);
}
const color = getNewColor();
document.documentElement.style.setProperty("--random-color", color.code);

This way a lot of code is replaced by way better lines!

← Back to blog

Fresh writing

Recent blogposts

Go to blog