Transitions✨ Premium

Portal Open

An appearance in two beats: a glowing cyan ring opens first in the center of the frame, then the content is revealed by a circle growing from the middle (clip-path: circle()), while the ring widens and fades; on closing, the circle shrinks back and the ring lights up again before retracting. 1.7 KB of JavaScript, closed content out of keyboard reach, a 0.15 s fade under reduced motion.

CSSclip-pathCircle

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Transitions has 52 effects, including 9 free. Explore the category →

3 usage examples

A portal to another map — a browser adventure game — Portal Open example 1

① A portal to another map — a browser adventure game

WhenThe hero reaches the end of the Ashen Forest path and the player clicks "Step through the portal": the ring lights up, then the Ysmir Ice Fields map appears inside the circle.
WhyThe ring lighting up before the opening announces the passage; the player understands they are changing worlds before even seeing the new map.
Settings220 px round frame (border-radius: 50%) set on the map; ring adjusted to 200 then 240 px; content in an icy blue gradient with two sharp white shapes; the code's durations unchanged.
A sign language interpreter — a benefits office's video desk — Portal Open example 2

② A sign language interpreter — a benefits office's video desk

WhenDuring an online appointment about a housing benefit file, the user asks for a sign language interpreter: the blue ring lights up in the video window, then the interpreter's picture is revealed.
WhyThe ring signals that someone is coming before the video shows: the deaf user has time to look at the right place.
Settings236 × 164 px window, blue #1d4ed8 ring (180 then 280 px); "live" label on a dark band at the bottom of the video; help text under the button.
A silo's inside camera — a grain cooperative's monitoring screen — Portal Open example 3

③ A silo's inside camera — a grain cooperative's monitoring screen

WhenThe technician checks silo 4 (soft wheat, 68%) and clicks "View through the hatch": the circle opens on the camera image above the grain.
WhyThe opening circle echoes the hatch's shape: you go from the diagram to the real view of the grain without changing screens.
Settings220 px round frame ringed in gray like a hatch; golden #fbbf24 ring; content as a grain texture (two patterned radial-gradients); silo diagram on the left.

How it works

The .portal-open-wrapper frame (200 × 120 px, 14 px corners, overflow: hidden) stacks two elements. The .portal-open-content, a cyan #06b6d4 → #0891b2 gradient, is fully masked at rest by clip-path: circle(0 at 50% 50%): a zero-radius circle in the center. The .portal-open-ring is a centered round with a 3 px #22d3ee border and a glow (outer and inner box-shadow), at size 0 and opacity 0.

The script (1.7 KB) splits the opening into three steps. At 0 ms, the .portal-open-active class grows the ring to 200 px and lights it in 0.5 s. At 200 ms, .portal-open-visible opens the clipping circle to circle(75%) in 0.7 s (enough to reach the frame's corners). At 500 ms, .portal-open-ring-fade widens the ring to 240 px and fades it in 0.4 s after a 0.3 s wait. Measured in Chromium 151: at 150 ms, a half-lit 109 px ring and content still hidden; at 400 ms, circle at 40% and ring almost full; around 1.2 s, content whole and ring off — same steps within a few percent in Firefox 153 and WebKit 26.5. Closing reverses the order: the ring lights up again, the circle closes, and the ring retracts 400 ms later.

Each click first cancels the pending timers: a fast double click ends in a consistent state (measured: portal closed, button at aria-expanded="false"). The button points to its frame with aria-controls, which allows several independent portals on the page. When closed, the content carries inert: invisible, it must not be reached by keyboard or read either. The ring animates width and height rather than a scale, to keep a crisp 3 px border at every size; it is a single absolutely positioned element, so the layout cost stays minimal.

Accessibility

  • Inert closed content: a clip-path hides the content from the eye, not from the keyboard or screen readers. The script therefore sets inert on the content while the portal is closed. Measured with a link in the content: portal closed, Tab goes straight to the button (Chromium, Firefox); open, Tab reaches the link.
  • Button state: a real <button> with aria-controls and aria-expanded, updated on every click (measured). The purely decorative ring is aria-hidden.
  • Reduced motion: under prefers-reduced-motion, the ring is not shown and the circle does not open: the content fades in over 0.15 s, after the same 200 ms (measured in all three engines: content at 1 at 400 ms, no clip-path).
  • Glow and photosensitivity: the ring lights up once per opening, with no repeated flashing: no flash-related risk. White text contrast on the cyan gradient: 2.4 to 3.7:1, too low for body text — darken the gradient (#0e7490 → #155e75: 5.4 and 7.3:1) or put the text on a dark band, as scene 2 does.

Browser compatibility

CSS (animated clip-path: circle(), size and opacity transitions) + 1.7 KB of JavaScript, no dependency. Measured in Chromium 151, Firefox 153 and WebKit 26.5: same opening and closing steps, double click with no stuck state, inert content once closed, two independent portals. Animating clip-path: circle() works unprefixed since Chrome 55, Firefox 54 and Safari 12.1; the inert attribute since Chrome 102, Firefox 112 and Safari 15.5.

Chrome 102+✓ Full
Firefox 112+✓ Full
Safari 15.5+✓ Full
Edge 102+✓ Full
Mobile iOS 15.5+✓ Full
Android Chrome 102+✓ Full

Before inert (Chrome 55-101, Safari 12.1-15.4), the animation is the same but the closed content stays reachable by keyboard. Without JavaScript, the portal stays closed. Under reduced motion, a short fade replaces the ring and the circle.

The code

HTML structure to paste into your page (the CSS + JS come with Premium):

index.html — structure
<div class="portal-open-stage">
  <div class="portal-open-wrapper" id="portalOpenWrapper">
    <div class="portal-open-ring" aria-hidden="true"></div>
    <div class="portal-open-content">…</div>
  </div>
  <button class="portal-open-btn" type="button" aria-controls="portalOpenWrapper" aria-expanded="false">…</button>
</div>
Unlock the full code — $9.90/mo incl. tax

The full HTML + CSS + JS of Portal Open, ready to paste — plus all 840 effects. Or $299 once, lifetime access.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Offsets (JS — 200 and 500 ms on opening, 400 ms on closing) ring, then circle at 200 ms, fade at 500 ms Raise the first to 400 ms for a ring that "charges" longer before opening; at 0, ring and circle start together and the announcing effect is gone.
Ring size (CSS — 200px then 240px) 200 px then 240 px when fading Match it to your frame: roughly the frame's smaller dimension, then +20%. A ring larger than the frame is clipped by its overflow: hidden.
Circle opening (CSS — circle(75% at 50% 50%), 0.7 s) 75%: the corners are reached at 50% 100% starts the circle from the bottom; for a very elongated frame, go up to 100% so the corners are not left empty.
Color (CSS — border-color and box-shadow of .portal-open-ring) cyan #22d3ee with a glow Change it on the ring's base rule, not only on the active state, otherwise it goes back to cyan during closing.
Frame shape (CSS — .portal-open-wrapper) 200 × 120 px, 14 px corners border-radius: 50% on a square frame gives a real porthole; the clipping circle and the ring stay centered.

FAQ

So that closing is the exact reverse of opening: the circle closes while the ring goes back to 200 px and lights up, then the ring retracts in turn 400 ms later. The portal visibly "closes" instead of vanishing. If you prefer a sober closing, remove the line that takes off .portal-open-ring-fade in the closing branch: the ring will stay off.
A fade or a lone circle reveal the content in one beat. Portal Open adds a first one, the ring, which announces the opening before the content is visible: useful when users need to know where to look (an incoming video, a map change).
Yes: the content is an ordinary block, clipped by clip-path. A <video> or an <img> with object-fit: cover over 100% of the frame is revealed the same way. Remember to start playback only on opening, and to pause it on closing.