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,check'); --average-icon-url: url('data:image/svg+xml;utf8,info'); --fail-icon-url: url('data:image/svg+xml;utf8,warn'); @@ -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 @@ + + + + +