Portal Open
Une apparition en deux temps : un anneau lumineux cyan s'ouvre d'abord au centre du cadre, puis le contenu est découvert par un cercle qui grandit depuis le milieu (clip-path: circle()), pendant que l'anneau s'élargit et s'efface ; à la fermeture, le cercle se referme et l'anneau se rallume avant de se rétracter. 1,7 Ko de JavaScript, contenu fermé hors de portée du clavier, fondu de 0,15 s sous mouvement réduit.
Mis à jour le
Cet effet fait partie d'Effect.Labs — 840 effets vanilla, une partie gratuite, une partie premium. Transitions comprend 52 effets, dont 9 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
Le cadre .portal-open-wrapper (200 × 120 px, coins de 14 px, overflow: hidden) superpose deux éléments. Le contenu .portal-open-content, dégradé cyan #06b6d4 → #0891b2, est entièrement masqué au repos par clip-path: circle(0 at 50% 50%) : un cercle de rayon nul au centre. L'anneau .portal-open-ring est un rond centré de 3 px de bordure #22d3ee avec une lueur (box-shadow extérieure et intérieure), de taille 0 et d'opacité 0.
Le script (1,7 Ko) découpe l'ouverture en trois étapes. À 0 ms, la classe .portal-open-active fait grandir l'anneau à 200 px et l'allume en 0,5 s. À 200 ms, .portal-open-visible ouvre le cercle de découpe jusqu'à circle(75%) en 0,7 s (assez pour atteindre les coins du cadre). À 500 ms, .portal-open-ring-fade élargit l'anneau à 240 px et l'éteint en 0,4 s après 0,3 s d'attente. Mesuré dans Chromium 151 : à 150 ms, anneau de 109 px à demi allumé et contenu encore caché ; à 400 ms, cercle à 40 % et anneau presque plein ; vers 1,2 s, contenu entier et anneau éteint — mêmes étapes à quelques pour cent près dans Firefox 153 et WebKit 26.5. La fermeture inverse l'ordre : l'anneau se rallume, le cercle se referme, et l'anneau se rétracte 400 ms plus tard.
Chaque clic annule d'abord les minuteurs en cours : un double clic rapide finit dans un état cohérent (mesuré : portail fermé, bouton à aria-expanded="false"). Le bouton désigne son cadre par aria-controls, ce qui permet plusieurs portails indépendants dans la page. Fermé, le contenu porte inert : invisible, il ne doit pas non plus être atteint au clavier ni lu. L'anneau anime width et height plutôt qu'une échelle, pour garder une bordure de 3 px nette à toutes les tailles ; c'est un élément seul en position absolue, le recalcul reste minime.
Accessibilité
- Contenu fermé inerte : un
clip-pathcache le contenu à l'œil, pas au clavier ni aux lecteurs d'écran. Le script pose doncinertsur le contenu tant que le portail est fermé. Mesuré avec un lien dans le contenu : portail fermé, Tab passe directement au bouton (Chromium, Firefox) ; ouvert, Tab atteint le lien. - État du bouton : vrai
<button>avecaria-controlsetaria-expanded, mis à jour à chaque clic (mesuré). L'anneau, purement décoratif, est enaria-hidden. - Mouvement réduit : sous
prefers-reduced-motion, l'anneau n'est pas affiché et le cercle ne s'ouvre pas : le contenu apparaît en fondu de 0,15 s, après les mêmes 200 ms (mesuré dans les trois moteurs : contenu à 1 à 400 ms, aucunclip-path). - Lueur et épilepsie : l'anneau s'allume une fois par ouverture, sans clignotement répété : aucun risque lié aux flashs. Contraste du texte blanc sur le dégradé cyan : 2,4 à 3,7:1, trop faible pour un texte courant — foncez le dégradé (
#0e7490→#155e75: 5,4 et 7,3:1) ou posez le texte sur un bandeau sombre, comme la scène 2.
Compatibilité navigateur
CSS (clip-path: circle() animé, transitions de taille et d'opacité) + 1,7 Ko de JavaScript, aucune dépendance. Mesuré dans Chromium 151, Firefox 153 et WebKit 26.5 : mêmes étapes d'ouverture et de fermeture, double clic sans état bloqué, contenu inerte une fois fermé, deux portails indépendants. L'animation de clip-path: circle() existe sans préfixe depuis Chrome 55, Firefox 54 et Safari 12.1 ; l'attribut inert depuis Chrome 102, Firefox 112 et Safari 15.5.
Avant inert (Chrome 55-101, Safari 12.1-15.4), l'animation est la même mais le contenu fermé reste atteignable au clavier. Sans JavaScript, le portail reste fermé. Sous mouvement réduit, un fondu court remplace l'anneau et le cercle.
Le code
Structure HTML à coller dans votre page (le CSS + JS sont inclus avec Premium) :
<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>
Le code complet HTML + CSS + JS de Portal Open, prêt à coller — et les 840 effets. Ou 299 € TTC une fois, accès à vie.
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
Décalages (JS — 200 et 500 ms à l'ouverture, 400 ms à la fermeture) |
anneau, puis cercle à 200 ms, extinction à 500 ms | Portez le premier à 400 ms pour un anneau qui « charge » plus longtemps avant l'ouverture ; à 0, l'anneau et le cercle partent ensemble et l'effet d'annonce disparaît. |
Taille de l'anneau (CSS — 200px puis 240px) |
200 px puis 240 px à l'extinction | Calez-la sur votre cadre : à peu près la plus petite dimension du cadre, puis +20 %. Un anneau plus grand que le cadre est coupé par son overflow: hidden. |
Ouverture du cercle (CSS — circle(75% at 50% 50%), 0,7 s) |
75 % : les coins sont atteints | at 50% 100% fait partir le cercle du bas ; pour un cadre très allongé, montez à 100 % pour ne pas laisser les coins vides. |
Couleur (CSS — border-color et box-shadow de .portal-open-ring) |
cyan #22d3ee avec lueur |
Changez-la sur la règle de base de l'anneau, pas seulement sur l'état actif, sinon il reprend le cyan pendant la fermeture. |
Forme du cadre (CSS — .portal-open-wrapper) |
200 × 120 px, coins de 14 px | border-radius: 50% sur un cadre carré donne un vrai hublot ; le cercle de découpe et l'anneau restent centrés. |
FAQ
.portal-open-ring-fade dans la branche de fermeture : l'anneau restera éteint.clip-path. Une <video> ou une <img> en object-fit: cover sur 100 % du cadre s'y découvre de la même façon. Pensez à ne lancer la lecture qu'à l'ouverture, et à la mettre en pause à la fermeture.