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(layout-shift-elements): surface CLS contribution per shifted element #10968

Merged
merged 10 commits into from
Jun 24, 2020

Conversation

Beytoven
Copy link
Contributor

The layout-shift-elements audit surfaces up to the top 5 elements that shifted during page load and contributed the most to the CLS metric. With this change, it'll also show the amount each of these elements contribute to the CLS score.

Addresses #10751

@Beytoven Beytoven requested a review from a team as a code owner June 16, 2020 01:13
@googlebot
Copy link

All (the pull request submitter and all commit authors) CLAs are signed, but one or more commits were authored or co-authored by someone other than the pull request submitter.

We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that by leaving a comment that contains only @googlebot I consent. in this pull request.

Note to project maintainer: There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent. In those cases, you can manually confirm consent of the commit author(s), and set the cla label to yes (if enabled on your project).

ℹ️ Googlers: Go here for more info.

const clsPerNodeMap = new Map();
/** @type {Set<number>} */
const clsNodeIds = new Set();
static getLayoutShiftElements(mainThreadEvents) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Gonna add comments throughout this function as it has grown pretty complicated.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Agreed. A high-level comment here explaining the approach would be useful. Explaining that score is the additional CLS since the last event, and that we want to distribute that incremental score between all the nodes that have shifted, proportional to the impact region of each shift.

@@ -483,6 +483,7 @@ declare global {
nodeLabel?: string;
devtoolsNodePath: string;
snippet?: string;
score?: number;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Open to suggestions on renaming this. Don't know if there's a better naming option here so left it as score for now.

Copy link
Collaborator

Choose a reason for hiding this comment

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

yeah this seems fine to me. score will be specific to the type of element, so metricName becomes a discriminant. future metrics may overload score but it'll be orthogonal so it seems fine to just use score and not cls_score. also seems fine to keep the types simple and not do a real type discriminant (like interface CLSTraceElement extends TraceElement { score: number}.

@@ -176,15 +176,15 @@ module.exports = [
},
},
// TODO: uncomment when Chrome m84 lands
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will delete this TODO once I verify the smoke test can pass in the CI runs.

Copy link
Collaborator

Choose a reason for hiding this comment

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

#10976 will take care of this.

Copy link
Collaborator

Choose a reason for hiding this comment

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

can you rm this change

Copy link
Collaborator

@connorjclark connorjclark left a comment

Choose a reason for hiding this comment

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

Any idea why the now deployment doesn't have any values for CLS contribution?

@@ -16,6 +16,8 @@ const pageFunctions = require('../../lib/page-functions.js');
const TraceProcessor = require('../../lib/tracehouse/trace-processor.js');
const RectHelpers = require('../../lib/rect-helpers.js');

/** @typedef {{nodeId: Number, score?: Number}} TraceElementData */
Copy link
Collaborator

Choose a reason for hiding this comment

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

totalAreaOfImpact += areaOfImpact;
});

[...pixelsMovedPerNode.entries()].forEach(entry => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

for (const [key, pixelsMoved] of pixelsMovedPerNode.entries()) { ...

for-loops are better than .forEach, and destructuring key-value entry into variables is nice for readability

.sort((a, b) => b[1] - a[1])
.slice(0, 5).map(entry => Number(entry[0]));
const topFive = [...clsPerNode.entries()]
.sort((a, b) => b[1] - a[1]).slice(0, 5)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
.sort((a, b) => b[1] - a[1]).slice(0, 5)
.sort((a, b) => b[1] - a[1])
.slice(0, 5)

nit

.map(entry => {
return {
nodeId: Number(entry[0]),
score: Number(entry[1]),
Copy link
Collaborator

Choose a reason for hiding this comment

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

I feel like at least one of these are numbers already

@@ -483,6 +483,7 @@ declare global {
nodeLabel?: string;
devtoolsNodePath: string;
snippet?: string;
score?: number;
Copy link
Collaborator

Choose a reason for hiding this comment

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

yeah this seems fine to me. score will be specific to the type of element, so metricName becomes a discriminant. future metrics may overload score but it'll be orthogonal so it seems fine to just use score and not cls_score. also seems fine to keep the types simple and not do a real type discriminant (like interface CLSTraceElement extends TraceElement { score: number}.

lighthouse-core/gather/gatherers/trace-elements.js Outdated Show resolved Hide resolved
lighthouse-core/gather/gatherers/trace-elements.js Outdated Show resolved Hide resolved
const clsPerNodeMap = new Map();
/** @type {Set<number>} */
const clsNodeIds = new Set();
static getLayoutShiftElements(mainThreadEvents) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Agreed. A high-level comment here explaining the approach would be useful. Explaining that score is the additional CLS since the last event, and that we want to distribute that incremental score between all the nodes that have shifted, proportional to the impact region of each shift.

@connorjclark connorjclark changed the title core(layout-shift-elements): capture and surface CLS contribution per top shifted elements core(layout-shift-elements): surface CLS contribution per shifted element Jun 16, 2020

for (const [nodeId, pixelsMoved] of pixelsMovedPerNode.entries()) {
let clsContribution = clsPerNode.get(nodeId) || 0;
clsContribution += (pixelsMoved / totalAreaOfImpact) * Number(event.score);
Copy link
Collaborator

Choose a reason for hiding this comment

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

is event.score already a number?

Copy link
Collaborator

Choose a reason for hiding this comment

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

bump on this

Copy link
Collaborator

@connorjclark connorjclark left a comment

Choose a reason for hiding this comment

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

Just one small thing left from me (the usage of Number(event.score)

@connorjclark
Copy link
Collaborator

As a potential follow up: maybe we should instead show the percentage (or add a third column for it)? Since CLS itself is a fairly nebulous unit, it'd be nice to just weigh these contributions in terms of %.

image

@googlebot
Copy link

A Googler has manually verified that the CLAs look good.

(Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.)

ℹ️ Googlers: Go here for more info.

@Beytoven Beytoven merged commit ead5da4 into master Jun 24, 2020
@Beytoven Beytoven deleted the cls-element-values branch June 24, 2020 00:06
gMakunde pushed a commit to gMakunde/lighthouse that referenced this pull request Jul 6, 2020
gMakunde pushed a commit to gMakunde/lighthouse that referenced this pull request Aug 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants