Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Fixed-position outer <svg> lands outside a clip after scroll; fixed HTML boxes are re-anchored

Open Beginner friendly
#522 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
72/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
html, javascript
Domain
frontend

Research direction

Start in src/utils/capture.helpers.js at freezeViewportPositioned (around line 134), where clones that aren't HTML elements are skipped. Run the reproduction page with the clip, then check that the svg pixel at (120, 100) is red. Confirm that an outer svg whose parent is not in the SVG namespace gets re-anchored, while nested SVG children are left alone and the div result stays the same.

Written by the indexing model from the issue text.

Description

🔧 in development
Describe it simply:

With clip on a scrolled page, a position: fixed <div> is drawn where it is painted, but a position: fixed outer <svg> is not. The svg keeps position: fixed in the clone, so in the foreignObject it sits at its viewport offset from the top of the document and falls outside a clip of the scrolled viewport.

Seen in 3.3.0 and 3.3.4 (Chromium 153).

Quick demo to reproduce
<!doctype html>
<html>
  <body style="margin: 0; height: 3000px">
    <svg width="200" height="100" style="position: fixed; left: 20px; top: 50px">
      <rect width="200" height="100" fill="red" />
    </svg>
    <div style="position: fixed; left: 300px; top: 50px; width: 200px; height: 100px; background: blue"></div>
    <script type="module">
      import { snapdom } from "https://unpkg.com/@zumer/[email protected]/dist/snapdom.mjs";
      window.scrollTo(0, 1000);
      // The visible viewport strip that holds both fixed boxes.
      const image = await snapdom(document.body, { clip: { x: 0, y: 1000, width: 600, height: 200 } });
      const canvas = await image.toCanvas();
      const pixel = (x, y) => [...canvas.getContext("2d").getImageData(x * canvas.width / 600, y * canvas.height / 200, 1, 1).data];
      console.log(JSON.stringify({ svg: pixel(120, 100), div: pixel(400, 100) }));
    </script>
  </body>
</html>

Observed: {"svg":[0,0,0,0],"div":[0,0,255,255]}: the div is drawn and the svg is missing.

Expected: the svg's centre is red, [255,0,0,255], as it is on screen.

Where

freezeViewportPositioned skips any clone that isn't an HTML element, so an outer <svg> is never re-anchored:

https://github.com/zumerlab/snapdom/blob/a2ffe5cb92e3787e28e7b9cc39dddd88b96a1134/src/utils/capture.helpers.js#L134

An outer <svg> (one whose parent isn't SVG) is a CSS box like any HTML element and takes the same absolute position and size. Letting it through that check (isHTMLEl(cloneEl) || (cloneEl.localName === 'svg' && <its source parent is not in the SVG namespace>)) draws the svg in the right place. We carry that patch against the built bundle for now.

This was written by Claude Code on behalf of max-sixty

Dominant language
JavaScript
Stars
8.2k
Forks
308
Avg merge
2h 47m
Merged PRs (30d)
3

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from zumerlab/snapdom

All issues in zumerlab/snapdom

Similar issues

More JavaScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.