Open Bug 1782712 Opened 2 years ago Updated 1 year ago

inserting iframe and then making it position fixed makes web page scroll

Categories

(Core :: Layout: Scrolling and Overflow, defect)

Firefox 102
defect

Tracking

()

People

(Reporter: kaprielovag, Unassigned)

References

(Depends on 1 open bug)

Details

Attachments

(1 file)

Attached video screencast 2022-08-02 15-47-03.mp4 (deleted) —

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36

Steps to reproduce:

If I add an iframe with position: fixed to any web page that scrolls on top, the scroll changes position. I only see this behavior in firefox. Example below.
https://kaprielov.github.io/iframe-example/

Actual results:

unwanted scrolling

Expected results:

no unwanted scrolling

The Bugbug bot thinks this bug should belong to the 'Core::Layout: Scrolling and Overflow' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.

Component: Untriaged → Layout: Scrolling and Overflow
Product: Firefox → Core

The testcase first inserts the iframe into the document and then sets position fixed on it. So I think what is happening is that the document is getting laid out after inserting the iframe (but before it is position fixed), so the iframe takes up space and is at the top of the document, this pushes down the other content. The the iframe becomes position fixed and it no longer takes up space. If the testcase made the iframe fixed before adding it to the document (or made it have a class that give it position fixed before inserting it) then the problem goes away.

Summary: Web pages scroll when you add an iframe with position: fixed → inserting iframe and then making it position fixed makes web page scroll
Severity: -- → S3
Status: UNCONFIRMED → NEW
Ever confirmed: true

This is most likely because AsyncFrameInit::Run somehow triggers a flush.

Flags: needinfo?(emilio)

nsSubDocumentFrame::ShowViewer calls nsFrameLoader::UpdatePositionAndSize, nsFrameLoader::UpdateBaseWindowPositionAndSize, nsDocShell::GetPosition, nsDocShell::GetPositionAndSize which flushes.

So I took a look and while comment 4 is true, that's not the root cause here, because we only call UpdatePositionAndSize if we're not on the first reflow.

I took a closer look and this is the relevant flush:

DoFlushPendingNotifications(https://kaprielov.github.io/iframe-example/)
#01: mozilla::PresShell::DoFlushPendingNotifications(mozilla::ChangesToFlush) (/home/emilio/src/moz/gecko-3/layout/base/PresShell.cpp:4226)
#02: mozilla::dom::Document::FlushPendingNotifications(mozilla::ChangesToFlush) (/home/emilio/src/moz/gecko-3/dom/base/Document.cpp:10734)
#03: mozilla::dom::Document::FlushPendingNotifications(mozilla::ChangesToFlush) (/home/emilio/src/moz/gecko-3/dom/base/Document.cpp:10734)
#04: nsDocLoader::DocLoaderIsEmpty(bool, mozilla::Maybe<nsresult> const&) (/home/emilio/src/moz/gecko-3/uriloader/base/nsDocLoader.cpp:743)
#05: nsDocLoader::OnStopRequest(nsIRequest*, nsresult) (/home/emilio/src/moz/gecko-3/uriloader/base/nsDocLoader.cpp:0)
#06: nsDocShell::OnStopRequest(nsIRequest*, nsresult) (/home/emilio/src/moz/gecko-3/docshell/base/nsDocShell.cpp:0)
#07: mozilla::net::nsLoadGroup::NotifyRemovalObservers(nsIRequest*, nsresult) (/home/emilio/src/moz/gecko-3/netwerk/base/nsLoadGroup.cpp:631)
#08: mozilla::net::nsLoadGroup::Cancel(nsresult) (/home/emilio/src/moz/gecko-3/netwerk/base/nsLoadGroup.cpp:258)
#09: nsDocLoader::Stop() (/home/emilio/src/moz/gecko-3/uriloader/base/nsDocLoader.cpp:259)
#10: nsDocShell::Stop(unsigned int) (/home/emilio/src/moz/gecko-3/docshell/base/nsDocShell.cpp:4367)
#11: nsDocShell::InternalLoad(nsDocShellLoadState*, mozilla::Maybe<unsigned int>) (/home/emilio/src/moz/gecko-3/docshell/base/nsDocShell.cpp:9602)
#12: nsDocShell::LoadURI(nsDocShellLoadState*, bool, bool) (/home/emilio/src/moz/gecko-3/docshell/base/nsDocShell.cpp:859)
#13: nsFrameLoader::ReallyStartLoadingInternal() (/home/emilio/src/moz/gecko-3/dom/base/nsFrameLoader.cpp:778)
#14: nsFrameLoader::ReallyStartLoading() (/home/emilio/src/moz/gecko-3/dom/base/nsFrameLoader.cpp:652)
#15: mozilla::dom::Document::MaybeInitializeFinalizeFrameLoaders() (/home/emilio/src/moz/gecko-3/dom/base/Document.cpp:9233)
#16: mozilla::detail::RunnableMethodImpl<mozilla::dom::Document*, void (mozilla::dom::Document::*)(), true, (mozilla::RunnableKind)0, >::Run() (/home/emilio/src/moz/gecko-3/obj-debug/dist/include/nsThreadUtils.h:1219)
#17: nsContentUtils::RemoveScriptBlocker() (/home/emilio/src/moz/gecko-3/dom/base/nsContentUtils.cpp:6006)
#18: mozilla::dom::Document::EndUpdate() (/home/emilio/src/moz/gecko-3/dom/base/Document.cpp:7802)
#19: mozAutoDocUpdate::~mozAutoDocUpdate() (/home/emilio/src/moz/gecko-3/dom/base/mozAutoDocUpdate.h:0)
#20: mozilla::dom::Element::SetAttr(int, nsAtom*, nsAtom*, nsTSubstring<char16_t> const&, nsIPrincipal*, bool) (/home/emilio/src/moz/gecko-3/dom/base/Element.cpp:0)
#21: mozilla::dom::HTMLIFrameElement_Binding::set_srcdoc(JSContext*, JS::Handle<JSObject*>, void*, JSJitSetterCallArgs) (/home/emilio/src/moz/gecko-3/obj-debug/dom/bindings/HTMLIFrameElementBinding.cpp:190)
#22: bool mozilla::dom::binding_detail::GenericSetter<mozilla::dom::binding_detail::NormalThisPolicy>(JSContext*, unsigned int, JS::Value*) (/home/emilio/src/moz/gecko-3/dom/bindings/BindingUtils.cpp:3266)

So, it happens during the srcdoc setter, and that's because we're stopping the ongoing about:blank load. I suspect bug 543435 would fix this.

Depends on: sync-about-blank
Flags: needinfo?(emilio)
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: