Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core(perf): speed up tap-target's isVisible() #9056

Merged
merged 7 commits into from
Jun 5, 2019
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 2 additions & 28 deletions lighthouse-core/gather/gatherers/seo/tap-targets.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,38 +32,12 @@ const TARGET_SELECTORS = [
const tapTargetsSelector = TARGET_SELECTORS.join(',');

/**
* @param {Element} element
* @param {HTMLElement} element
* @returns {boolean}
*/
/* istanbul ignore next */
function elementIsVisible(element) {
const {overflowX, overflowY, display, visibility} = getComputedStyle(element);

if (
display === 'none' ||
(visibility === 'collapse' && ['TR', 'TBODY', 'COL', 'COLGROUP'].includes(element.tagName))
) {
// Element not displayed
return false;
}

// only for block and inline-block, since clientWidth/Height are always 0 for inline elements
if (display === 'block' || display === 'inline-block') {
// if height/width is 0 and no overflow in that direction then
// there's no content that the user can see and tap on
if ((element.clientWidth === 0 && overflowX === 'hidden') ||
(element.clientHeight === 0 && overflowY === 'hidden')) {
return false;
}
}

const parent = element.parentElement;
if (parent && parent.tagName !== 'BODY') {
// if a parent is invisible then the current element is also invisible
return elementIsVisible(parent);
}

return true;
return !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to fix the failure can we check if any of these dimensions are 0?

it feels like everything was so carefully written the first time around though I'm not sure I fully understand how these compare...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeahh... something with a 1px height but 0x width is still invisible. doesnt matter the height.

Not sure what the test case was supposed to be for. @mattzeunert

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test failure is fixed after merging master, because the node is filtered out by elementCenterIsAtZAxisTop. The position absolute PR also generally improves the smoke test a bunch.

Not sure what the test case was supposed to be for.

The tap target can't be tapped on because the content is hidden by the overflow: hidden. We care about the total number of tap targets in the artifacts because the pass rate is 1 - failureCount/totalTapTargets, and we don't want invisible elements to bring the score up.

to fix the failure can we check if any of these dimensions are 0?

Just because the element has a width of 0 doesn't mean the tap target is untappable, because there could be overflowing child content that the user can tap on.

I added a test case for a width: 0 element with visible child content.

it feels like everything was so carefully written the first time around though I'm not sure I fully understand how these compare...

I think this change is fine, we have reasonable smoke test coverage and I tried it on 50 sites and didn't notice any changes.

I think the new elementIsVisible will deem more elements visible than before, but they'll then be filtered out by elementCenterIsAtZAxisTop.

}

/**
Expand Down