diff --git a/lighthouse-core/audits/dobetterweb/no-vulnerable-libraries.js b/lighthouse-core/audits/dobetterweb/no-vulnerable-libraries.js
index dff555f48518..8278a520b7e6 100644
--- a/lighthouse-core/audits/dobetterweb/no-vulnerable-libraries.js
+++ b/lighthouse-core/audits/dobetterweb/no-vulnerable-libraries.js
@@ -171,9 +171,9 @@ class NoVulnerableLibrariesAudit extends Audit {
let displayValue = '';
if (totalVulns > 1) {
- displayValue = `${totalVulns} vulnerabilities detected.`;
+ displayValue = `${totalVulns} vulnerabilities detected`;
} else if (totalVulns === 1) {
- displayValue = `${totalVulns} vulnerability was detected.`;
+ displayValue = `${totalVulns} vulnerability detected`;
}
const headings = [
diff --git a/lighthouse-core/audits/dobetterweb/uses-http2.js b/lighthouse-core/audits/dobetterweb/uses-http2.js
index ce68259a7eaf..54c41b4ae4ae 100644
--- a/lighthouse-core/audits/dobetterweb/uses-http2.js
+++ b/lighthouse-core/audits/dobetterweb/uses-http2.js
@@ -61,9 +61,9 @@ class UsesHTTP2Audit extends Audit {
let displayValue = '';
if (resources.length > 1) {
displayValue =
- `${Util.formatNumber(resources.length)} requests were not handled over HTTP/2`;
+ `${Util.formatNumber(resources.length)} requests not served via HTTP/2`;
} else if (resources.length === 1) {
- displayValue = `${resources.length} request was not handled over HTTP/2`;
+ displayValue = `${resources.length} request not served via HTTP/2`;
}
const headings = [
diff --git a/lighthouse-core/report/html/renderer/dom.js b/lighthouse-core/report/html/renderer/dom.js
index f6905b2af8ec..69ce25b9f15e 100644
--- a/lighthouse-core/report/html/renderer/dom.js
+++ b/lighthouse-core/report/html/renderer/dom.js
@@ -152,6 +152,14 @@ class DOM {
return this._document;
}
+ /**
+ * TODO(paulirish): import and conditionally apply the DevTools frontend subclasses instead of this
+ * @return {boolean}
+ */
+ isDevTools() {
+ return !!this._document.querySelector('.lh-devtools');
+ }
+
/**
* Guaranteed context.querySelector. Always returns an element or throws if
* nothing matches query.
diff --git a/lighthouse-core/report/html/renderer/report-renderer.js b/lighthouse-core/report/html/renderer/report-renderer.js
index 0c8c16a45dbb..011dfe869c2f 100644
--- a/lighthouse-core/report/html/renderer/report-renderer.js
+++ b/lighthouse-core/report/html/renderer/report-renderer.js
@@ -60,19 +60,35 @@ class ReportRenderer {
* @return {DocumentFragment}
*/
_renderReportHeader(report) {
- const header = this._dom.cloneTemplate('#tmpl-lh-heading', this._templateContext);
- this._dom.find('.lh-config__timestamp', header).textContent =
+ const el = this._dom.cloneTemplate('#tmpl-lh-heading', this._templateContext);
+ const domFragment = this._dom.cloneTemplate('#tmpl-lh-scores-wrapper', this._templateContext);
+ const placeholder = this._dom.find('.lh-scores-wrapper-placeholder', el);
+ /** @type {HTMLDivElement} */ (placeholder.parentNode).replaceChild(domFragment, placeholder);
+
+ this._dom.find('.lh-config__timestamp', el).textContent =
Util.formatDateTime(report.fetchTime);
- this._dom.find('.lh-product-info__version', header).textContent = report.lighthouseVersion;
- const url = /** @type {HTMLAnchorElement} */ (this._dom.find('.lh-metadata__url', header));
- const toolbarUrl = /** @type {HTMLAnchorElement}*/ (this._dom.find('.lh-toolbar__url', header));
- url.href = url.textContent = toolbarUrl.href = toolbarUrl.textContent = report.finalUrl;
+ this._dom.find('.lh-product-info__version', el).textContent = report.lighthouseVersion;
+ const metadataUrl = /** @type {HTMLAnchorElement} */ (this._dom.find('.lh-metadata__url', el));
+ const toolbarUrl = /** @type {HTMLAnchorElement}*/ (this._dom.find('.lh-toolbar__url', el));
+ metadataUrl.href = metadataUrl.textContent = report.finalUrl;
+ toolbarUrl.href = toolbarUrl.textContent = report.finalUrl;
const emulationDescriptions = Util.getEmulationDescriptions(report.configSettings || {});
- this._dom.find('.lh-config__emulation', header).textContent = emulationDescriptions.summary;
- return header;
+ this._dom.find('.lh-config__emulation', el).textContent = emulationDescriptions.summary;
+ return el;
+ }
+
+ /**
+ * @return {Element}
+ */
+ _renderReportShortHeader() {
+ const shortHeaderContainer = this._dom.createElement('div', 'lh-header-container');
+ const wrapper = this._dom.cloneTemplate('#tmpl-lh-scores-wrapper', this._templateContext);
+ shortHeaderContainer.appendChild(wrapper);
+ return shortHeaderContainer;
}
+
/**
* @param {ReportJSON} report
* @return {DocumentFragment}
@@ -124,12 +140,19 @@ class ReportRenderer {
* @return {DocumentFragment}
*/
_renderReport(report) {
- const headerStickyContainer = this._dom.createElement('div', 'lh-header-sticky');
- headerStickyContainer.appendChild(this._renderReportHeader(report));
- const scoreContainer = this._dom.find('.lh-scores-container', headerStickyContainer);
+ let header;
+ const headerContainer = this._dom.createElement('div');
+ if (this._dom.isDevTools()) {
+ headerContainer.classList.add('lh-header-plain');
+ header = this._renderReportShortHeader();
+ } else {
+ headerContainer.classList.add('lh-header-sticky');
+ header = this._renderReportHeader(report);
+ }
+ headerContainer.appendChild(header);
+ const scoresContainer = this._dom.find('.lh-scores-container', headerContainer);
const container = this._dom.createElement('div', 'lh-container');
-
const reportSection = container.appendChild(this._dom.createElement('div', 'lh-report'));
reportSection.appendChild(this._renderReportWarnings(report));
@@ -138,6 +161,8 @@ class ReportRenderer {
const isSoloCategory = report.reportCategories.length === 1;
if (!isSoloCategory) {
scoreHeader = this._dom.createElement('div', 'lh-scores-header');
+ } else {
+ headerContainer.classList.add('lh-header--solo-category');
}
const detailsRenderer = new DetailsRenderer(this._dom);
@@ -162,14 +187,14 @@ class ReportRenderer {
if (scoreHeader) {
const scoreScale = this._dom.cloneTemplate('#tmpl-lh-scorescale', this._templateContext);
- scoreContainer.appendChild(scoreHeader);
- scoreContainer.appendChild(scoreScale);
+ scoresContainer.appendChild(scoreHeader);
+ scoresContainer.appendChild(scoreScale);
}
reportSection.appendChild(this._renderReportFooter(report));
const reportFragment = this._dom.createFragment();
- reportFragment.appendChild(headerStickyContainer);
+ reportFragment.appendChild(headerContainer);
reportFragment.appendChild(container);
return reportFragment;
diff --git a/lighthouse-core/report/html/renderer/report-ui-features.js b/lighthouse-core/report/html/renderer/report-ui-features.js
index 3f849dba494e..d230b1486ed0 100644
--- a/lighthouse-core/report/html/renderer/report-ui-features.js
+++ b/lighthouse-core/report/html/renderer/report-ui-features.js
@@ -71,6 +71,8 @@ class ReportUIFeatures {
* @param {ReportJSON} report
*/
initFeatures(report) {
+ if (this._dom.isDevTools()) return;
+
this.json = report;
this._setupMediaQueryListeners();
this._setupExportButton();
diff --git a/lighthouse-core/report/html/report-styles.css b/lighthouse-core/report/html/report-styles.css
index e72e7fb98a08..c3c9a43cc253 100644
--- a/lighthouse-core/report/html/report-styles.css
+++ b/lighthouse-core/report/html/report-styles.css
@@ -66,6 +66,10 @@
--lh-audit-group-vpadding: 8px;
--lh-section-vpadding: 12px;
--chevron-size: 12px;
+
+ /* Voodoo magic here to get narrow columns. 0 doesn't size the column like our friend 1px does */
+ --bytes-col-width: 1px;
+
--pass-icon-url: url('data:image/svg+xml;utf8,');
--average-icon-url: url('data:image/svg+xml;utf8,');
--fail-icon-url: url('data:image/svg+xml;utf8,');
@@ -93,8 +97,8 @@
--caption-font-size: 11px;
--caption-line-height: 14px;
--default-padding: 12px;
- --section-padding: 16px;
- --section-indent: 16px;
+ --section-padding: 12px;
+ --section-indent: 8px;
--audit-group-indent: 16px;
--audit-indent: 16px;
--expandable-indent: 16px;
@@ -105,7 +109,6 @@
--lh-section-vpadding: 8px;
}
-
@keyframes fadeIn {
0% { opacity: 0;}
100% { opacity: 0.6;}
@@ -610,6 +613,10 @@
z-index: 2;
will-change: transform;
}
+.lh-header-plain {
+ margin-top: var(--section-padding);
+}
+
.lh-header-container {
display: block;
margin: 0 auto;
@@ -708,6 +715,11 @@
background-color: var(--fail-color);
}
+/* Hide category score gauages if it's a single category report */
+.lh-header--solo-category .lh-scores-wrapper {
+ display: none;
+}
+
.lh-categories {
width: 100%;
@@ -831,8 +843,6 @@ summary.lh-passed-audits-summary {
.lh-table {
--image-preview-size: 24px;
border-collapse: collapse;
-
- --url-col-max-width: 450px;
}
.lh-table thead {
@@ -866,7 +876,13 @@ summary.lh-passed-audits-summary {
text-align: left;
min-width: 250px;
white-space: nowrap;
- max-width: var(--url-col-max-width);
+ max-width: 0;
+}
+
+/* Keep bytes columns narrow if they follow the URL column */
+.lh-table-column--url + th.lh-table-column--bytes,
+.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--bytes {
+ width: var(--bytes-col-width);
}
.lh-table-column--code {
@@ -950,13 +966,22 @@ summary.lh-passed-audits-summary {
position: absolute;
display: none; /* Don't retain these layers when not needed */
opacity: 0;
-
background: #ffffff;
- min-width: 23em;
+ min-width: 246px;
+ max-width: 275px;
padding: 15px;
border-radius: 5px;
text-align: initial;
}
+/* shrink tooltips to not be cutoff on left edge of narrow viewports
+ 45vw is chosen to be ~= width of the left column of metrics
+*/
+@media screen and (max-width: 535px) {
+ .tooltip {
+ min-width: 45vw;
+ padding: 3vw;
+ }
+}
.tooltip-boundary:hover {
background-color: #F8F9FA;
diff --git a/lighthouse-core/report/html/templates.html b/lighthouse-core/report/html/templates.html
index 1c0c6b97305a..770432f86343 100644
--- a/lighthouse-core/report/html/templates.html
+++ b/lighthouse-core/report/html/templates.html
@@ -99,6 +99,39 @@
+
+
+
+
+
+
+
+