Creating smooth cornered rectangles with CSS Houdini

Published Sun Jan 07 2024 21:00:00 GMT+0000 (Coordinated Universal Time)
Tech

TL;DR

I created a Houdini CSS registerPaint module for applying smooth-corners to rectangles in CSS.
You can find it here: smooth-corners Houdini CSS module
. You can also get it by installing the NPM package @george-gillams/components and importing the file from @george-gillams/components/smooth-corners-container/worklet.js

Background

Smooth rounded corners look great. I guess they’re just—smoother—than traditional rounded corners. That's why Apple use them extensively in both their hardware and software, and it's why Figma has the option to smooth out corners of any rectangle.
A squircle vs a square with rounded cornersA squircle vs a square with rounded corners
A squircle vs a square with rounded cornersA squircle vs a square with rounded corners

Currently, web developers don't have a great way to put smooth-corners in the browser. There is no CSS standard for them, and so the best we can do to create smooth-corners across all browsers is calculate an SVG path, and clip an element to that path.
Unfortunately this mechanism is inefficient and cumbersome.

A better solution with CSS Houdini

CSS Houdini is a project that aims to make CSS extensible, by allowing developers to inject code that the browser will run during the rendering pipeline. You can read more about this in Vincent’s blog post about CSS Houdini
.
One limitation of Houdini is that we still have to wait for JS to be loaded before our Houdini CSS extension will be available. If we had proper browser support for smooth-corners, that would not be necessary.

Building on the squircle

On the CSS Houdini examples website, there is an example of a registerPaint module that enables squircles in CSS
. (Note that this only works in supported browsers
— Chrome and Edge at the time of writing).
Unfortunately, this example does not support all rectangles — just squares.
I therefore took inspiration from the code, as well as some equations from Chamberlain Fong’s paper on Squircular Calculations
, and created my own equation for smooth-corners that works regardless of width/height ratio.
The mathematical equation I used to represent a rectangle with smooth cornersThe mathematical equation I used to represent a rectangle with smooth corners
The mathematical equation I used to represent a rectangle with smooth cornersThe mathematical equation I used to represent a rectangle with smooth corners

A graph showing a line in the shape of a rectangle with smooth-cornersA graph showing a line in the shape of a rectangle with smooth-corners
A graph showing a line in the shape of a rectangle with smooth-cornersA graph showing a line in the shape of a rectangle with smooth-corners

You can view this graph equation live
and change the height, width, and roundedness.
I then applied this in a Houdini module, and this was the result:
The resulting smooth-cornered rectangle rendered in Chrome using my Houdini CSS workletThe resulting smooth-cornered rectangle rendered in Chrome using my Houdini CSS worklet
The resulting smooth-cornered rectangle rendered in Chrome using my Houdini CSS workletThe resulting smooth-cornered rectangle rendered in Chrome using my Houdini CSS worklet

I also included support for different corner sizes on the same shape, so you can make some corners entirely square while others are more rounded.
A smooth-cornered rectangle with differently-rounded corners rendered in Chrome using my Houdini CSS workletA smooth-cornered rectangle with differently-rounded corners rendered in Chrome using my Houdini CSS worklet
A smooth-cornered rectangle with differently-rounded corners rendered in Chrome using my Houdini CSS workletA smooth-cornered rectangle with differently-rounded corners rendered in Chrome using my Houdini CSS worklet

Fallbacks

For browsers that lack Houdini CSS support, we should either fall back to a regular rounded corner. Alternatively, we could use a less-performant SVG clip-path implementation as a fallback.

As a component

Having created the module, I then extended the mechanism into a fully-fledged smooth-corners-container React component
which uses SVG masking as a fallback in browsers that don’t implement the Houdini CSS Paint API. You can view the smooth-corners component in Storybook
.
To support rendering without JS and SEO, I’ve ensured that we only use the Houdini CSS implementation when JS is available.

Copyright

Most of my photos are licensed under Creative Commons BY-SA 3.0
.
If you are unsure about your right to use them please contact me.