For years the latest articles list on my homepage had a neat little CSS trick where each post had wobbly “rough boxes” around them. To create the effect I used a script from aptly named Rough Boxes. One minor problem, CSS Houdini paintlets aren’t – and probably never will be – cross-browser. Do websites have to look the same in every browser? No. But after half a decade of not seeing those wobbly boxes on iOS, I decided to abandon Houdini and draw my own quirky boxes… so I made a web component that you can use today called <wobbly-box>!

View on GitHub

Introducing WobblyBox

WobblyBox is a web component for drawing wobbly boxes around your content. Copy or install the file into your project then wrap any element you want WobblyBox around with the <wobbly-box> Custom Element.

<script type="module" src="wobbly-box.js"></script>
	Any content goes here

Making a WobblyBox with SVG and Border-Image

I wanted something as simple as the Houdini script so I started looking at porting the <canvas>-based paintlet script but couldn’t get over the feeling that SVG might be the best fit.

Inside every SVG path there are some little commands in the path string. Some you may already know like M is for “move”, Z is for “terminate”, L is for “line”. One I didn’t know about was Q which creates a point on the path and bends the path towards that point in a bit of an arc.

Q was a major unlocking for the effect because drawing a box in SVG is relatively easy. Here’s a 100x100 box inset 5px from the edge to account for wobble.

<path d="M5,5 95,5 95,95 5,95 5,5Z" />

The next step was adding in Q points on the path in between the points that make my box wobble…

<path d="M5,5 Q50,0 95,5 Q100,50 95,95 Q50,100 5,95 Q0,50 5,5Z" />

I wanted a bit of randomization in the borders, just like the original so I used JavaScript to generate random Q values within a few pixels positive or negative. I made some artistic choices to make it not completely random and have the top and bottom sides have the same bend while the inline sides of the box mirror each other.

The final step was to get this box I made to surround the content. I had an image that I wanted to use as a border… so I thought the not-often-used border-image property might be appropriate.

border-image is a complex but awesome property. To be honest, I avoid border-image in my day-to-day because of its complexity, but it seemed well-suited here. It creates a 9-slice border box around an element. With a single image and some magic numbers you the images crops and repeats the image appropriately to surround the element. Back in the wild west days of the internet this was a popular technique but required a lot of extra divs. I think border-radius and the death of skeuomorphism ultimately depopularized the technique.

Then I wrapped it all up in a web component because that seemed like the easiest delivery vehicle. I’m happy with the final effect and it’s close to what I had before except that it avoids redrawing the entire border on resize, so that’s a plus.

Not a big roadmap

I could have – maybe should have – used a pre-existing solution like WiredJS components. I like how WiredJS looks, especially for rough prototyping, but it’s probably overkill for my little boxes. I like how simple <wobbly-box> is; more cartoony and a lot more dumb.

If I were to make some improvements, there’s three big ticket items I’m considering…

  1. It’d be cool to control --wobble, --thickness, as well as --border-color
  2. Get rid of magic numbers
  3. Sometimes there’s a little “tuck” in the corners due to how CSS’s 9-slice borders works, I’ve tried to nudge those but it’s imperfect. It’s kind of cute, so potentially worth keeping.

But those improvements are not for today! I just needed this to work on Safari and Firefox.