diff --git a/lighthouse-core/audits/first-meaningful-paint.js b/lighthouse-core/audits/first-meaningful-paint.js index 32ebfb74dd5b..a90dc6f4205b 100644 --- a/lighthouse-core/audits/first-meaningful-paint.js +++ b/lighthouse-core/audits/first-meaningful-paint.js @@ -15,8 +15,8 @@ class FirstMeaningfulPaint extends Audit { static get meta() { return { name: 'first-meaningful-paint', - description: 'First meaningful paint', - helpText: 'First meaningful paint measures when the primary content of a page is visible. ' + + description: 'First Meaningful Paint', + helpText: 'First Meaningful Paint measures when the primary content of a page is visible. ' + '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint).', scoreDisplayMode: Audit.SCORING_MODES.NUMERIC, requiredArtifacts: ['traces'], diff --git a/lighthouse-core/config/default-config.js b/lighthouse-core/config/default-config.js index 25d3a65c9812..f3b2605b715b 100644 --- a/lighthouse-core/config/default-config.js +++ b/lighthouse-core/config/default-config.js @@ -189,7 +189,6 @@ module.exports = { groups: { 'metrics': { title: 'Metrics', - description: 'These metrics encapsulate your web app\'s performance across a number of dimensions.', }, 'load-opportunities': { title: 'Opportunities', @@ -248,7 +247,6 @@ module.exports = { categories: { 'performance': { name: 'Performance', - description: 'These encapsulate your web app\'s current performance and opportunities to improve it.', audits: [ {id: 'first-contentful-paint', weight: 3, group: 'metrics'}, {id: 'first-meaningful-paint', weight: 1, group: 'metrics'}, @@ -363,7 +361,6 @@ module.exports = { }, 'best-practices': { name: 'Best Practices', - description: 'We\'ve compiled some recommendations for modernizing your web app and avoiding performance pitfalls.', audits: [ {id: 'appcache-manifest', weight: 1}, {id: 'no-websql', weight: 1}, diff --git a/lighthouse-core/report/html/renderer/category-renderer.js b/lighthouse-core/report/html/renderer/category-renderer.js index 9481a09da47a..632edd5776f4 100644 --- a/lighthouse-core/report/html/renderer/category-renderer.js +++ b/lighthouse-core/report/html/renderer/category-renderer.js @@ -39,8 +39,8 @@ class CategoryRenderer { this.dom.find('.lh-audit__display-text', auditEl).textContent = displayValue; } - this.dom.find('.lh-audit__title', auditEl).appendChild( - this.dom.convertMarkdownCodeSnippets(audit.result.description)); + const titleEl = this.dom.find('.lh-audit__title', auditEl); + titleEl.appendChild(this.dom.convertMarkdownCodeSnippets(audit.result.description)); this.dom.find('.lh-audit__description', auditEl) .appendChild(this.dom.convertMarkdownLinkSnippets(audit.result.helpText)); @@ -64,7 +64,7 @@ class CategoryRenderer { const tooltip = this.dom.createChildOf(textEl, 'div', 'lh-error-tooltip-content tooltip'); tooltip.textContent = audit.result.debugString || 'Report error: no audit information'; } else if (audit.result.debugString) { - const debugStrEl = auditEl.appendChild(this.dom.createElement('div', 'lh-debug')); + const debugStrEl = this.dom.createChildOf(titleEl, 'div', 'lh-debug'); debugStrEl.textContent = audit.result.debugString; } return auditEl; @@ -86,7 +86,7 @@ class CategoryRenderer { * @param {!ReportRenderer.CategoryJSON} category * @return {!Element} */ - renderCategoryScore(category) { + renderCategoryHeader(category) { const tmpl = this.dom.cloneTemplate('#tmpl-lh-category-header', this.templateContext); const gaugeContainerEl = this.dom.find('.lh-score__gauge', tmpl); @@ -95,8 +95,11 @@ class CategoryRenderer { this.dom.find('.lh-category-header__title', tmpl).appendChild( this.dom.convertMarkdownCodeSnippets(category.name)); - this.dom.find('.lh-category-header__description', tmpl) - .appendChild(this.dom.convertMarkdownLinkSnippets(category.description)); + if (category.description) { + const descEl = this.dom.convertMarkdownLinkSnippets(category.description); + this.dom.find('.lh-category-header__description', tmpl).appendChild(descEl); + } + return /** @type {!Element} */ (tmpl.firstElementChild); } @@ -157,9 +160,7 @@ class CategoryRenderer { * @return {!Element} */ _renderFailedAuditsSection(elements) { - const failedElem = this.renderAuditGroup({ - title: `Failed audits`, - }, {expandable: false, itemCount: this._getTotalAuditsLength(elements)}); + const failedElem = this.dom.createElement('div'); failedElem.classList.add('lh-failed-audits'); elements.forEach(elem => failedElem.appendChild(elem)); return failedElem; @@ -253,7 +254,7 @@ class CategoryRenderer { render(category, groupDefinitions) { const element = this.dom.createElement('div', 'lh-category'); this.createPermalinkSpan(element, category.id); - element.appendChild(this.renderCategoryScore(category)); + element.appendChild(this.renderCategoryHeader(category)); const manualAudits = category.audits.filter(item => item.result.scoreDisplayMode === 'manual'); const nonManualAudits = category.audits.filter(audit => !manualAudits.includes(audit)); @@ -300,8 +301,6 @@ class CategoryRenderer { auditsUngrouped.notApplicable.forEach((/** @type {!ReportRenderer.AuditJSON} */ audit, i) => notApplicableElements.push(this.renderAudit(audit, i))); - let hasFailedGroups = false; - Object.keys(auditsGroupedByGroup).forEach(groupId => { const group = groupDefinitions[groupId]; const groups = auditsGroupedByGroup[groupId]; @@ -309,15 +308,15 @@ class CategoryRenderer { if (groups.failed.length) { const auditGroupElem = this.renderAuditGroup(group, {expandable: false}); groups.failed.forEach((item, i) => auditGroupElem.appendChild(this.renderAudit(item, i))); + auditGroupElem.classList.add('lh-audit-group--unadorned'); auditGroupElem.open = true; failedElements.push(auditGroupElem); - - hasFailedGroups = true; } if (groups.passed.length) { const auditGroupElem = this.renderAuditGroup(group, {expandable: true}); groups.passed.forEach((item, i) => auditGroupElem.appendChild(this.renderAudit(item, i))); + auditGroupElem.classList.add('lh-audit-group--unadorned'); passedElements.push(auditGroupElem); } @@ -325,18 +324,14 @@ class CategoryRenderer { const auditGroupElem = this.renderAuditGroup(group, {expandable: true}); groups.notApplicable.forEach((item, i) => auditGroupElem.appendChild(this.renderAudit(item, i))); + auditGroupElem.classList.add('lh-audit-group--unadorned'); notApplicableElements.push(auditGroupElem); } }); if (failedElements.length) { - // if failed audits are grouped skip the 'X Failed Audits' header - if (hasFailedGroups) { - failedElements.forEach(elem => element.appendChild(elem)); - } else { - const failedElem = this._renderFailedAuditsSection(failedElements); - element.appendChild(failedElem); - } + const failedElem = this._renderFailedAuditsSection(failedElements); + element.appendChild(failedElem); } if (manualAudits.length) { diff --git a/lighthouse-core/report/html/renderer/details-renderer.js b/lighthouse-core/report/html/renderer/details-renderer.js index 1eb66ae6c618..86effddf9c9c 100644 --- a/lighthouse-core/report/html/renderer/details-renderer.js +++ b/lighthouse-core/report/html/renderer/details-renderer.js @@ -253,22 +253,11 @@ class DetailsRenderer { for (const thumbnail of details.items) { const frameEl = this._dom.createChildOf(filmstripEl, 'div', 'lh-filmstrip__frame'); - - let timing = Util.formatMilliseconds(thumbnail.timing, 1); - if (thumbnail.timing > 1000) { - timing = Util.formatNumber(thumbnail.timing / 1000) + ' s'; - } - - const timingEl = this._dom.createChildOf(frameEl, 'div', 'lh-filmstrip__timestamp'); - timingEl.textContent = timing; - - const base64data = thumbnail.data; this._dom.createChildOf(frameEl, 'img', 'lh-filmstrip__thumbnail', { - src: `data:image/jpeg;base64,${base64data}`, - alt: `Screenshot at ${timing}`, + src: `data:image/jpeg;base64,${thumbnail.data}`, + alt: `Screenshot`, }); } - return filmstripEl; } diff --git a/lighthouse-core/report/html/renderer/performance-category-renderer.js b/lighthouse-core/report/html/renderer/performance-category-renderer.js index 97ca2eda9f7a..a467c50b1f31 100644 --- a/lighthouse-core/report/html/renderer/performance-category-renderer.js +++ b/lighthouse-core/report/html/renderer/performance-category-renderer.js @@ -50,13 +50,12 @@ class PerformanceCategoryRenderer extends CategoryRenderer { element.classList.add(`lh-load-opportunity--${Util.calculateRating(audit.result.score)}`); element.id = audit.result.name; - const summary = this.dom.find('.lh-load-opportunity__summary', tmpl); const titleEl = this.dom.find('.lh-load-opportunity__title', tmpl); titleEl.textContent = audit.result.description; this.dom.find('.lh-audit__index', element).textContent = `${index + 1}`; if (audit.result.debugString || audit.result.error) { - const debugStrEl = this.dom.createChildOf(summary, 'div', 'lh-debug'); + const debugStrEl = this.dom.createChildOf(titleEl, 'div', 'lh-debug'); debugStrEl.textContent = audit.result.debugString || 'Audit error'; } if (audit.result.error) return element; @@ -86,18 +85,37 @@ class PerformanceCategoryRenderer extends CategoryRenderer { return element; } + /** + * Get an audit's wastedMs to sort the opportunity by, and scale the sparkline width + * Opportunties with an error won't have a summary object, so MIN_VALUE is returned to keep any + * erroring opportunities last in sort order. + * @param {!ReportRenderer.AuditJSON} audit + * @return {number} + */ + _getWastedMs(audit) { + if ( + audit.result.details && + audit.result.details.summary && + typeof audit.result.details.summary.wastedMs === 'number' + ) { + return audit.result.details.summary.wastedMs; + } else { + return Number.MIN_VALUE; + } + } + /** * @override */ render(category, groups) { const element = this.dom.createElement('div', 'lh-category'); this.createPermalinkSpan(element, category.id); - element.appendChild(this.renderCategoryScore(category)); + element.appendChild(this.renderCategoryHeader(category)); + // Metrics const metricAudits = category.audits.filter(audit => audit.group === 'metrics'); const metricAuditsEl = this.renderAuditGroup(groups['metrics'], {expandable: false}); - // Metrics const keyMetrics = metricAudits.filter(a => a.weight >= 3); const otherMetrics = metricAudits.filter(a => a.weight < 3); @@ -111,9 +129,16 @@ class PerformanceCategoryRenderer extends CategoryRenderer { otherMetrics.forEach(item => { metricsColumn2El.appendChild(this._renderMetric(item)); }); + const estValuesEl = this.dom.createChildOf(metricsColumn2El, 'div', + 'lh-metrics__disclaimer lh-metrics__disclaimer'); + estValuesEl.textContent = 'Values are estimated and may vary.'; + + metricAuditsEl.open = true; + metricAuditsEl.classList.add('lh-audit-group--metrics'); + element.appendChild(metricAuditsEl); // Filmstrip - const timelineEl = this.dom.createChildOf(metricAuditsEl, 'div', 'lh-timeline'); + const timelineEl = this.dom.createChildOf(element, 'div', 'lh-filmstrip-container'); const thumbnailAudit = category.audits.find(audit => audit.id === 'screenshot-thumbnails'); const thumbnailResult = thumbnailAudit && thumbnailAudit.result; if (thumbnailResult && thumbnailResult.details) { @@ -124,15 +149,14 @@ class PerformanceCategoryRenderer extends CategoryRenderer { timelineEl.appendChild(filmstripEl); } - metricAuditsEl.open = true; - element.appendChild(metricAuditsEl); - // Opportunities const opportunityAudits = category.audits .filter(audit => audit.group === 'load-opportunities' && !Util.showAsPassed(audit.result)) - .sort((auditA, auditB) => auditB.result.rawValue - auditA.result.rawValue); + .sort((auditA, auditB) => this._getWastedMs(auditB) - this._getWastedMs(auditA)); + if (opportunityAudits.length) { - const maxWaste = Math.max(...opportunityAudits.map(audit => audit.result.rawValue)); + const wastedMsValues = opportunityAudits.map(audit => this._getWastedMs(audit)); + const maxWaste = Math.max(...wastedMsValues); const scale = Math.ceil(maxWaste / 1000) * 1000; const groupEl = this.renderAuditGroup(groups['load-opportunities'], {expandable: false}); const tmpl = this.dom.cloneTemplate('#tmpl-lh-opportunity-header', this.templateContext); @@ -141,6 +165,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer { opportunityAudits.forEach((item, i) => groupEl.appendChild(this._renderOpportunity(item, i, scale))); groupEl.open = true; + groupEl.classList.add('lh-audit-group--opportunities'); element.appendChild(groupEl); } @@ -157,9 +182,11 @@ class PerformanceCategoryRenderer extends CategoryRenderer { const groupEl = this.renderAuditGroup(groups['diagnostics'], {expandable: false}); diagnosticAudits.forEach((item, i) => groupEl.appendChild(this.renderAudit(item, i))); groupEl.open = true; + groupEl.classList.add('lh-audit-group--diagnostics'); element.appendChild(groupEl); } + // Passed audits const passedElements = category.audits .filter(audit => (audit.group === 'load-opportunities' || audit.group === 'diagnostics') && Util.showAsPassed(audit.result)) diff --git a/lighthouse-core/report/html/renderer/report-renderer.js b/lighthouse-core/report/html/renderer/report-renderer.js index 724dc092c359..4350fcc2ace3 100644 --- a/lighthouse-core/report/html/renderer/report-renderer.js +++ b/lighthouse-core/report/html/renderer/report-renderer.js @@ -236,7 +236,7 @@ ReportRenderer.AuditJSON; // eslint-disable-line no-unused-expressions * name: string, * id: string, * score: (number|null), - * description: string, + * description: (string|undefined), * manualDescription: string, * audits: !Array * }} diff --git a/lighthouse-core/report/html/report-styles.css b/lighthouse-core/report/html/report-styles.css index 171afa2fbc66..2c37d04c1dfa 100644 --- a/lighthouse-core/report/html/report-styles.css +++ b/lighthouse-core/report/html/report-styles.css @@ -9,18 +9,20 @@ --monospace-font-family: 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace; --body-font-size: 14px; --body-line-height: 18px; - --subheader-font-size: 16px; + --subheader-font-size: 14px; --subheader-line-height: 20px; - --header-font-size: 20px; + --subheader-color: hsl(206, 6%, 25%); + --header-font-size: 16px; --header-line-height: 24px; --title-font-size: 24px; --title-line-height: 28px; --caption-font-size: 12px; --caption-line-height: 16px; --default-padding: 12px; - --section-padding: 20px; + --section-padding: 16px; --section-indent: 16px; --audit-group-indent: 16px; + --audit-item-gap: 5px; --audit-indent: 16px; --text-indent: 8px; --expandable-indent: 20px; @@ -32,6 +34,7 @@ --informative-color: #0c50c7; --medium-75-gray: #757575; --medium-50-gray: hsl(210, 17%, 98%); + --medium-100-gray: hsl(200, 12%, 95%); --warning-color: #ffab00; /* md amber a700 */ --report-border-color: #ccc; --report-secondary-border-color: #ebebeb; @@ -47,22 +50,30 @@ --lh-score-highlight-bg: hsla(0, 0%, 90%, 0.2); --lh-score-icon-background-size: 24px; --lh-score-margin: 12px; - --lh-table-header-bg: hsla(0, 0%, 50%, 0.4); + --lh-table-header-bg: #f8f9fa; --lh-table-higlight-bg: hsla(0, 0%, 75%, 0.1); --lh-sparkline-height: 5px; --lh-sparkline-thin-height: 3px; --lh-filmstrip-thumbnail-width: 60px; - --lh-score-icon-width: calc(1.5 * var(--body-font-size)); + --lh-score-icon-width: calc(var(--body-font-size) / 14 * 16); --lh-category-score-width: calc(5 * var(--body-font-size)); --lh-audit-vpadding: 8px; - --lh-audit-index-width: 1.3em; + --lh-audit-index-width: 18px; --lh-audit-hgap: 12px; - --lh-audit-group-vpadding: 12px; + --lh-audit-group-vpadding: 8px; --lh-section-vpadding: 12px; --pass-icon-url: url('data:image/svg+xml;utf8,check'); --average-icon-url: url('data:image/svg+xml;utf8,info'); --fail-icon-url: url('data:image/svg+xml;utf8,warn'); - --chevron-icon-url: url('data:image/svg+xml;utf8,'); + --chevron-icon-url: url('data:image/svg+xml;utf8,'); + + --av-timer-icon-url: url('data:image/svg+xml;utf8,'); + --photo-filter-icon-url: url('data:image/svg+xml;utf8,'); + --visibility-icon-url: url('data:image/svg+xml;utf8,'); + --check-circle-icon-url: url('data:image/svg+xml;utf8,'); + --check-icon-url: url('data:image/svg+xml;utf8,'); + --search-icon-url: url('data:image/svg+xml;utf8,'); + --remove-circle-icon-url: url('data:image/svg+xml;utf8,'); } .lh-vars.lh-devtools { @@ -87,7 +98,7 @@ --lh-audit-vpadding: 4px; --lh-audit-hgap: 12px; - --lh-audit-group-vpadding: 8px; + --lh-audit-group-vpadding: 12px; --lh-section-vpadding: 8px; } @@ -109,9 +120,14 @@ scroll-behavior: smooth; } -.lh-root :focus { +.lh-root :focus, +.lh-root .lh-details > summary:focus { outline: -webkit-focus-ring-color auto 3px; } +.lh-root summary:focus { + outline: 1px solid hsl(217, 89%, 61%); +} + .lh-root [hidden] { display: none !important; @@ -126,6 +142,13 @@ cursor: pointer; } +.lh-audit__description, +.lh-load-opportunity__description, +.lh-details { + margin-left: calc(var(--text-indent) + var(--lh-audit-index-width) + 2 * var(--audit-item-gap)); + margin-right: calc(var(--text-indent) + 2px); +} + .lh-details { font-size: var(--body-font-size); margin-top: var(--default-padding); @@ -189,6 +212,7 @@ .lh-audit__score-icon { margin-left: var(--lh-score-margin); width: var(--lh-score-icon-width); + height: var(--lh-score-icon-width); background: none no-repeat center center / contain; } @@ -225,22 +249,29 @@ display: none; } +.lh-category-header__description, +.lh-audit__description { + color: var(--secondary-text-color); +} - -.lh-audit__description, .lh-category-header__description { - margin-top: 5px; +.lh-category-header__description { font-size: var(--body-font-size); - color: var(--secondary-text-color); - line-height: var(--body-line-height); + margin: calc(var(--default-padding) / 2) 0 var(--default-padding); } .lh-audit__header > div, .lh-audit__header > span { - margin: 0 5px; + margin: 0 var(--audit-item-gap); +} +.lh-audit__header > div:first-child, .lh-audit__header > span:first-child { + margin-left: 0; } +.lh-audit__header > div:last-child, .lh-audit__header > span:last-child { + margin-right: 0; +} + .lh-audit__header .lh-audit__index { - margin-left: var(--text-indent); width: var(--lh-audit-index-width); } @@ -251,12 +282,12 @@ .lh-toggle-arrow { background: var(--chevron-icon-url) no-repeat center center / 20px 20px; width: 12px; + height: 18px; flex: none; transition: transform 150ms ease-in-out; cursor: pointer; border: none; transform: rotateZ(90deg); - margin-right: calc(var(--expandable-indent) - 12px); margin-top: calc((var(--body-line-height) - 12px) / 2); } @@ -267,18 +298,22 @@ /* Expandable Details (Audit Groups, Audits) */ .lh-expandable-details { - padding-left: var(--expandable-indent); + } .lh-expandable-details__summary { cursor: pointer; - margin-left: calc(0px - var(--expandable-indent)); } .lh-audit__header { display: flex; + padding: var(--lh-audit-vpadding) var(--text-indent); +} +.lh-audit__header:hover { + background-color: #F8F9FA; } + .lh-audit-group[open] > .lh-audit-group__summary > .lh-toggle-arrow, .lh-expandable-details[open] > .lh-expandable-details__summary > .lh-toggle-arrow, .lh-expandable-details[open] > .lh-expandable-details__summary > div > .lh-toggle-arrow { @@ -290,30 +325,8 @@ display: none; } -/* Perf Timeline */ - -.lh-timeline-container { - overflow: hidden; - border-top: 1px solid var(--metric-timeline-rule-color); -} - -.lh-timeline { - padding: 0; - padding-bottom: 0; - width: calc(var(--lh-filmstrip-thumbnail-width) * 10 + var(--default-padding) * 2); -} - -.lh-narrow .lh-timeline-container { - width: calc(100vw - var(--section-padding) * 2); - overflow-x: scroll; -} -.lh-devtools .lh-timeline-container { - width: 100%; - overflow-x: scroll; -} - -/* Perf Timeline Metric */ +/* Perf Metric */ .lh-metric-container { display: flex; @@ -321,18 +334,19 @@ .lh-metric-column { flex: 1; +} +.lh-metric-column:first-of-type { margin-right: 20px; } .lh-metric { - border-top: 1px solid var(--report-secondary-border-color); + border-bottom: 1px solid var(--report-secondary-border-color); } .lh-metric__innerwrap { display: flex; justify-content: space-between; - margin: var(--lh-audit-vpadding) 0; - padding: var(--lh-audit-vpadding) var(--text-indent); + padding: 11px var(--text-indent); } .lh-metric__header { @@ -353,25 +367,35 @@ flex: 1; } +.lh-metrics__disclaimer { + color: var(--medium-75-gray); + text-align: right; + margin: var(--lh-section-vpadding) 0; + padding: 0 var(--text-indent); +} + .lh-metric__description { color: var(--secondary-text-color); } - -.lh-metric--pass .lh-metric__value { - color: var(--pass-color); +.lh-metric__value { + white-space: nowrap; /* No wrapping between metric value and the icon */ } + .lh-metric .lh-metric__value::after { content: ''; - width: var(--body-font-size); - height: var(--body-font-size); + width: var(--lh-score-icon-width); + height: var(--lh-score-icon-width); background-size: contain; display: inline-block; vertical-align: text-bottom; margin-left: calc(var(--body-font-size) / 2); } +.lh-metric--pass .lh-metric__value { + color: var(--pass-color); +} .lh-metric--pass .lh-metric__value::after { background: var(--pass-icon-url) no-repeat 50% 50%; } @@ -388,7 +412,6 @@ .lh-metric--fail .lh-metric__value { color: var(--fail-color); } - .lh-metric--fail .lh-metric__value::after { background: var(--fail-icon-url) no-repeat 50% 50%; } @@ -406,8 +429,6 @@ /* Perf load opportunity */ .lh-load-opportunity { - padding-top: var(--lh-audit-vpadding); - padding-bottom: var(--lh-audit-vpadding); border-bottom: 1px solid var(--report-secondary-border-color); } @@ -425,11 +446,14 @@ color: var(--medium-75-gray); text-align: center; display: unset; - line-height: calc(3 * var(--body-font-size)); + line-height: calc(2.3 * var(--body-font-size)); } .lh-load-opportunity__summary { - padding-right: var(--text-indent); + padding: var(--lh-audit-vpadding) var(--text-indent); +} +.lh-load-opportunity__summary:hover { + background-color: #F8F9FA; } .lh-load-opportunity__col { @@ -447,11 +471,6 @@ flex: 4; } -.lh-load-opportunity__summary .lh-debug { - width: calc(100% - var(--expandable-indent)); - margin: 0 var(--expandable-indent); -} - .lh-load-opportunity__title { font-size: var(--body-font-size); flex: 10; @@ -508,7 +527,6 @@ } .lh-sparkline__bar { - background: var(--informative-color); height: 100%; float: right; } @@ -516,6 +534,12 @@ /* Filmstrip */ +.lh-filmstrip-container { + padding: 0 var(--expandable-indent); + margin: 0 auto; +} + + .lh-filmstrip { display: flex; flex-direction: row; @@ -528,24 +552,6 @@ position: relative; } -.lh-filmstrip__timestamp { - margin-bottom: calc(0.5 * var(--caption-line-height)); - font-size: var(--caption-font-size); - line-height: var(--caption-line-height); - padding-top: 1px; - padding-right: 6px; -} - -.lh-filmstrip__timestamp::before { - content: ''; - height: 7px; - width: 2px; - background: var(--metric-timeline-rule-color); - position: absolute; - right: 0; - top: -2px; -} - .lh-filmstrip__thumbnail { border: 1px solid var(--report-secondary-border-color); max-height: 100px; @@ -555,21 +561,14 @@ /* Audit */ .lh-audit { - margin-bottom: var(--lh-audit-vpadding); - padding-top: var(--lh-audit-vpadding); - border-top: 1px solid var(--report-secondary-border-color); + border-bottom: 1px solid var(--report-secondary-border-color); font-size: var(--body-font-size); } -.lh-audit:last-of-type { +.lh-audit:last-child { border-bottom: none; } -.lh-audit .lh-debug { - margin-left: calc(var(--expandable-indent) + var(--lh-audit-index-width)); - margin-right: var(--lh-score-icon-width); -} - .lh-audit--error .lh-audit__display-text { color: var(--fail-color); } @@ -577,22 +576,68 @@ /* Audit Group */ .lh-audit-group { - padding-top: var(--lh-audit-group-vpadding); - border-top: 1px solid var(--report-secondary-border-color); - padding-left: var(--expandable-indent); + padding: var(--lh-audit-group-vpadding) 0; + border-bottom: 1px solid var(--report-secondary-border-color); +} + +.lh-audit-group:last-child { + border-bottom: none; } .lh-audit-group__header { font-size: var(--subheader-font-size); line-height: var(--subheader-line-height); + color: var(--subheader-color); flex: 1; + font-weight: bold; +} + +.lh-audit-group__header::before { + content: ''; + width: calc(var(--subheader-font-size) / 14 * 24); + height: calc(var(--subheader-font-size) / 14 * 24); + margin-right: calc(var(--subheader-font-size) / 2); + background: var(--medium-100-gray) none no-repeat center / 16px; + display: inline-block; + border-radius: 50%; + vertical-align: middle; +} + +/* A11y/Seo groups within Passed don't get an icon */ +.lh-audit-group--unadorned .lh-audit-group__header::before { + content: none; +} + + +.lh-audit-group--manual .lh-audit-group__header::before { + background-image: var(--search-icon-url); +} +.lh-passed-audits .lh-audit-group__header::before { + background-image: var(--check-icon-url); +} +.lh-audit-group--diagnostics .lh-audit-group__header::before { + background-image: var(--search-icon-url); +} +.lh-audit-group--opportunities .lh-audit-group__header::before { + background-image: var(--photo-filter-icon-url); +} +.lh-audit-group--metrics .lh-audit-group__header::before { + background-image: var(--av-timer-icon-url); +} +.lh-audit-group--notapplicable .lh-audit-group__header::before { + background-image: var(--remove-circle-icon-url); +} + +/* Removing too much whitespace */ +.lh-audit-group--metrics { + margin-top: -28px; + border-bottom: none; } .lh-audit-group__summary { display: flex; justify-content: space-between; - margin-bottom: var(--lh-audit-group-vpadding); - margin-left: calc(0px - var(--expandable-indent)); + padding-right: var(--text-indent); } .lh-audit-group__itemcount { @@ -601,15 +646,17 @@ } .lh-audit-group__summary .lh-toggle-arrow { - margin-top: calc((var(--subheader-line-height) - 12px) / 2); + } .lh-audit-group__description { font-size: var(--body-font-size); - color: var(--secondary-text-color); - margin-top: calc(0px - var(--lh-audit-group-vpadding)); - margin-bottom: var(--lh-audit-group-vpadding); - line-height: var(--body-line-height); + color: var(--medium-75-gray); + margin: var(--lh-audit-group-vpadding) 0; +} + +.lh-audit-group--unadorned .lh-audit-group__description { + margin-top: 0; } @@ -620,18 +667,6 @@ margin-top: 3px; } -.lh-debug::before { - display: none; - content: ''; - background: url('data:image/svg+xml;utf8,warn') no-repeat 50% 50%; - background-size: contain; - width: 20px; - height: 20px; - position: relative; - margin-right: calc(var(--default-padding) / 2); - top: 5px; -} - /* Report */ @@ -736,6 +771,10 @@ border-top: 1px solid var(--report-border-color); } +.lh-category:first-of-type { + padding-top: calc(2 * var(--section-padding)); +} + /* section hash link jump should preserve fixed header https://css-tricks.com/hash-tag-links-padding/ */ @@ -756,6 +795,10 @@ margin-bottom: var(--lh-section-vpadding); } +.lh-category-header__title { + line-height: 24px; +} + .lh-category-header .lh-score__gauge .lh-gauge__label { display: none; } @@ -840,9 +883,9 @@ summary.lh-passed-audits-summary { .lh-table { --image-preview-size: 24px; - border: 1px solid var(--report-secondary-border-color); border-collapse: collapse; width: 100%; + margin-bottom: var(--lh-audit-vpadding); --url-col-max-width: 450px; } @@ -850,6 +893,12 @@ summary.lh-passed-audits-summary { .lh-table thead { background: var(--lh-table-header-bg); } +.lh-table thead th, +.lh-details summary { + color: var(--medium-75-gray); + font-weight: normal; + text-align: left; +} .lh-table tbody tr:nth-child(even) { background-color: var(--lh-table-higlight-bg); @@ -925,9 +974,9 @@ summary.lh-passed-audits-summary { .tooltip-boundary:hover .tooltip { display: block; - animation: fadeInTooltip 150ms; + animation: fadeInTooltip 250ms; animation-fill-mode: forwards; - animation-delay: 900ms; + animation-delay: 850ms; min-width: 23em; background: #ffffff; padding: 15px; @@ -955,5 +1004,3 @@ summary.lh-passed-audits-summary { 75% { opacity: 1; } 100% { opacity: 1; filter: drop-shadow(1px 0px 1px #aaa) drop-shadow(0px 2px 4px hsla(206, 6%, 25%, 0.15)); } } - -/*# sourceURL=report.styles.css */ diff --git a/lighthouse-core/report/html/templates.html b/lighthouse-core/report/html/templates.html index fff99ad8d3d0..d5bffd69aab2 100644 --- a/lighthouse-core/report/html/templates.html +++ b/lighthouse-core/report/html/templates.html @@ -425,7 +425,7 @@

Lighthouse