diff --git a/core/audits/non-composited-animations.js b/core/audits/non-composited-animations.js
index 8c6e7fb48547..e0a807b9f3ef 100644
--- a/core/audits/non-composited-animations.js
+++ b/core/audits/non-composited-animations.js
@@ -32,6 +32,14 @@ const UIStrings = {
=1 {Unsupported CSS Property: {properties}}
other {Unsupported CSS Properties: {properties}}
}`,
+ /**
+ * @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.
+ * @example {--swing-y, --rotation} properties
+ */
+ unsupportedCustomCSSProperty: `{propertyCount, plural,
+ =1 {Custom CSS properties cannot be animated on the compositor: {properties}}
+ other {Custom CSS properties cannot be animated on the compositor: {properties}}
+ }`,
/** 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. */
transformDependsBoxSize: 'Transform-related property depends on box size',
/** 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) {
return ACTIONABLE_FAILURE_REASONS
.filter(reason => failureCode & reason.flag)
.map(reason => {
+ // Handle both regular CSS properties and custom CSS properties
if (reason.text === UIStrings.unsupportedCSSProperty) {
- return str_(reason.text, {
- propertyCount: unsupportedProperties.length,
- properties: unsupportedProperties.join(', '),
- });
+ const customProperties = new Set();
+ const nonCustomProperties = new Set();
+
+ // Separate custom properties (starting with '--') from regular properties
+ for (const property of unsupportedProperties) {
+ if (property.startsWith('--')) {
+ customProperties.add(property);
+ } else {
+ nonCustomProperties.add(property);
+ }
+ }
+
+ const reasons = [];
+
+ // Add regular CSS properties message if any exist
+ if (nonCustomProperties.size > 0) {
+ reasons.push(str_(UIStrings.unsupportedCSSProperty, {
+ propertyCount: nonCustomProperties.size,
+ properties: Array.from(nonCustomProperties).join(', '),
+ }));
+ }
+
+ // Add custom CSS properties message if any exist
+ if (customProperties.size > 0) {
+ reasons.push(str_(UIStrings.unsupportedCustomCSSProperty, {
+ propertyCount: customProperties.size,
+ properties: Array.from(customProperties).join(', '),
+ }));
+ }
+
+ return reasons;
}
+
return str_(reason.text);
- });
+ })
+ .flat(); // Flatten array since we might return multiple messages for unsupported properties
}
class NonCompositedAnimations extends Audit {
diff --git a/core/test/audits/non-composited-animations-test.js b/core/test/audits/non-composited-animations-test.js
index 11f99eb02479..154bee29ce1c 100644
--- a/core/test/audits/non-composited-animations-test.js
+++ b/core/test/audits/non-composited-animations-test.js
@@ -233,4 +233,129 @@ describe('Non-composited animations audit', () => {
expect(auditResult.details.items[0].subItems.items[5].animation)
.toBeUndefined();
});
+
+ // Testing custom CSS property separation
+ it('separates custom CSS properties from regular properties', async () => {
+ const artifacts = {
+ TraceElements: [
+ {
+ traceEventType: 'animation',
+ nodeId: 4,
+ node: {
+ devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
+ selector: 'body > div#custom-animated',
+ nodeLabel: 'div',
+ snippet: '
',
+ },
+ animations: [
+ {
+ name: 'customAnimation',
+ failureReasonsMask: 8192,
+ unsupportedProperties: ['--swing-y', '--rotation', 'color', 'height'],
+ },
+ ],
+ },
+ ],
+ HostUserAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) ' +
+ 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4216.0 Safari/537.36',
+ };
+
+ const auditResult = await NonCompositedAnimationsAudit.audit(artifacts);
+ expect(auditResult.score).toEqual(0);
+ expect(auditResult.details.headings).toHaveLength(2);
+ expect(auditResult.displayValue).toBeDisplayString('1 animated element found');
+ expect(auditResult.details.items).toHaveLength(1);
+
+ const subItems = auditResult.details.items[0].subItems.items;
+
+ // There should be two separate messages: one for standard CSS properties, and one for custom properties.
+ expect(subItems).toHaveLength(2);
+
+ const failureReasons = subItems.map(item => item.failureReason);
+
+ expect(failureReasons[0])
+ .toBeDisplayString('Unsupported CSS Properties: color, height');
+ expect(failureReasons[1])
+ .toBeDisplayString(
+ 'Custom CSS properties cannot be animated on the compositor: --swing-y, --rotation'
+ );
+
+ expect(subItems[0].animation).toEqual('customAnimation');
+ expect(subItems[1].animation).toEqual('customAnimation');
+ });
+
+ // Custom properties only
+ it('handles animations with only custom CSS properties', async () => {
+ const artifacts = {
+ TraceElements: [
+ {
+ traceEventType: 'animation',
+ nodeId: 5,
+ node: {
+ devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
+ selector: 'body > div#only-custom',
+ nodeLabel: 'div',
+ snippet: '
',
+ },
+ animations: [
+ {
+ failureReasonsMask: 8192,
+ unsupportedProperties: ['--yheight'],
+ },
+ ],
+ },
+ ],
+ HostUserAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) ' +
+ 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4216.0 Safari/537.36',
+ };
+
+ const auditResult = await NonCompositedAnimationsAudit.audit(artifacts);
+ expect(auditResult.score).toEqual(0);
+ expect(auditResult.details.items).toHaveLength(1);
+
+ const subItems = auditResult.details.items[0].subItems.items;
+ expect(subItems).toHaveLength(1);
+ expect(subItems[0].failureReason)
+ .toBeDisplayString(
+ 'Custom CSS properties cannot be animated on the compositor: --yheight'
+ );
+ expect(subItems[0].animation).toBeUndefined();
+ });
+
+ // In the case of general properties only
+ it('handles animations with only regular CSS properties', async () => {
+ const artifacts = {
+ TraceElements: [
+ {
+ traceEventType: 'animation',
+ nodeId: 6,
+ node: {
+ devtoolsNodePath: '1,HTML,1,BODY,1,DIV',
+ selector: 'body > div#only-regular',
+ nodeLabel: 'div',
+ snippet: '
',
+ },
+ animations: [
+ {
+ name: 'regularAnimation',
+ failureReasonsMask: 8192,
+ unsupportedProperties: ['margin', 'padding'],
+ },
+ ],
+ },
+ ],
+ HostUserAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) ' +
+ 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4216.0 Safari/537.36',
+ };
+
+ const auditResult = await NonCompositedAnimationsAudit.audit(artifacts);
+ expect(auditResult.score).toEqual(0);
+ expect(auditResult.details.items).toHaveLength(1);
+
+ const subItems = auditResult.details.items[0].subItems.items;
+ expect(subItems).toHaveLength(1);
+ expect(subItems[0].failureReason)
+ .toBeDisplayString('Unsupported CSS Properties: margin, padding');
+ expect(subItems[0].animation).toEqual('regularAnimation');
+ });
});
diff --git a/shared/localization/locales/en-US.json b/shared/localization/locales/en-US.json
index 0abe2fa96034..bdcfd83f69ef 100644
--- a/shared/localization/locales/en-US.json
+++ b/shared/localization/locales/en-US.json
@@ -1229,6 +1229,9 @@
"core/audits/non-composited-animations.js | unsupportedCSSProperty": {
"message": "{propertyCount, plural,\n =1 {Unsupported CSS Property: {properties}}\n other {Unsupported CSS Properties: {properties}}\n }"
},
+ "core/audits/non-composited-animations.js | unsupportedCustomCSSProperty": {
+ "message": "{propertyCount, plural,\n =1 {Custom CSS properties cannot be animated on the compositor: {properties}}\n other {Custom CSS properties cannot be animated on the compositor: {properties}}\n }"
+ },
"core/audits/non-composited-animations.js | unsupportedTimingParameters": {
"message": "Effect has unsupported timing parameters"
},
diff --git a/shared/localization/locales/en-XL.json b/shared/localization/locales/en-XL.json
index 0e4d595438bf..66344d16a7b0 100644
--- a/shared/localization/locales/en-XL.json
+++ b/shared/localization/locales/en-XL.json
@@ -1229,6 +1229,9 @@
"core/audits/non-composited-animations.js | unsupportedCSSProperty": {
"message": "{propertyCount, plural,\n =1 {Ûńŝúp̂ṕôŕt̂éd̂ ĆŜŚ P̂ŕôṕêŕt̂ý: {properties}}\n other {Ûńŝúp̂ṕôŕt̂éd̂ ĆŜŚ P̂ŕôṕêŕt̂íêś: {properties}}\n }"
},
+ "core/audits/non-composited-animations.js | unsupportedCustomCSSProperty": {
+ "message": "{propertyCount, plural,\n =1 {Ĉúŝt́ôḿ ĈŚŜ ṕr̂óp̂ér̂t́îéŝ ćâńn̂ót̂ b́ê án̂ím̂át̂éd̂ ón̂ t́ĥé ĉóm̂ṕôśît́ôŕ: {properties}}\n other {Ĉúŝt́ôḿ ĈŚŜ ṕr̂óp̂ér̂t́îéŝ ćâńn̂ót̂ b́ê án̂ím̂át̂éd̂ ón̂ t́ĥé ĉóm̂ṕôśît́ôŕ: {properties}}\n }"
+ },
"core/audits/non-composited-animations.js | unsupportedTimingParameters": {
"message": "Êf́f̂éĉt́ ĥáŝ ún̂śûṕp̂ór̂t́êd́ t̂ím̂ín̂ǵ p̂ár̂ám̂ét̂ér̂ś"
},