Move Modal in on a Path

Avatar of Chris Coyier
Chris Coyier on (Updated on )

Have you seen those fancy interactions where a modal window flys down from the top of the page? Maybe it slides in from the side while it fades up to full opacity? Maybe it falls in from above and goes from blurry to focused? Kinda cool, if it fits the vibe of your website.

They always seem to move in a straight line though. Thanks to the fairly new offset-path, they don’t have to!

The offset-path property in CSS exists so that you can place an element in some position along a path. Like, the same path syntax we’re used to from SVG.

Here’s a super simple path. Literally just two instructions:

<path d="M 250,100 S -300,500 -700,-200"></path>

See the Pen A very simple path. by Chris Coyier (@chriscoyier) on CodePen.

I can move that path data right over to CSS and animate along a path there:

See the Pen Animate along path. by Chris Coyier (@chriscoyier) on CodePen.

In this case, it was a @keyframe animation doing the movement, which is essentially just changing the offset-distance value.

The element being animated can be anything! Like, say, a modal ;)

See the Pen Move Modal In on Path by Chris Coyier (@chriscoyier) on CodePen.

In this case, no @keyframes, just a transition and differnet values of offset-distance.

Careful about that rotation!

I’m using offset-rotation: 0deg; here, because if I didn’t, the modal would twist to orient itself along the path. That’s very cool that that is possible, but in this case it’s awkward.

Fallbacks

This kind of thing is easily an enhancement. In the case here, we’re also fading out the opacity and scale, so a fallback is automatically handled. You could also wrap this stuff in a @supports statement so you could have alternate ways of hiding the modal in the case offset-path isn’t supported.

/* Fallback hide/show stuff */
.modal {
  
}
.modal.hide {

}
/* If supported, path-based hiding/showing */
/* Might as well test the rotation feature, as it's also vital */
@supports (offset-rotation: 0deg) {
  .modal {
    offset-rotation: 0deg;
    offset-path: path("M 250,100 S -300,500 -700,-200");
  }
  .modal.hide {
    offset-distance: 100%;
  }
}

Handling Reduced Motion

Not eveyone prefers UI’s with lots of movement, and browsers can accomdate that. We can yank out the motion like this:

@media (prefers-reduced-motion) {
  .modal {
    offset-path: none;
  }
}

I could swear that media query was working a week or two ago, but right now I can’t get it to actually work in any browser I tried (while toggling the setting at the OS level). Eventually, it will work though.

Like the other fallback, make sure to provide an alternate way for the modal to hide itself. I’m also not entirely sure what the best practice is here. Perhaps if you’re designing a “reduced motion” experience on purpose, you’d opt for no movement at all. Just a display block/none change.