diff --git a/dist/content_visibility.js b/dist/content_visibility.js new file mode 100644 index 0000000..77ea7b7 --- /dev/null +++ b/dist/content_visibility.js @@ -0,0 +1,78 @@ +//[content_visibility] +// Uncomment the previous line for testing on webpagetest.org + +function extractContentVisibilityFromAST(ast) { + const contentVisibilityValues = []; + + if (!ast || !Array.isArray(ast)) { + return contentVisibilityValues; + } + + const rulesToProcess = [...ast]; + + while (rulesToProcess.length > 0) { + const rule = rulesToProcess.shift(); + + if (rule.type === 'rule' && rule.declarations) { + // Process regular CSS rules + for (const declaration of rule.declarations) { + if (declaration.type === 'declaration' && + declaration.property && + declaration.property.toLowerCase() === 'content-visibility' && + declaration.value) { + contentVisibilityValues.push(declaration.value.trim()); + } + } + } else if (rule.type === 'media' && rule.rules) { + rulesToProcess.push(...rule.rules); + } else if (rule.type === 'supports' && rule.rules) { + rulesToProcess.push(...rule.rules); + } else if (rule.type === 'keyframes' && rule.keyframes) { + for (const keyframe of rule.keyframes) { + if (keyframe.declarations) { + for (const declaration of keyframe.declarations) { + if (declaration.type === 'declaration' && + declaration.property && + declaration.property.toLowerCase() === 'content-visibility' && + declaration.value) { + contentVisibilityValues.push(declaration.value.trim()); + } + } + } + } + } + } + + return contentVisibilityValues; +} + +function getUniqueValues(values) { + const unique = []; + const seen = {}; + for (let i = 0; i < values.length; i++) { + const value = values[i]; + if (!seen[value]) { + seen[value] = true; + unique.push(value); + } + } + return unique; +} + +const contentVisibilityValues = []; + +if (typeof parsed_css !== 'undefined' && Array.isArray(parsed_css)) { + for (const cssData of parsed_css) { + if (cssData && cssData.ast) { + const values = extractContentVisibilityFromAST(cssData.ast); + contentVisibilityValues.push(...values); + } + } +} + +return { + used: contentVisibilityValues.length > 0, + count: contentVisibilityValues.length, + values: contentVisibilityValues, + uniqueValues: getUniqueValues(contentVisibilityValues) +}; diff --git a/metric-summary.md b/metric-summary.md index f69a1d9..3845711 100644 --- a/metric-summary.md +++ b/metric-summary.md @@ -723,6 +723,36 @@ Example response: [5, 12, 11] ``` +## [content_visibility.js](https://github.com/HTTPArchive/custom-metrics/blob/main/dist/content_visibility.js) metrics + +### content_visibility +Detects CSS rules using the `content-visibility` property for performance optimization analysis. This metric uses efficient regex-based detection with performance optimizations to find content-visibility declarations in stylesheets, style blocks, and inline styles. Returns information about CSS rules that have content-visibility set to values other than 'visible' (such as 'auto', 'hidden', or 'skip'). + +**Performance Optimizations:** +- Early exit for inline styles when content-visibility is found in stylesheets/style blocks +- Pre-filtering of inline styles to avoid unnecessary regex processing + +Example response: + +```json +{ + "used": true, + "count": 5, + "values": [ + "auto", + "hidden", + "skip", + "auto", + "hidden" + ], + "uniqueValues": [ + "auto", + "hidden", + "skip" + ] +} +``` + ## [Images.js](https://github.com/HTTPArchive/custom-metrics/blob/main/dist/Images.js) metrics A JSON array of `` elements on the page.