Repository: GoogleChrome/lighthouse
Pull request #8883 (2019-05-06 18:07:11)

report(redesign): don't init sticky header features for single category reports
#8185


Patch:
diff --git a/lighthouse-core/audits/performance-budget.js b/lighthouse-core/audits/performance-budget.js
index f47f4f1de..71f3630e9 100644
--- a/lighthouse-core/audits/performance-budget.js
+++ b/lighthouse-core/audits/performance-budget.js
@@ -12,9 +12,9 @@ const i18n = require('../lib/i18n/i18n.js');
 const UIStrings = {
   /** Title of a Lighthouse audit that compares the size and quantity of page resources against targets set by the user. These targets are thought of as "performance budgets" because these metrics impact page performance (i.e. how quickly a page loads). */
   title: 'Performance budget',
-  /** Description of a Lighthouse audit where a user sets budgets for the quantity and size of page resources. No character length limits. */
+  /** Description of a Lighthouse audit where a user sets budgets for the quantity and size of page resources. No character length limits. 'Learn More' becomes link text to additional documentation. */
   description: 'Keep the quantity and size of network requests under the targets ' +
-    'set by the provided performance budget.',
+    'set by the provided performance budget. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/budgets).',
   /** [ICU Syntax] Entry in a data table identifying the number of network requests of a particular type. Count will be a whole number. String should be as short as possible to be able to fit well into the table. */
   requestCountOverBudget: `{count, plural,
     =1 {1 request}
diff --git a/lighthouse-core/audits/resource-summary.js b/lighthouse-core/audits/resource-summary.js
index b39add3ae..d7835a9cb 100644
--- a/lighthouse-core/audits/resource-summary.js
+++ b/lighthouse-core/audits/resource-summary.js
@@ -12,9 +12,9 @@ const i18n = require('../lib/i18n/i18n.js');
 const UIStrings = {
   /** Imperative title of a Lighthouse audit that tells the user to minimize the size and quantity of resources used to load the page. */
   title: 'Keep request counts low and transfer sizes small',
-  /** Description of a Lighthouse audit that tells the user that they can setup a budgets for the quantity and size of page resources. No character length limits. */
+  /** Description of a Lighthouse audit that tells the user that they can setup a budgets for the quantity and size of page resources. No character length limits. 'Learn More' becomes link text to additional documentation. */
   description: 'To set budgets for the quantity and size of page resources,' +
-    ' add a budget.json file.',
+    ' add a budget.json file. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/budgets).',
   /** [ICU Syntax] Label for an audit identifying the number of requests and kilobytes used to load the page. */
   displayValue: `{requestCount, plural, =1 {1 request} other {# requests}}` +
     ` • { byteCount, number, bytes } KB`,
diff --git a/lighthouse-core/lib/i18n/en-US.json b/lighthouse-core/lib/i18n/en-US.json
index e40e4f048..02e444d58 100644
--- a/lighthouse-core/lib/i18n/en-US.json
+++ b/lighthouse-core/lib/i18n/en-US.json
@@ -744,8 +744,8 @@
     "description": "Descriptive title of a Lighthouse audit that tells the user the server latencies observed from each origin the page connected to. This is displayed in a list of audit titles that Lighthouse generates."
   },
   "lighthouse-core/audits/performance-budget.js | description": {
-    "message": "Keep the quantity and size of network requests under the targets set by the provided performance budget.",
-    "description": "Description of a Lighthouse audit where a user sets budgets for the quantity and size of page resources. No character length limits."
+    "message": "Keep the quantity and size of network requests under the targets set by the provided performance budget. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/budgets).",
+    "description": "Description of a Lighthouse audit where a user sets budgets for the quantity and size of page resources. No character length limits. 'Learn More' becomes link text to additional documentation."
   },
   "lighthouse-core/audits/performance-budget.js | requestCountOverBudget": {
     "message": "{count, plural,\n    =1 {1 request}\n    other {# requests}\n   }",
@@ -764,8 +764,8 @@
     "description": "Imperative title of a Lighthouse audit that tells the user to eliminate the redirects taken through multiple URLs to load the page. This is shown in a list of audits that Lighthouse generates."
   },
   "lighthouse-core/audits/resource-summary.js | description": {
-    "message": "To set budgets for the quantity and size of page resources, add a budget.json file.",
-    "description": "Description of a Lighthouse audit that tells the user that they can setup a budgets for the quantity and size of page resources. No character length limits."
+    "message": "To set budgets for the quantity and size of page resources, add a budget.json file. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/budgets).",
+    "description": "Description of a Lighthouse audit that tells the user that they can setup a budgets for the quantity and size of page resources. No character length limits. 'Learn More' becomes link text to additional documentation."
   },
   "lighthouse-core/audits/resource-summary.js | displayValue": {
     "message": "{requestCount, plural, =1 {1 request} other {# requests}} • { byteCount, number, bytes } KB",
diff --git a/lighthouse-core/report/html/renderer/category-renderer.js b/lighthouse-core/report/html/renderer/category-renderer.js
index e61b4b3b5..b03bdf238 100644
--- a/lighthouse-core/report/html/renderer/category-renderer.js
+++ b/lighthouse-core/report/html/renderer/category-renderer.js
@@ -128,10 +128,10 @@ class CategoryRenderer {
 
     // Add list of warnings or singular warning
     const warningsEl = this.dom.createChildOf(titleEl, 'div', 'lh-warnings');
+    this.dom.createChildOf(warningsEl, 'span').textContent = Util.UIStrings.warningHeader;
     if (warnings.length === 1) {
-      warningsEl.textContent = `${Util.UIStrings.warningHeader} ${warnings.join('')}`;
+      warningsEl.appendChild(this.dom.document().createTextNode(warnings.join('')));
     } else {
-      warningsEl.textContent = Util.UIStrings.warningHeader;
       const warningsUl = this.dom.createChildOf(warningsEl, 'ul');
       for (const warning of warnings) {
         const item = this.dom.createChildOf(warningsUl, 'li');
diff --git a/lighthouse-core/report/html/renderer/performance-category-renderer.js b/lighthouse-core/report/html/renderer/performance-category-renderer.js
index 0575015c0..943f80d69 100644
--- a/lighthouse-core/report/html/renderer/performance-category-renderer.js
+++ b/lighthouse-core/report/html/renderer/performance-category-renderer.js
@@ -147,8 +147,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
 
     // 'Values are estimated and may vary' is used as the category description for PSI
     if (environment !== 'PSI') {
-      const estValuesEl = this.dom.createChildOf(metricsColumn2El, 'div',
-          'lh-metrics__disclaimer lh-metrics__disclaimer');
+      const estValuesEl = this.dom.createChildOf(metricsColumn1El, 'div', 'lh-metrics__disclaimer');
       estValuesEl.textContent = Util.UIStrings.varianceDisclaimer;
     }
 
diff --git a/lighthouse-core/report/html/renderer/report-ui-features.js b/lighthouse-core/report/html/renderer/report-ui-features.js
index cb9ef74d9..e0733f3b5 100644
--- a/lighthouse-core/report/html/renderer/report-ui-features.js
+++ b/lighthouse-core/report/html/renderer/report-ui-features.js
@@ -82,18 +82,21 @@ class ReportUIFeatures {
 
     this.json = report;
     this._setupMediaQueryListeners();
-    this._setupSmoothScroll();
     this._setupExportButton();
     this._setupThirdPartyFilter();
-    this._setupStickyHeaderElements();
     this._setUpCollapseDetailsAfterPrinting();
     this._resetUIState();
     this._document.addEventListener('keyup', this.onKeyUp);
     this._document.addEventListener('copy', this.onCopy);
-    this._document.addEventListener('scroll', this._updateStickyHeaderOnScroll);
-    window.addEventListener('resize', this._updateStickyHeaderOnScroll);
     const topbarLogo = this._dom.find('.lh-topbar__logo', this._document);
     topbarLogo.addEventListener('click', this._toggleDarkTheme);
+
+    // There is only a sticky header when at least 2 categories are present.
+    if (Object.keys(this.json.categories).length >= 2) {
+      this._setupStickyHeaderElements();
+      this._document.addEventListener('scroll', this._updateStickyHeaderOnScroll);
+      window.addEventListener('resize', this._updateStickyHeaderOnScroll);
+    }
   }
 
   /**
@@ -114,17 +117,6 @@ class ReportUIFeatures {
     this.onMediaQueryChange(mediaQuery);
   }
 
-  _setupSmoothScroll() {
-    for (const el of this._dom.findAll('a.lh-gauge__wrapper', this._document)) {
-      const anchorElement = /** @type {HTMLAnchorElement} */ (el);
-      anchorElement.addEventListener('click', e => {
-        e.preventDefault();
-        window.history.pushState({}, '', anchorElement.hash);
-        this._dom.find(anchorElement.hash, this._document).scrollIntoView({behavior: 'smooth'});
-      });
-    }
-  }
-
   /**
    * Handle media query change events.
    * @param {MediaQueryList|MediaQueryListEvent} mql
diff --git a/lighthouse-core/report/html/report-styles.css b/lighthouse-core/report/html/report-styles.css
index f09c9f423..39f353415 100644
--- a/lighthouse-core/report/html/report-styles.css
+++ b/lighthouse-core/report/html/report-styles.css
@@ -76,6 +76,7 @@
   --lh-audit-group-vpadding: 8px;
   --lh-section-vpadding: 12px;
   --chevron-size: 12px;
+  --inner-audit-left-padding: calc(var(--score-shape-size) + var(--score-shape-margin-left) + var(--score-shape-margin-right));
 
   /* Palette. */
   --color-black-100: #F5F5F5;
@@ -105,8 +106,8 @@
   --env-name-min-width: 220px;
   --env-tem-padding: 10px 0px;
   --expandable-padding: 0 0 2px calc(var(--score-shape-margin-left) + var(--score-shape-size) + var(--score-shape-margin-right));
-  --gauge-circle-size-big: 120px;
-  --gauge-circle-size: 96px;
+  --gauge-circle-size-big: 112px;
+  --gauge-circle-size: 80px;
   --header-padding: 20px 0 20px 0;
   --highlighter-bg: var(--color-black-400);
   --icon-square-size: calc(var(--score-shape-size) * 0.88);
@@ -116,14 +117,13 @@
   --plugin-icon-size: 65%;
   --pwa-icon-margin: 0 6px 0 -2px;
   --pwa-icon-size: var(--topbar-icon-size);
-  --score-container-padding: 12px;
-  --score-container-width: 160px;
-  --score-number-font-size-big: 42px;
-  --score-number-font-size: 34px;
+  --score-container-padding: 8px;
+  --score-container-width: 148px;
+  --score-number-font-size-big: 38px;
+  --score-number-font-size: 28px;
   --score-shape-margin-left: 4px;
   --score-shape-margin-right: 12px;
-  --score-shape-margin-top: 7px;
-  --score-shape-margin: var(--score-shape-margin-top) var(--score-shape-margin-right) 0 var(--score-shape-margin-left);
+  --score-shape-margin: 0 var(--score-shape-margin-right) 0 var(--score-shape-margin-left);
   --score-shape-size: 12px;
   --score-title-font-size-big: 28px;
   --score-title-font-size: 20px;
@@ -133,7 +133,7 @@
   --scorescale-width: 18px;
   --section-padding: 40px;
   --topbar-bg: var(--color-black-100);
-  --topbar-height: 36px;
+  --topbar-height: 32px;
   --topbar-icon-size: 24px;
   --topbar-padding: 0 8px;
   --metrics-toggle-color: var(--color-black-200);
@@ -215,19 +215,17 @@
     --header-padding: 16px 0 16px 0;
     --plugin-icon-size: 75%;
     --pwa-icon-margin: 0 7px 0 -3px;
-    --score-container-padding: 8px;
     --score-container-width: 112px;
     --score-number-font-size-big: 34px;
     --score-number-font-size: 26px;
     --score-shape-margin-left: 2px;
-    --score-shape-margin-top: 7px;
     --score-shape-size: 10px;
     --score-title-font-size-big: 22px;
     --score-title-font-size: 14px;
     --score-title-line-height-big: 26px;
     --score-title-line-height: 20px;
     --section-padding: 24px;
-    --topbar-height: 32px;
+    --topbar-height: 28px;
     --topbar-icon-size: 20px;
   }
 
@@ -328,7 +326,6 @@
 }
 
 .lh-audit__description, .lh-audit__stackpack {
-  --inner-audit-left-padding: calc(var(--text-indent) + var(--lh-audit-index-width) + 2 * var(--audit-item-gap));
   --inner-audit-right-padding: calc(var(--text-indent) + 2px);
   padding-left: var(--inner-audit-left-padding);
   padding-right: var(--inner-audit-right-padding);
@@ -340,6 +337,7 @@
   font-size: var(--body-font-size);
   margin-top: var(--default-padding);
   margin-bottom: var(--default-padding);
+  margin-left: var(--inner-audit-left-padding);
   /* whatever the .lh-details side margins are */
   width: 100%;
 }
@@ -461,6 +459,7 @@
 }
 .lh-category-header__description  {
   font-size: var(--body-font-size);
+  text-align: center;
   margin: 0px auto;
   max-width: 400px;
 }
@@ -491,6 +490,7 @@
 /* Expandable Details (Audit Groups, Audits) */
 .lh-audit__header {
   display: flex;
+  align-items: center;
   font-weight: 500;
   padding: var(--lh-audit-vpadding) 0;
 }
@@ -563,9 +563,10 @@
 
 .lh-metric__innerwrap {
   display: flex;
+  align-items: center;
   flex-wrap: wrap;
   justify-content: space-between;
-  padding: 8px var(--text-indent);
+  padding: 10px var(--text-indent);
 }
 
 .lh-metric__details {
@@ -579,7 +580,6 @@
 
 .lh-metrics__disclaimer {
   color: var(--medium-75-gray);
-  text-align: right;
   margin: var(--lh-section-vpadding) 0;
   padding: 0 var(--text-indent);
 }
@@ -711,9 +711,7 @@
 }
 
 .lh-load-opportunity__header .lh-load-opportunity__col {
-  background-color: var(--medium-50-gray);
   color: var(--medium-75-gray);
-  text-align: center;
   display: unset;
   line-height: calc(2.3 * var(--body-font-size));
 }
@@ -724,10 +722,12 @@
 
 .lh-load-opportunity__col--one {
   flex: 5;
+  align-items: center;
   margin-right: 2px;
 }
 .lh-load-opportunity__col--two {
   flex: 4;
+  text-align: right;
 }
 
 .lh-audit--load-opportunity .lh-audit__display-text {
@@ -888,6 +888,10 @@
   /* When the header takes 100% width, the chevron becomes small. */
   max-width: calc(100% - var(--chevron-size));
 }
+/* max-width makes the metric toggle not flush. metrics doesn't have a chevron so unset. */
+.lh-audit-group--metrics .lh-audit-group__header {
+  max-width: unset;
+}
 
 .lh-audit-group__header span.lh-audit-group__title {
   font-weight: bold;
@@ -970,11 +974,13 @@
 
 .lh-warnings {
   --item-margin: calc(var(--body-line-height) / 6);
-  border: 1px solid var(--color-average);
-  border-radius: 4px;
+  color: var(--color-average);
   margin: var(--lh-audit-vpadding) 0;
   padding: calc(var(--lh-audit-vpadding) / 2) var(--lh-audit-vpadding);
 }
+.lh-warnings span {
+  font-weight: bold;
+}
 
 .lh-warnings--toplevel {
   --item-margin: calc(var(--header-line-height) / 4);
@@ -1160,18 +1166,18 @@
 .lh-table {
   --image-preview-size: 24px;
   border-collapse: collapse;
+  /* Can't assign padding to table, so shorten the width instead. */
+  width: calc(100% - var(--inner-audit-left-padding));
 }
 
-.lh-table thead {
-  background-color: var(--lh-table-higlight-bg);
-}
 .lh-table thead th {
   font-weight: normal;
+  color: var(--color-black-600);
   /* See text-wrapping comment on .lh-container. */
   word-break: normal;
 }
 
-.lh-table tbody tr:nth-child(even) {
+.lh-table tbody tr:nth-child(odd) {
   background-color: var(--lh-table-higlight-bg);
 }
 
@@ -1179,6 +1185,12 @@
 .lh-table td {
   padding: 8px 6px;
 }
+.lh-table th:first-child {
+  padding-left: 0;
+}
+.lh-table th:last-child {
+  padding-right: 0;
+}
 
 /* Looks unnecessary, but mostly for keeping the <th>s left-aligned */
 .lh-table-column--text,
diff --git a/lighthouse-core/report/html/templates.html b/lighthouse-core/report/html/templates.html
index 5893421c3..cc96aee34 100644
--- a/lighthouse-core/report/html/templates.html
+++ b/lighthouse-core/report/html/templates.html
@@ -180,8 +180,6 @@ limitations under the License.
       justify-content: center;
       background-color: var(--color-sticky-header-bg);
       border-bottom: 1px solid var(--color-black-200);
-      padding-top: var(--score-container-padding);
-      padding-bottom: 4px;
       z-index: 1000;
       pointer-events: none;
       opacity: 0;
@@ -234,6 +232,7 @@ limitations under the License.
     .lh-topbar__logo {
       width: var(--topbar-icon-size);
       height: var(--topbar-icon-size);
+      user-select: none;
     }
     .lh-topbar__logo .shape {
       fill: var(--body-text-color);
@@ -267,7 +266,7 @@ limitations under the License.
     }
     .lh-export__button.active + .lh-export__dropdown {
       opacity: 1;
-      clip: rect(0, 187px, 242px, 0);
+      clip: rect(-1px, 187px, 242px, -3px);
     }
     .lh-export__dropdown {
       position: absolute;
diff --git a/proto/sample_v2_round_trip.json b/proto/sample_v2_round_trip.json
index 0bd017558..89196f363 100644
--- a/proto/sample_v2_round_trip.json
+++ b/proto/sample_v2_round_trip.json
@@ -2032,7 +2032,7 @@
             "title": "Prevents users to paste into password fields"
         },
         "performance-budget": {
-            "description": "Keep the quantity and size of network requests under the targets set by the provided performance budget.",
+            "description": "Keep the quantity and size of network requests under the targets set by the provided performance budget. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/budgets).",
             "details": {
                 "headings": [
                     {
@@ -2245,7 +2245,7 @@
             "title": "Eliminate render-blocking resources"
         },
         "resource-summary": {
-            "description": "To set budgets for the quantity and size of page resources, add a budget.json file.",
+            "description": "To set budgets for the quantity and size of page resources, add a budget.json file. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/budgets).",
             "details": {
                 "headings": [
                     {
@@ -2453,51 +2453,51 @@
             "details": {
                 "headings": [
                     {
-                        "itemType": "node", 
-                        "key": "tapTarget", 
+                        "itemType": "node",
+                        "key": "tapTarget",
                         "text": "Tap Target"
-                    }, 
+                    },
                     {
-                        "itemType": "text", 
-                        "key": "size", 
+                        "itemType": "text",
+                        "key": "size",
                         "text": "Size"
-                    }, 
+                    },
                     {
-                        "itemType": "node", 
-                        "key": "overlappingTarget", 
+                        "itemType": "node",
+                        "key": "overlappingTarget",
                         "text": "Overlapping Target"
                     }
-                ], 
+                ],
                 "items": [
                     {
-                        "height": 18.0, 
-                        "overlapScoreRatio": 0.8333333333333334, 
+                        "height": 18.0,
+                        "overlapScoreRatio": 0.8333333333333334,
                         "overlappingTarget": {
-                            "path": "3,HTML,1,BODY,18,BUTTON", 
-                            "selector": "body > button.small-button", 
-                            "snippet": "<button class=\"small-button\">Do something else</button>", 
+                            "path": "3,HTML,1,BODY,18,BUTTON",
+                            "selector": "body > button.small-button",
+                            "snippet": "<button class=\"small-button\">Do something else</button>",
                             "type": "node"
-                        }, 
-                        "overlappingTargetScore": 720.0, 
-                        "size": "200x18", 
+                        },
+                        "overlappingTargetScore": 720.0,
+                        "size": "200x18",
                         "tapTarget": {
-                            "path": "3,HTML,1,BODY,17,BUTTON", 
-                            "selector": "body > button.small-button", 
-                            "snippet": "<button class=\"small-button\">Do something</button>", 
+                            "path": "3,HTML,1,BODY,17,BUTTON",
+                            "selector": "body > button.small-button",
+                            "snippet": "<button class=\"small-button\">Do something</button>",
                             "type": "node"
-                        }, 
-                        "tapTargetScore": 864.0, 
+                        },
+                        "tapTargetScore": 864.0,
                         "width": 200.0
                     }
-                ], 
+                ],
                 "type": "table"
-            }, 
-            "displayValue": "0% appropriately sized tap targets", 
-            "id": "tap-targets", 
-            "score": 0.0, 
-            "scoreDisplayMode": "binary", 
+            },
+            "displayValue": "0% appropriately sized tap targets",
+            "id": "tap-targets",
+            "score": 0.0,
+            "scoreDisplayMode": "binary",
             "title": "Tap targets are not sized appropriately"
-        }, 
+        },
         "td-headers-attr": {
             "description": "Screen readers have features to make navigating tables easier. Ensuring `<td>` cells using the `[headers]` attribute only refer to other cells in the same table may improve the experience for screen reader users. [Learn more](https://dequeuniversity.com/rules/axe/3.1/td-headers-attr?application=lighthouse).",
             "id": "td-headers-attr",
@@ -3773,11 +3773,11 @@
                     "id": "structured-data",
                     "weight": 0.0
                 }
-            ], 
-            "description": "These checks ensure that your page is optimized for search engine results ranking. There are additional factors Lighthouse does not check that may affect your search ranking. [Learn more](https://support.google.com/webmasters/answer/35769).", 
-            "id": "seo", 
-            "manualDescription": "Run these additional validators on your site to check additional SEO best practices.", 
-            "score": 0.73, 
+            ],
+            "description": "These checks ensure that your page is optimized for search engine results ranking. There are additional factors Lighthouse does not check that may affect your search ranking. [Learn more](https://support.google.com/webmasters/answer/35769).",
+            "id": "seo",
+            "manualDescription": "Run these additional validators on your site to check additional SEO best practices.",
+            "score": 0.73,
             "title": "SEO"
         }
     },


Test patch:
diff --git a/lighthouse-core/test/report/html/renderer/report-ui-features-test.js b/lighthouse-core/test/report/html/renderer/report-ui-features-test.js
index 09c8ed5ea..4e83cd0cc 100644
--- a/lighthouse-core/test/report/html/renderer/report-ui-features-test.js
+++ b/lighthouse-core/test/report/html/renderer/report-ui-features-test.js
@@ -108,6 +108,15 @@ describe('ReportUIFeatures', () => {
       assert.equal(dom.findAll('.lh-category', container).length, 5);
     });
 
+    it('should init a report with a single category', () => {
+      const lhr = JSON.parse(JSON.stringify(sampleResults));
+      lhr.categories = {
+        performance: lhr.categories.performance,
+      };
+      const container = render(lhr);
+      assert.equal(dom.findAll('.lh-category', container).length, 1);
+    });
+
     describe('third-party filtering', () => {
       let container;
 
diff --git a/lighthouse-core/test/results/sample_v2.json b/lighthouse-core/test/results/sample_v2.json
index cfe88c52d..95f002dd0 100644
--- a/lighthouse-core/test/results/sample_v2.json
+++ b/lighthouse-core/test/results/sample_v2.json
@@ -1276,7 +1276,7 @@
     "performance-budget": {
       "id": "performance-budget",
       "title": "Performance budget",
-      "description": "Keep the quantity and size of network requests under the targets set by the provided performance budget.",
+      "description": "Keep the quantity and size of network requests under the targets set by the provided performance budget. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/budgets).",
       "score": null,
       "scoreDisplayMode": "informative",
       "details": {
@@ -1379,7 +1379,7 @@
     "resource-summary": {
       "id": "resource-summary",
       "title": "Keep request counts low and transfer sizes small",
-      "description": "To set budgets for the quantity and size of page resources, add a budget.json file.",
+      "description": "To set budgets for the quantity and size of page resources, add a budget.json file. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/budgets).",
       "score": null,
       "scoreDisplayMode": "informative",
       "displayValue": "18 requests • 157 KB",