Skip to content

Commit e67b897

Browse files
authored
core(non-composited-animations): separate custom CSS properties (#16627)
1 parent 63033f4 commit e67b897

File tree

4 files changed

+174
-5
lines changed

4 files changed

+174
-5
lines changed

core/audits/non-composited-animations.js

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ const UIStrings = {
3232
=1 {Unsupported CSS Property: {properties}}
3333
other {Unsupported CSS Properties: {properties}}
3434
}`,
35+
/**
36+
* @description [ICU Syntax] Descriptive reason for why a user-provided animation failed to be optimized by the browser due to custom CSS properties (CSS variables) not being supported on the compositor. Shown in a table with a list of other potential failure reasons.
37+
* @example {--swing-y, --rotation} properties
38+
*/
39+
unsupportedCustomCSSProperty: `{propertyCount, plural,
40+
=1 {Custom CSS properties cannot be animated on the compositor: {properties}}
41+
other {Custom CSS properties cannot be animated on the compositor: {properties}}
42+
}`,
3543
/** Descriptive reason for why a user-provided animation failed to be optimized by the browser due to a `transform` property being dependent on the size of the element itself. Shown in a table with a list of other potential failure reasons. */
3644
transformDependsBoxSize: 'Transform-related property depends on box size',
3745
/** Descriptive reason for why a user-provided animation failed to be optimized by the browser due to a `filter` property possibly moving pixels. Shown in a table with a list of other potential failure reasons. */
@@ -90,14 +98,44 @@ function getActionableFailureReasons(failureCode, unsupportedProperties) {
9098
return ACTIONABLE_FAILURE_REASONS
9199
.filter(reason => failureCode & reason.flag)
92100
.map(reason => {
101+
// Handle both regular CSS properties and custom CSS properties
93102
if (reason.text === UIStrings.unsupportedCSSProperty) {
94-
return str_(reason.text, {
95-
propertyCount: unsupportedProperties.length,
96-
properties: unsupportedProperties.join(', '),
97-
});
103+
const customProperties = new Set();
104+
const nonCustomProperties = new Set();
105+
106+
// Separate custom properties (starting with '--') from regular properties
107+
for (const property of unsupportedProperties) {
108+
if (property.startsWith('--')) {
109+
customProperties.add(property);
110+
} else {
111+
nonCustomProperties.add(property);
112+
}
113+
}
114+
115+
const reasons = [];
116+
117+
// Add regular CSS properties message if any exist
118+
if (nonCustomProperties.size > 0) {
119+
reasons.push(str_(UIStrings.unsupportedCSSProperty, {
120+
propertyCount: nonCustomProperties.size,
121+
properties: Array.from(nonCustomProperties).join(', '),
122+
}));
123+
}
124+
125+
// Add custom CSS properties message if any exist
126+
if (customProperties.size > 0) {
127+
reasons.push(str_(UIStrings.unsupportedCustomCSSProperty, {
128+
propertyCount: customProperties.size,
129+
properties: Array.from(customProperties).join(', '),
130+
}));
131+
}
132+
133+
return reasons;
98134
}
135+
99136
return str_(reason.text);
100-
});
137+
})
138+
.flat(); // Flatten array since we might return multiple messages for unsupported properties
101139
}
102140

103141
class NonCompositedAnimations extends Audit {

core/test/audits/non-composited-animations-test.js

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,4 +233,129 @@ describe('Non-composited animations audit', () => {
233233
expect(auditResult.details.items[0].subItems.items[5].animation)
234234
.toBeUndefined();
235235
});
236+
237+
// Testing custom CSS property separation
238+
it('separates custom CSS properties from regular properties', async () => {
239+
const artifacts = {
240+
TraceElements: [
241+
{
242+
traceEventType: 'animation',
243+
nodeId: 4,
244+
node: {
245+
devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
246+
selector: 'body > div#custom-animated',
247+
nodeLabel: 'div',
248+
snippet: '<div id="custom-animated">',
249+
},
250+
animations: [
251+
{
252+
name: 'customAnimation',
253+
failureReasonsMask: 8192,
254+
unsupportedProperties: ['--swing-y', '--rotation', 'color', 'height'],
255+
},
256+
],
257+
},
258+
],
259+
HostUserAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) ' +
260+
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4216.0 Safari/537.36',
261+
};
262+
263+
const auditResult = await NonCompositedAnimationsAudit.audit(artifacts);
264+
expect(auditResult.score).toEqual(0);
265+
expect(auditResult.details.headings).toHaveLength(2);
266+
expect(auditResult.displayValue).toBeDisplayString('1 animated element found');
267+
expect(auditResult.details.items).toHaveLength(1);
268+
269+
const subItems = auditResult.details.items[0].subItems.items;
270+
271+
// There should be two separate messages: one for standard CSS properties, and one for custom properties.
272+
expect(subItems).toHaveLength(2);
273+
274+
const failureReasons = subItems.map(item => item.failureReason);
275+
276+
expect(failureReasons[0])
277+
.toBeDisplayString('Unsupported CSS Properties: color, height');
278+
expect(failureReasons[1])
279+
.toBeDisplayString(
280+
'Custom CSS properties cannot be animated on the compositor: --swing-y, --rotation'
281+
);
282+
283+
expect(subItems[0].animation).toEqual('customAnimation');
284+
expect(subItems[1].animation).toEqual('customAnimation');
285+
});
286+
287+
// Custom properties only
288+
it('handles animations with only custom CSS properties', async () => {
289+
const artifacts = {
290+
TraceElements: [
291+
{
292+
traceEventType: 'animation',
293+
nodeId: 5,
294+
node: {
295+
devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
296+
selector: 'body > div#only-custom',
297+
nodeLabel: 'div',
298+
snippet: '<div id="only-custom">',
299+
},
300+
animations: [
301+
{
302+
failureReasonsMask: 8192,
303+
unsupportedProperties: ['--yheight'],
304+
},
305+
],
306+
},
307+
],
308+
HostUserAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) ' +
309+
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4216.0 Safari/537.36',
310+
};
311+
312+
const auditResult = await NonCompositedAnimationsAudit.audit(artifacts);
313+
expect(auditResult.score).toEqual(0);
314+
expect(auditResult.details.items).toHaveLength(1);
315+
316+
const subItems = auditResult.details.items[0].subItems.items;
317+
expect(subItems).toHaveLength(1);
318+
expect(subItems[0].failureReason)
319+
.toBeDisplayString(
320+
'Custom CSS properties cannot be animated on the compositor: --yheight'
321+
);
322+
expect(subItems[0].animation).toBeUndefined();
323+
});
324+
325+
// In the case of general properties only
326+
it('handles animations with only regular CSS properties', async () => {
327+
const artifacts = {
328+
TraceElements: [
329+
{
330+
traceEventType: 'animation',
331+
nodeId: 6,
332+
node: {
333+
devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
334+
selector: 'body > div#only-regular',
335+
nodeLabel: 'div',
336+
snippet: '<div id="only-regular">',
337+
},
338+
animations: [
339+
{
340+
name: 'regularAnimation',
341+
failureReasonsMask: 8192,
342+
unsupportedProperties: ['margin', 'padding'],
343+
},
344+
],
345+
},
346+
],
347+
HostUserAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) ' +
348+
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4216.0 Safari/537.36',
349+
};
350+
351+
const auditResult = await NonCompositedAnimationsAudit.audit(artifacts);
352+
expect(auditResult.score).toEqual(0);
353+
expect(auditResult.details.items).toHaveLength(1);
354+
355+
const subItems = auditResult.details.items[0].subItems.items;
356+
expect(subItems).toHaveLength(1);
357+
expect(subItems[0].failureReason)
358+
.toBeDisplayString('Unsupported CSS Properties: margin, padding');
359+
expect(subItems[0].animation).toEqual('regularAnimation');
360+
});
236361
});

shared/localization/locales/en-US.json

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

shared/localization/locales/en-XL.json

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)