Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions public/js/compare/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ function pageXrayTemplate(d) {
const p1 = d.p1, p2 = d.p2, config = d.config;
const showRuns = d.runs1.length > 1 || d.runs2.length > 1;

function section(title) {
return '<tr class="pageXraySection"><th colspan="3">' + h(title) + '</th></tr>';
function section(title, kind) {
const cls = 'pageXraySection' + (kind ? ' pageXraySection--' + kind : '');
return '<tr class="' + cls + '"><th colspan="3">' + h(title) + '</th></tr>';
}

let html = '';
Expand Down Expand Up @@ -123,7 +124,7 @@ function pageXrayTemplate(d) {
'<td>' + h(p2.meta.connectivity) + '</td></tr>';
}

html += section('Content');
html += section('Content', 'content');
html += '<tr><td class="tabletext">Total</td>' +
'<td>' + p1.requests + ' (' + formatBytes(p1.transferSize) + ' / ' + formatBytes(p1.contentSize) + ')</td>' +
'<td>' + p2.requests + ' (' + formatBytes(p2.transferSize) + ' / ' + formatBytes(p2.contentSize) + ')</td></tr>';
Expand All @@ -144,7 +145,7 @@ function pageXrayTemplate(d) {
'<td>' + img2.requests + ' (' + formatBytes(img2.transferSize) + ')</td></tr>';

if (p1.renderBlocking && p2.renderBlocking) {
html += section('Render blocking');
html += section('Render blocking', 'blocking');
html += '<tr><td class="tabletext">Render blocking</td>' +
'<td>' + p1.renderBlocking.blocking + '</td>' +
'<td>' + p2.renderBlocking.blocking + '</td></tr>';
Expand Down Expand Up @@ -176,11 +177,18 @@ function pageXrayTemplate(d) {
'<td>' + formatTime(p2.visualMetrics[key]) + '</td></tr>';
}
});
if (vmHtml) html += section('Visual metrics') + vmHtml;
if (vmHtml) html += section('Visual metrics', 'visual') + vmHtml;
}

if (p1.googleWebVitals && p2.googleWebVitals) {
html += section('Core Web Vitals');
// CLS is a unitless float that browsers report at full precision
// (e.g. 0.05641193152186011). Round to three decimals — that's
// the granularity that matters for comparison and matches the
// convention used in the sitespeed.io HTML report.
function fmtCLS(v) {
return typeof v === 'number' ? v.toFixed(3) : (v == null ? '' : v);
}
html += section('Core Web Vitals', 'cwv');
html += '<tr><td class="tabletext">First Contentful Paint</td>' +
'<td>' + formatTime(p1.googleWebVitals.firstContentfulPaint) + '</td>' +
'<td>' + formatTime(p2.googleWebVitals.firstContentfulPaint) + '</td></tr>';
Expand All @@ -191,8 +199,8 @@ function pageXrayTemplate(d) {
'<td>' + formatTime(p1.googleWebVitals.totalBlockingTime) + '</td>' +
'<td>' + formatTime(p2.googleWebVitals.totalBlockingTime) + '</td></tr>';
html += '<tr><td class="tabletext">Cumulative Layout Shift</td>' +
'<td>' + p1.googleWebVitals.cumulativeLayoutShift + '</td>' +
'<td>' + p2.googleWebVitals.cumulativeLayoutShift + '</td></tr>';
'<td>' + fmtCLS(p1.googleWebVitals.cumulativeLayoutShift) + '</td>' +
'<td>' + fmtCLS(p2.googleWebVitals.cumulativeLayoutShift) + '</td></tr>';
}

if (p1.cpu && p2.cpu && p1.cpu.longTasks && p2.cpu.longTasks) {
Expand All @@ -212,7 +220,7 @@ function pageXrayTemplate(d) {
'<td>' + p1.cpu.longTasks.tasks + '</td>' +
'<td>' + p2.cpu.longTasks.tasks + '</td></tr>';
}
if (cpuHtml) html += section('CPU') + cpuHtml;
if (cpuHtml) html += section('CPU', 'cpu') + cpuHtml;
}

if (d.cpuCategories1 && d.cpuCategories2) {
Expand All @@ -221,7 +229,7 @@ function pageXrayTemplate(d) {
// CPU has no long-task data but we still want the disclosure rows
// visually under a heading).
if (!(p1.cpu && p2.cpu && p1.cpu.longTasks && p2.cpu.longTasks)) {
html += section('CPU');
html += section('CPU', 'cpu');
}
html += '<tr><td class="tabletext" colspan="3"> CPU time spent by category ' +
'<button onclick="toggleRow(this, \'cpuCategoryInfo\', this.childNodes[0]);" class="submit submit-smaller">' +
Expand Down Expand Up @@ -273,7 +281,7 @@ function pageXrayTemplate(d) {
'<td><a href="' + h(p1.meta.result) + '" target="_blank" rel="noopener noreferrer">Result page</a></td>' +
'<td><a href="' + h(p2.meta.result) + '" target="_blank" rel="noopener noreferrer">Result page</a></td></tr>';
}
if (capturesHtml) html += section('Captures') + capturesHtml;
if (capturesHtml) html += section('Captures', 'captures') + capturesHtml;

html += '</tbody></table></div>';
return html;
Expand Down
32 changes: 24 additions & 8 deletions src/css/page-xray.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,43 @@

/*
* Section divider rows — full-width header cells inserted between
* groups of related metrics ("Content", "Visual metrics", "Core Web
* Vitals", "CPU", "Captures"). Reads as a quiet, scannable label
* rather than competing with the data rows: small caps, secondary
* text colour, extra top padding to separate it from the previous
* group, and no hover treatment.
* groups of related metrics ("Content", "Render blocking", "Visual
* metrics", "Core Web Vitals", "CPU", "Captures"). Each kind gets
* its own quiet pastel/text pair so the eye can tell sections apart
* at a glance instead of seeing identical bars stacked down the
* table. Hover is suppressed so they stay visually distinct from
* data rows.
*/
.pageXrayTable .pageXraySection th {
text-align: left;
font-size: 0.7rem;
font-weight: var(--font-weight-semibold);
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--color-text-muted);
background: var(--color-surface);
padding: 14px 12px 6px;
border-bottom: 1px solid var(--color-border);
}
.pageXrayTable .pageXraySection:hover th {
background: var(--color-surface);
/* Keep the section's own background on hover — re-set in each
modifier below; this rule just disables the default row-hover
tint that the .pageXrayTable tr:hover rule would otherwise paint. */
}

.pageXrayTable .pageXraySection--content th { background: var(--color-info-bg); color: var(--color-info); }
.pageXrayTable .pageXraySection--blocking th { background: var(--color-warning-bg); color: var(--color-warning); }
.pageXrayTable .pageXraySection--visual th { background: #f3e8ff; color: #6b21a8; }
.pageXrayTable .pageXraySection--cwv th { background: var(--color-ok-bg); color: var(--color-ok); }
.pageXrayTable .pageXraySection--cpu th { background: #ffedd5; color: #9a3412; }
.pageXrayTable .pageXraySection--captures th { background: var(--color-surface); color: var(--color-text-muted); }

/* Repeat for hover so the bg doesn't snap to the row-hover tint. */
.pageXrayTable .pageXraySection--content:hover th { background: var(--color-info-bg); }
.pageXrayTable .pageXraySection--blocking:hover th { background: var(--color-warning-bg); }
.pageXrayTable .pageXraySection--visual:hover th { background: #f3e8ff; }
.pageXrayTable .pageXraySection--cwv:hover th { background: var(--color-ok-bg); }
.pageXrayTable .pageXraySection--cpu:hover th { background: #ffedd5; }
.pageXrayTable .pageXraySection--captures:hover th { background: var(--color-surface); }

.pageXrayTable {
table-layout: fixed;

Expand Down
Loading