Skip to content

Commit 0d5d6d0

Browse files
committed
rustdoc: avoid whole page layout on each frame
This makes two changes, based on experimenting with different browsers: - It debounces resizing the body text. This improves behavior on huge pages like struct.Vec.html, because it doesn't have to do layout. - It does the sidebar width updates directly on the sidebar instead of doing it on the `<HTML>` element. Doing it on `<HTML>` causes it to recalculate CSS for the entire document, also causing layout jank.
1 parent b46d43f commit 0d5d6d0

File tree

3 files changed

+67
-9
lines changed

3 files changed

+67
-9
lines changed

src/librustdoc/html/static/css/rustdoc.css

+14-4
Original file line numberDiff line numberDiff line change
@@ -389,12 +389,14 @@ img {
389389
.sidebar {
390390
font-size: 0.875rem;
391391
flex: 0 0 var(--desktop-sidebar-width);
392+
width: var(--desktop-sidebar-width);
392393
overflow-y: scroll;
393394
overscroll-behavior: contain;
394395
position: sticky;
395396
height: 100vh;
396397
top: 0;
397398
left: 0;
399+
z-index: 100;
398400
}
399401

400402
.rustdoc.src .sidebar {
@@ -403,7 +405,6 @@ img {
403405
overflow-x: hidden;
404406
/* The sidebar is by default hidden */
405407
overflow-y: hidden;
406-
z-index: 1;
407408
}
408409

409410
.hide-sidebar .sidebar,
@@ -415,8 +416,8 @@ img {
415416
touch-action: none;
416417
width: 9px;
417418
cursor: col-resize;
418-
z-index: 10;
419-
position: absolute;
419+
z-index: 200;
420+
position: fixed;
420421
height: 100%;
421422
/* make sure there's a 1px gap between the scrollbar and resize handle */
422423
left: calc(var(--desktop-sidebar-width) + 1px);
@@ -445,6 +446,14 @@ img {
445446
cursor: col-resize !important;
446447
}
447448

449+
.sidebar-resizing .sidebar {
450+
position: fixed;
451+
z-index: 100;
452+
}
453+
.sidebar-resizing > body {
454+
padding-left: var(--resizing-sidebar-width);
455+
}
456+
448457
.sidebar-resizer:hover,
449458
.sidebar-resizer:active,
450459
.sidebar-resizer:focus,
@@ -474,7 +483,7 @@ img {
474483

475484
.sidebar-resizer.active {
476485
/* make the resize tool bigger when actually resizing, to avoid :hover styles on other stuff
477-
while resizing */
486+
while resizing */
478487
padding: 0 140px;
479488
width: 2px;
480489
margin-left: -140px;
@@ -503,6 +512,7 @@ img {
503512
.src-sidebar-expanded .src .sidebar {
504513
overflow-y: auto;
505514
flex-basis: var(--src-sidebar-width);
515+
width: var(--src-sidebar-width);
506516
}
507517

508518
.src-sidebar-expanded .src .sidebar > *:not(#src-sidebar-toggle) {

src/librustdoc/html/static/js/main.js

+53-4
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,13 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
13371337
// it gets the sidebar to restore its size.
13381338
let desiredSidebarSize = null;
13391339

1340+
// Sidebar resize debouncer.
1341+
//
1342+
// The sidebar itself is resized instantly, but the body HTML can be too
1343+
// big for that, causing reflow jank. To reduce this, we queue up a separate
1344+
// animation frame and throttle it.
1345+
let pendingSidebarResizingFrame = false;
1346+
13401347
// If this page has no sidebar at all, bail out.
13411348
const resizer = document.querySelector(".sidebar-resizer");
13421349
const sidebar = document.querySelector(".sidebar");
@@ -1360,12 +1367,26 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
13601367
if (isSrcPage) {
13611368
window.rustdocCloseSourceSidebar();
13621369
updateLocalStorage("src-sidebar-width", null);
1370+
// [RUSTDOCIMPL] CSS variable fast path
1371+
//
1372+
// The sidebar width variable is attached to the <html> element by
1373+
// storage.js, because the sidebar and resizer don't exist yet.
1374+
// But the resize code, in `resize()`, sets the property on the
1375+
// sidebar and resizer elements (which are the only elements that
1376+
// use the variable) to avoid recalculating CSS on the entire
1377+
// document on every frame.
1378+
//
1379+
// So, to clear it, we need to clear all three.
13631380
document.documentElement.style.removeProperty("--src-sidebar-width");
1381+
sidebar.style.removeProperty("--src-sidebar-width");
1382+
resizer.style.removeProperty("--src-sidebar-width");
13641383
} else {
13651384
addClass(document.documentElement, "hide-sidebar");
13661385
updateLocalStorage("hide-sidebar", "true");
13671386
updateLocalStorage("desktop-sidebar-width", null);
13681387
document.documentElement.style.removeProperty("--desktop-sidebar-width");
1388+
sidebar.style.removeProperty("--desktop-sidebar-width");
1389+
resizer.style.removeProperty("--desktop-sidebar-width");
13691390
}
13701391
}
13711392

@@ -1384,15 +1405,27 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
13841405
}
13851406
}
13861407

1387-
// Call this to set the correct CSS variable and setting.
1388-
// This function doesn't enforce size constraints. Do that before calling it!
1408+
/**
1409+
* Call this to set the correct CSS variable and setting.
1410+
* This function doesn't enforce size constraints. Do that before calling it!
1411+
*
1412+
* @param {number} size - CSS px width of the sidebar.
1413+
*/
13891414
function changeSidebarSize(size) {
13901415
if (isSrcPage) {
13911416
updateLocalStorage("src-sidebar-width", size);
1392-
document.documentElement.style.setProperty("--src-sidebar-width", size + "px");
1417+
// [RUSTDOCIMPL] CSS variable fast path
1418+
//
1419+
// While this property is set on the HTML element at load time,
1420+
// because the sidebar isn't actually loaded yet,
1421+
// we scope this update to the sidebar to avoid hitting a slow
1422+
// path in WebKit.
1423+
sidebar.style.setProperty("--src-sidebar-width", size + "px");
1424+
resizer.style.setProperty("--src-sidebar-width", size + "px");
13931425
} else {
13941426
updateLocalStorage("desktop-sidebar-width", size);
1395-
document.documentElement.style.setProperty("--desktop-sidebar-width", size + "px");
1427+
sidebar.style.setProperty("--desktop-sidebar-width", size + "px");
1428+
resizer.style.setProperty("--desktop-sidebar-width", size + "px");
13961429
}
13971430
}
13981431

@@ -1424,6 +1457,19 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
14241457
const constrainedPos = Math.min(pos, window.innerWidth - BODY_MIN, SIDEBAR_MAX);
14251458
changeSidebarSize(constrainedPos);
14261459
desiredSidebarSize = constrainedPos;
1460+
if (pendingSidebarResizingFrame !== false) {
1461+
clearTimeout(pendingSidebarResizingFrame);
1462+
}
1463+
pendingSidebarResizingFrame = setTimeout(() => {
1464+
if (currentPointerId === null || pendingSidebarResizingFrame === false) {
1465+
return;
1466+
}
1467+
pendingSidebarResizingFrame = false;
1468+
document.documentElement.style.setProperty(
1469+
"--resizing-sidebar-width",
1470+
desiredSidebarSize + "px"
1471+
);
1472+
}, 100);
14271473
}
14281474
}
14291475
// Respond to the window resize event.
@@ -1447,6 +1493,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
14471493
window.removeEventListener("pointermove", resize, false);
14481494
window.removeEventListener("pointerup", stopResize, false);
14491495
removeClass(document.documentElement, "sidebar-resizing");
1496+
document.documentElement.style.removeProperty( "--resizing-sidebar-width");
14501497
if (resizer.releasePointerCapture) {
14511498
resizer.releasePointerCapture(currentPointerId);
14521499
currentPointerId = null;
@@ -1472,6 +1519,8 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
14721519
window.addEventListener("pointerup", stopResize, false);
14731520
addClass(resizer, "active");
14741521
addClass(document.documentElement, "sidebar-resizing");
1522+
const pos = e.clientX - sidebar.offsetLeft - 3;
1523+
document.documentElement.style.setProperty( "--resizing-sidebar-width", pos + "px");
14751524
desiredSidebarSize = null;
14761525
}
14771526
resizer.addEventListener("pointerdown", initResize, false);

src/librustdoc/html/static_files.rs

-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ static_files! {
100100
storage_js => "static/js/storage.js",
101101
scrape_examples_js => "static/js/scrape-examples.js",
102102
wheel_svg => "static/images/wheel.svg",
103-
sidebar_svg => "static/images/sidebar.svg",
104103
clipboard_svg => "static/images/clipboard.svg",
105104
copyright => "static/COPYRIGHT.txt",
106105
license_apache => "static/LICENSE-APACHE.txt",

0 commit comments

Comments
 (0)