Explorer
KNOW-PAT-149

Overlay annotation sur site live — iframe, calque, scroll sync

Domaine
web-uiux
Type
pattern
Priorité
P0

Parent : [[INDEX-WEB-UIUX]]

Overlay annotation sur site live

Problème

Annoter un site « en direct » (bulles, texte, pins) exige de superposer une couche interactive sans casser le site cible ni perdre la position des annotations au scroll/resize.

Solution — Architecture en 3 couches

┌─────────────────────────────────────────┐
│  CHROME (toolbar, panels) — z-index 50  │  ← ton app, pointer-events: auto
├─────────────────────────────────────────┤
│  ANNOTATION LAYER — z-index 20          │  ← SVG/canvas absolu, coords %
├─────────────────────────────────────────┤
│  TARGET (iframe ou snapshot) — z-index 0│  ← site client, pointer-events selon mode
└─────────────────────────────────────────┘

Mode A — iframe (site same-origin ou autorisé)

  • iframe plein viewport sous le calque annotation.
  • Mode browse : pointer-events: none sur le calque → clics passent à l'iframe.
  • Mode annotate : pointer-events: auto sur le calque → iframe en pointer-events: none.
  • Sync scroll : écouter scroll sur iframe.contentWindow (same-origin) ou wrapper scrollable.

Mode B — extension / bookmarklet (cross-origin)

  • Injection script + calque fixed position: fixed; inset: 0.
  • Coords en pourcentage du viewport document + scrollX/scrollY au save.
  • Reposition au scroll via transform: translate ou recalc absolute.

Mode C — snapshot (fallback)

  • Capture (html-to-image / serveur) → image de fond + annotations en coords image.
  • Moins « live » mais fiable cross-origin.

Règles coords (obligatoire)

Champ Type Pourquoi
x, y number 0–1 (% viewport) Survit au resize
scrollX, scrollY number Ancrage page scrollée
viewportWidth number Détection drift layout
targetUrl string Contexte session

Ne jamais stocker px seuls sans référence viewport.

Exemple

type ToolMode = "browse" | "annotate" | "text" | "pin"

<div className="relative h-screen overflow-hidden">
  <iframe ref={frameRef} src={url} className="absolute inset-0 w-full h-full border-0" />
  <svg
    className="absolute inset-0 w-full h-full"
    style={{ pointerEvents: mode === "browse" ? "none" : "auto" }}
  >
    {annotations.map(a => <AnnotationPin key={a.id} {...a} />)}
  </svg>
  <Toolbar mode={mode} onModeChange={setMode} />
</div>

Anti-erreurs (reviennent en 5 jours)

  • Annotations qui flottent au scroll → coords % + scroll offset manquants.
  • Clics bloqués sur le site → oublier toggle browse/annotate.
  • iframe X-Frame-Options → prévoir mode snapshot ou extension.
  • z-index war avec le site cible → calque dans shadow DOM ou iframe isolé pour le chrome uniquement.

Quand ne PAS l'utiliser

  • Commentaires sur maquettes statiques (PNG/Figma export) → coords image suffisent.

Source

  • Excellence design-tool knowledge-core — 2026-06-09

Liens connexes

  • [[KNOW-PAT-136-ProjectBeta-editor-ux-patterns|KNOW-PAT-136]]