Kihagyás

SVG-overlay az <img> fölött — aspect-ratio CSS layout bug#

A tanulság#

Ha SVG-vel overlay-zünk egy <img>-et (pl. callout-marker-ek), és a wrapper-container max-h + overflow-auto kombinációval van korlátozva, az img és SVG különböző méretben renderelődnek, és a koordináta-rendszerek szétcsúsznak.

A felhasználói tünet: "a piros gyűrű nem a számon van", "a klikk rossz helyre megy". Pedig az OCR-koordináták pontosak.

Why#

Tipikus rossz code:

<div className="max-h-[80vh] overflow-auto inline-block">
  <img src={...} className="max-w-full" />
  <svg
    viewBox="0 0 3308 4678"
    preserveAspectRatio="xMidYMid meet"
    className="absolute inset-0 h-full w-full"
  />
</div>

Probléma: 1. <img> keeps natural aspect (3308:4678), scrolls when taller than max-h 2. <svg> sizes itself to the CLAMPED container (e.g., 600×640 instead of 600×848), with viewBox 3308×4678 3. Different aspect ratiospreserveAspectRatio="meet" adds horizontal padding to center the SVG content 4. Coordinate mismatch: egy bbox (231, 736) a kép-pixel-térben az SVG fölött eltolódik

How to apply (fix pattern)#

{/* Outer = scrollable viewport */}
<div className="max-h-[calc(100vh-160px)] overflow-auto">
  {/* Inner = exact img-aspect dimensions */}
  <div
    className="relative"
    style={{ aspectRatio: `${imgWidth} / ${imgHeight}` }}
  >
    <img
      src={imageUrl}
      className="block h-full w-full"
    />
    <svg
      viewBox={`0 0 ${imgWidth} ${imgHeight}`}
      preserveAspectRatio="none"
      className="absolute inset-0 h-full w-full"
    >
      {/* rect-ek kép-pixel koordinátákban — most már pontosan rajta */}
    </svg>
  </div>
</div>

Why ez működik: 1. Inner <div> aspectRatio: w/h CSS-szel mindig ugyanaz az aspect ratio mint a kép 2. <img> h-full w-full kitölti az inner-t 3. <svg> absolute inset-0 h-full w-full ugyanazok a dimenziók mint az inner 4. preserveAspectRatio="none" — mivel a wrapper aspect = viewBox aspect, nincs distortion (a none csak akkor torzít ha különböznek)

Bidirectional click bug társa#

Plus: az SVG-rect fill="transparent" defaulton NEM klikkelhető (csak a 2px-es stroke fogad eseményt). Megoldás:

<rect
  x={...} y={...} width={...} height={...}
  fill="white"
  fillOpacity={0.001}  // láthatatlan de full-area clickable
  onClick={...}
/>

fillOpacity=0.001 invisible visuálisan de pointer-events-elfogadja a click-et az egész területen. Plus pointer-events="all" is explicit alternatíva.

Implementáció#

Mikor érzed magad rajta#

  • "A klikk csak a vékony border-en regisztrálódik" → fillOpacity-fix
  • "A piros gyűrű mellette van a számtól" → aspect-ratio container fix
  • "Mobil-en máshol van mint desktop-on" → CSS responsive max-h interakció — aspect-container megoldja

Kapcsolódó#