Closed Bug 1809836 Opened 2 years ago Closed 2 years ago

[CTW] Bounds incorrect for scrolled position: fixed elements

Categories

(Core :: Disability Access APIs, defect)

defect

Tracking

()

RESOLVED FIXED
111 Branch
Tracking Status
firefox111 --- fixed

People

(Reporter: Jamie, Assigned: morgan)

References

(Blocks 1 open bug)

Details

(Whiteboard: [ctw-m5])

Attachments

(1 file)

STR:

  1. Open this test case:
    data:text/html,<div style="position: fixed;"><button>top</button></div><script> for (let i = 0; i < 1000; ++i) { const div = document.createElement("div"); div.innerHTML = `<button>${i}</button>`; document.body.append(div); } </script>`
    
  2. Get the Accessible for the "top" button.
  3. Get its bounds.
  4. Scroll the page to the bottom.
  5. Get the bounds for the "top" Accessible.
    • Expected: Same as step 3.
    • Actual: A very negative y coordinate.

Even though the "top" button is a child of a document which has a scroll position, it is position: fixed, so it should not take the scroll position into account.

We probably have a similar problem with position: sticky, but I'm not quite sure how to handle that; it's a bit more complicated.

Yup, I can confirm that we definitely have the same problem for sticky positioning. Test case:

data:text/html,<div style="position: sticky; top: 0px;"><button>top</button></div><script> for (let i = 0; i < 1000; ++i) { const div = document.createElement("div"); div.innerHTML =<button>${i}</button>; document.body.append(div); } </script>

We somehow need to figure out when the element is effectively ignoring the scroll position and when it isn't. We also need to get notified when that changes.

Hmm, looks like we need to respond to things that do scroll suppression
https://drafts.csswg.org/css-scroll-anchoring/#suppression-triggers

Assignee: nobody → mreschenberg

:Jamie I can't get this test to fail -- I verified that the scroll offset changes for the doc accessible (so the page is scrolling) but it looks like the bounds are correct for the top button when testing on central. Does this pass for you locally?

accessible/tests/browser/scroll/browser_test_scroll_bounds.js

/**
 * Test bounds and scroll offset on fixed-pos accs
 */
addAccessibleTask(
  `
  <div style="position: fixed;">
    <button id="top">top</button>
  </div>
  `,
  async function(browser, docAcc) {
    const origBounds = await testBoundsWithContent(docAcc, "top", browser);

    await invokeContentTask(browser, [], () => {
      for (let i = 0; i < 1000; ++i) {
        const div = content.document.createElement("div");
        div.innerHTML = "<button>${i}</button>";
        content.document.body.append(div);
      }
      // scroll to the bottom of the page
      content.window.scrollTo(0, content.document.body.scrollHeight);
    });

    await waitForContentPaint(browser);

    const newBounds = await testBoundsWithContent(docAcc, "top", browser);
    for (let i = 0; i < 4; i++) {
      is(
        origBounds[i],
        newBounds[i],
        "Bounds of fixed element are unaffected by scrolling"
      );
    }
  },
  { iframe: true, remoteIframe: true }
);

Flags: needinfo?(jteh)
Flags: needinfo?(jteh)
Whiteboard: [ctw-m5]

As discussed on Zoom, I think the reason the test doesn't fail is that ParentRelativeBounds adjusts for the scroll position. However, this only works if we happen to push cached bounds for the fixed element after the scroll event (for whatever reason; perhaps reflow). If the scroll event happens after we cache bounds for the fixed element, we often won't push a bounds update.

You could make the test reproduce this problem by moving the script which adds the 1000 buttons into the snippet, rather than doing this in the same task as the scroll. This would be closer to the test case I provided in comment 0.

Blocks: 1809082

I thought position:fixed elements were relative to the viewport, but turns out they're relative to their document. So in something like this (sorry for the verbose test case -- you need a scrollable iframe with a fixed element, and that iframe should be embedded in a scrollable top level doc)

data:text/html,<iframe style="margin-left:100px; margin-top:100px;" src="data:text/html,<div style='position:fixed;'>hello world</div>hello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello world"></iframe><br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a<br>a

the div in the iframe is fixed, so as you scroll the iframe text it doesn't move. but, if you scroll the top level document the hello world div inside the iframe scrolls (ie. it isn't fixed in the top level document).

sigh

Attachment #9312059 - Attachment description: WIP: Bug 1809836: Avoid caching scroll position on accs with scroll suppression r?Jamie → WIP: Bug 1809836: Avoid adding scroll offsets when computing bounds for position:fixed accs r?Jamie
Attachment #9312059 - Attachment description: WIP: Bug 1809836: Avoid adding scroll offsets when computing bounds for position:fixed accs r?Jamie → Bug 1809836: Avoid adding scroll offsets when computing bounds for position:fixed accs r?Jamie
Pushed by mreschenberg@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/227139b26cc2 Avoid adding scroll offsets when computing bounds for position:fixed accs r=Jamie
Status: NEW → RESOLVED
Closed: 2 years ago
Resolution: --- → FIXED
Target Milestone: --- → 111 Branch
Regressions: 1814538
Blocks: 1815153
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: