diff --git a/test/demos.mjs b/test/demos.mjs index 03faa587..b0d692d5 100644 --- a/test/demos.mjs +++ b/test/demos.mjs @@ -1,6 +1,6 @@ import {assert} from 'chai'; -import {dom, out, rule, ruleset, type} from '../index'; +import {dom, rule, ruleset, type} from '../index'; import {sigmoid, staticDom} from '../utils'; diff --git a/test/lhs_tests.mjs b/test/lhs_tests.mjs index 7747f593..ff03f3e9 100644 --- a/test/lhs_tests.mjs +++ b/test/lhs_tests.mjs @@ -1,6 +1,6 @@ import {assert} from 'chai'; -import {dom, rule, ruleset, out, type} from '../index'; +import {dom, rule, ruleset, type} from '../index'; import {staticDom} from '../utils'; diff --git a/test/ruleset_tests.mjs b/test/ruleset_tests.mjs index d2436c73..a8aaf17a 100644 --- a/test/ruleset_tests.mjs +++ b/test/ruleset_tests.mjs @@ -1,7 +1,7 @@ import {assert} from 'chai'; import {distance} from '../clusters'; -import {and, dom, nearest, out, props, rule, ruleset, score, type} from '../index'; +import {and, dom, nearest, props, rule, ruleset, score, type} from '../index'; import {domSort, sigmoid, staticDom} from '../utils'; diff --git a/test/utils_tests.mjs b/test/utils_tests.mjs index d0848b90..856bfd4c 100644 --- a/test/utils_tests.mjs +++ b/test/utils_tests.mjs @@ -1,5 +1,5 @@ import {assert} from 'chai'; -import {dom, out, rule, ruleset, score, type} from '../index'; +import {dom, rule, ruleset, score, type} from '../index'; import {NiceSet, toposort, staticDom, attributesMatch} from '../utils'; diff --git a/utilsForFrontend.mjs b/utilsForFrontend.mjs index 2c340ec6..08774d24 100644 --- a/utilsForFrontend.mjs +++ b/utilsForFrontend.mjs @@ -458,28 +458,45 @@ export function sigmoid(x) { } /** - * Return whether an element is practically visible, considing things like 0 - * size or opacity, ``display: none``, and ``visibility: hidden``. + * Return whether an element is practically visible, considering things like 0 + * size or opacity, ``visibility: hidden`` and ``overflow: hidden``. */ export function isVisible(fnodeOrElement) { + // This could be 5x more efficient if https://github.com/w3c/csswg-drafts/issues/4122 happens. const element = toDomElement(fnodeOrElement); + const elementRect = element.getBoundingClientRect(); + const elementStyle = getComputedStyle(element); + // Alternative to reading ``display: none`` due to Bug 1381071. + if (elementRect.width === 0 && elementRect.height === 0 && elementStyle.overflow !== 'hidden') { + return false; + } + if (elementStyle.visibility === 'hidden') { + return false; + } + // Check if the element is off-screen: + const frame = element.ownerDocument.defaultView; + if (elementRect.x + elementRect.width < 0 || + elementRect.y + elementRect.height < 0 || + elementRect.x > frame.innerWidth || elementRect.y > frame.innerHeight + ) { + return false; + } 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') { + const isElement = ancestor === element; + const style = isElement ? elementStyle : getComputedStyle(ancestor); + if (style.opacity === '0') { + return false; + } + if (style.display === 'contents') { + // ``display: contents`` elements have no box themselves, but children are + // still rendered. + continue; + } + const rect = isElement ? elementRect : ancestor.getBoundingClientRect(); + if ((rect.width === 0 || rect.height === 0) && elementStyle.overflow === 'hidden') { + // Zero-sized ancestors don’t make descendants hidden unless the descendant + // has ``overflow: hidden``. return false; - } else { - // It wasn't hidden based on a computed style. See if it's - // offscreen: - const rect = element.getBoundingClientRect(); - const frame = element.ownerDocument.defaultView; // window or iframe - if ((rect.right + frame.scrollX < 0) || - (rect.bottom + frame.scrollY < 0)) { - return false; - } } } return true;