Building a stamp border in CSS
For Valentine’s Day this year, I'm running a special event with the folks who have purchased one of my courses. For this event, I wanted to create a landing page that had a scrapbook / hand-made-card kind of vibe.
I wound up creating a “stamp” style effect, and I wanted to write up a lil’ tutorial, so you could see how it works, and use it yourself!
Let's start with the final code. It looks scary, but don't worry! We’ll break it down.
Step 1: We need a background image! Essentially we want to create a square with a hole punched out. The hole should be a circle with the radius equal to "--radius". It defaults to 8px, but it can be set to any number.
Here's what we need to create:
Once we have this image, we can tile it across the entire area. For now, we want a "Connect 4" board like this:
Here's the code at this point:
The radial-gradient is “transparent” from 0% to 98%, and then fades to “white” in those final 2%. This produces a sort of anti-aliasing effect. If we bump it up to 100%, we get a pixellated edge.
Here's a lil’ diagram explaining this gradient:
Remember, we're creating a square image that can be repeated. That square has a size of 24×24 pixels, because it includes the diameter of the circle (16px) and some extra space on each side:
Step 2: we want the holes to run along the edge of the box.
First, let's shift it up and to the left with background-position. We want to shift it up by half of its size (so, 12px in each direction).
This is the result:
The top and left edge look great! But the right and bottom aren't quite right. Unless our box happens to be a perfect multiple of 24px, we won't get that nice stamp effect.
领英推荐
Fortunately, we can solve this problem with a single tweak: background-repeat: round.
Amazing, right? round is similar to repeat, but it rounds the number of repeated images. So, instead of having 20.236 copies running horizontally, it rounds it to 20, and adds a bit of space between each instance.
As a result, it always fits perfectly. ?
Step 3: the last problem is that we only want the holes to run along the edge, not across the entire card.
We can solve this by “painting over” the holes in the middle, by adding a linear-gradient that is solid white, and insetting it by half of the image size (12px).
Here's the code for just the white rectangle:
And that's pretty much it!
We can apply both backgrounds by comma-separating all the values, so we wind up with 2 gradients applied to the same item. And instead of hardcoding all the numbers, we'll use a --radius CSS variable, and calc() for all the calculations.
You can see the effect “in context” on my custom “Valentine’s Day” page.
(Also! If you've purchased either “CSS for JavaScript Developers” or “The Joy of React”, you'll have received a 50%-off coupon you can gift to your valentine, or a friend / co-worker. The coupons only last a few more days!)
Finally, you can poke around with this code yourself here: https://codepen.io/joshwcomeau/pen/VwRqQGP
Thanks again to T. Afif for coming up with such an elegant solution! My original approach used dozens of SVGs ??. I'm way happier with this.
Hope this was helpful ??