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.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.
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:
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.
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.