Re: [csswg-drafts] [cssom-view] {element, elements, nodes}FromPoint but without restricting to the viewport clip? (#4122)

aHere's the intersection code that I thought of: https://stackoverflow.com/questions/9011668/get-element-at-point-in-entire-page-even-if-its-not-visible

Upon re-reading it I think what that code is trying to do would be better done by something like flex or grid, but I haven't thought out too much how, it seems it's sort of like the masonry layout stuff.

Anyhow... The usecase that prompted me to propose it was some investigation in https://github.com/mozilla/fathom/issues/91. But I've seen similar code elsewhere in sites like Facebook and such (see https://bugzilla.mozilla.org/show_bug.cgi?id=1381071#c1 for example).

The facebook code is:

```ts
function isVisible(element: HTMLElement): boolean {
  // Look upward in the DOM until we either reach the document or
  // find something hidden.
  let elem = element;
  while (
    elem &&
    elem !== document &&
    Style.get(elem, 'visibility') != 'hidden' &&
    Style.get(elem, 'display') != 'none') {
    elem = elem.parentNode;
  }

  // If we reached the document, the element is visible.
  return elem === document;
}
```

The code in the Mozilla add-on was similar too:

```js
export function isVisible(fnodeOrElement) {
    const element = toDomElement(fnodeOrElement);
    for (const ancestor of ancestors(element)) {
        const style = getComputedStyle(ancestor);
        if (style.visibility === 'hidden' ||
            style.display === 'none' ||
            style.opacity === '0' ||
            style.width === '0' ||
            style.height === '0') {
            return false;
        }
    }
    return true;
}
```

(I skipped [some branch](https://github.com/mozilla/fathom/blob/5cf2e902d3cdd01368ed72e7796b848f741e17b0/utilsForFrontend.mjs#L477) which was doing some viewport stuff because it's not clear what it's trying to do, I think it's trying to check elements scrolled out of view towards the top, or something).

The question that code is trying to answer is whether a given node is "visible", for some definition of visible. Both functions are bogus in multiple ways:

 * They don't work with anything that looks like shadow DOM in any way.
 * They assume `visibility` works differently than how it works (`visibility: visible` inside `visibility: hidden` is definitely visible).
 * The `style.width` and `style.height` checks in the add-on code is wrong (should be `0px` instead), they're meaningless is `overflow` is `visible`, etc...
 * They don't handle other ways to make an element "hidden".

The add-on use-case is even worse because walking the DOM from an add-on is slower due to security wrappers / proxies.

In the add-on use-case at least, the complaint against `elementsFromPoint()` was that it returned false for out-of-viewport elements. But using it actually _improved_ performance compared to all the DOM walking and layout querying (mostly because of the reduced number of DOM calls, actually).

It seems to me like a good improvement over those two functions but, that being said, chances are that a more thought-out proposal may want a bit more flexibility. For example, people may want to ignore all scroller clips, or maybe only those with user-scrollable overflow (that is, don't ignore `overflow: hidden` clips but ignore `overflow: scroll` clips)... In any case ignoring the viewport clip is a pretty good improvement over the situation now.

The Facebook code doesn't need to deal with all of the web, but libraries / frameworks and extensions do, this could allow them to write actually correct code :)

-- 
GitHub Notification of comment by emilio
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/4122#issuecomment-516183855 using your GitHub account

Received on Monday, 29 July 2019 22:18:44 UTC