w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.47k stars 658 forks source link

[resize-observer] Cross-document observing #3703

Open smfr opened 5 years ago

smfr commented 5 years ago

https://drafts.csswg.org/resize-observer-1/#dom-resizeobserver-observe

Does resizeObserver allow you to observe an element in another (same-origin) document? IntersectionObserver does, and there's some amount of code complexity associated with it. Should resizeObserver be arbitrarily different, and, if so, why?

cathiechen commented 5 years ago

Thanks Simon:) I'd like to share some specific scenarios we discussed.

  1. Frame tree changed in js callback. It's not safe to deliver RO in a frame, since it might be deleted while invoke js callbacks.

frameset.html

<frameset rows="50%, 50%">
    <frame id="frame1" src="./frame1.html"></frame>
    <frame id="frame2" src="./frame2.html"></frame>
</frameset>

frame1.html

frame1

frame2.html

<script type="text/javascript">
function test0() {
    let ro = new ResizeObserver(entries => {
        for (let entry of entries) {
            if (entry.target.parentNode) {
                entry.target.parentNode.removeChild(entry.target);
            }
        }
    });
    let frame1 = parent.document.querySelector('#frame1');
    let frame2 = parent.document.querySelector('#frame2');
    ro.observe(frame1);
    ro.observe(frame2);
}
test0();

</script>
  1. The observed target moved to a new document.

frameset.html

<frameset rows="50%, 50%">
    <frame id="frame1" src="./frame1.html"></frame>
    <frame id="frame2" src="./frame2.html"></frame>
</frameset>

frame1.html

<div id="target1">t1</div>

frame2.html

<div id="target2">t2</target>
<script>
var ro = new ResizeObserver( entries => {
    for (let entry of entries) {
        let target1 = parent.frames[0].document.querySelector('#target1');
        entry.target.parentElement.removeChild(entry.target);
        target1.parentElement.appendChild(entry.target);
    }
});

ro.observe(document.querySelector('#target2'));
</script>
  1. All targets of ResizeObserver are from other document. RO should be fired even its document is layout clean.

frameset.html

<frameset rows="50%, 50%">
    <frame id="frame1" src="./frame1.html"></frame>
    <frame id="frame2" src="./frame2.html"></frame>
</frameset>

frame1.html

<div id="target1">t1</div>

frame2.html

<script>
var ro = new ResizeObserver( entries => {
    for (let entry of entries) {
        console.log("Observe targets from other document.");
    }
});

let target1 = parent.frames[0].document.querySelector('#target1');
ro.observe(target1);
</script>
  1. The depth of target: Calculate the depth of target in frame tree not just current frame.
<div style="width:100px;height:100px;">t1
    <div id="target" style="width:100px;height:100px;">t2
        <iframe id="iframe" src="./frame1.html" onload="depth()"></iframe>
    </div>
</div>

<script>
function depth() {
    let target = document.querySelector('#target');
    let target1 = document.querySelector('#iframe').contentDocument.querySelector('#target1');

    var ro = new ResizeObserver( entries => {
        for (let entry of entries) {
            if (entry.target == target) {
                target1.style.width = "200px";
                console.log("There should no error event. target1 is deeper than target.");
            }
        }
    });
    ro.observe(target);
    ro.observe(target1);
}
</script>

frame1.html

<div id="target1"></div>