$100 off Fall Sale
Master the Fundamentals. Build Better With AI.
Get Discount Now →

Randomly Place an Element Along Edge of Another Element

Let me show you what I saw that started my brain turning:

This is from the website of the podcast The Midnight Rebellion on WBUR.

It’s a cute little crab that walks around on the top of an element! I love it!

It reminded me of a very cool CSS combo I like:

offset-path: border-box;
offset-distance: 20%; /* whatever */Code language: HTTP (http)

I normally think of offset-path as literally taking a path() element (or rect() or something) that sets up a path that you place items on. Then you animate the offset-distance value, which moves the element along that path.

But the path can just be the border of the parent element, which really simplifies things.

Now that Safari has random() (and Chrome has it behind the Experimental Web Features flag), we could make that crab walk to randomized places, perhaps entirely within CSS.

If you’re looking at the demos below in a non-supporting browser, you just won’t see the movement because the offset-distance is applied via CSS random() which will just be ignored. You could do an @supports fallback with hard-coded or JavaScript-generated values if you’re serious about shipping it.

Let’s start simple.

Setting Up The Box

Just a box.

.box {
  width: 200px;
  height: 200px;
  border: 2px solid black;
  position: relative;
}Code language: CSS (css)

Now let’s put something simple inside it.

<div class="box">
  <div class="circle">
  </div>
</div>Code language: HTML, XML (xml)

Put The Thing On The Box

Now I can place the simple circle on the path of the box. I usually think, oh, I’ll have to make a path the same size as the box like offset-path: rect(0 200px 200px 0);, but no, you can just say to use the broder.

.circle {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-color: red;
  offset-path: border-box;
  offset-distance: 20%;
}
Code language: CSS (css)

Not having to use hard pixel values for the path also makes it all nicely responsive to size changes.

Move The Thing

Now let’s move the circle around the path, as that’s the whole thing we’re going for here:

.circle {
  ...
  animation: moveCircle 25s infinite alternate ease-in-out;
}

You’d think we could just set some random positions:

@keyframes moveCircle {
  0%   { offset-distance: random(0%, 100%); }
  25%  { offset-distance: random(0%, 100%); }
  50%  { offset-distance: random(0%, 100%); }
  75%  { offset-distance: random(0%, 100%); }
  100% { offset-distance: random(0%, 100%); }
}Code language: CSS (css)

I can’t quite explain why that doesn’t work, but that doesn’t work. Maybe it’s the nature of the random function within one @keyframes block or something. I think all the numbers compute to the same value despite not using the element-shared keyword to explicitly tell it to do that (maybe it’s implied in this context).

But if we seed each function call with a unique seed it does work. I’ll make it go to 200% as well for more movement.

@keyframes moveCircle {
  0%   { offset-distance: random(--k1, 0%, 200%); }
  25%  { offset-distance: random(--k2, 0%, 200%); }
  50%  { offset-distance: random(--k3, 0%, 200%); }
  75%  { offset-distance: random(--k4, 0%, 200%); }
  100% { offset-distance: random(--k5, 0%, 200%); }
}Code language: CSS (css)

Here we go:

If you only wanted it along the top, you’d randomize up to 25%.

A Glowing Orb & Shadow

I was kind of mesmerized that this worked and detoured myself making other examples. For instance, we could put the circle in a track by building the “borders” with outline and box-shadow instead. Then make the circle impossibly glowy.

But otherwise the same movement applies here. I figure someone could make this glowing orb go through a maze or something cool.

The thing we’re moving doesn’t have to be a circle though of course, that element could be anything. I also thought I’d try making it just a big ol’ shadow and seeing how it feels watching that move around.

Or maybe a whole bunch of them moving differently:

What about the little crab?

Well we can’t do a crab. It’s been done. It’s passé.

We’ll have to do a doggie.

This is more elaborate as it’s not just a “circle” anymore but a whole bunch of (animated) circles that make a dog. But the core concept isn’t any more complicated. It just moves the dog to random positions.

But there are enough little limitations and stuff, I found it satisfying to use a little JavaScript to calculate the new position pseudo-randomly and flip the doggie when necessary.

I’ll leave it as an exercise for the reader to make a <dog-yard>.

Wanna learn CSS Animations deeply?

Leave a Reply

Your email address will not be published. Required fields are marked *

$966,000

Master.dev donates to open source projects through thanks.dev and Open Collective, as well as donates to non-profits like The Last Mile, Annie Canons, and Vets Who Code.