about summary refs log tree commit diff
path: root/src/librustdoc/html/static
diff options
context:
space:
mode:
authorMichael Howell <michael@notriddle.com>2023-10-07 11:10:36 -0700
committerMichael Howell <michael@notriddle.com>2023-10-11 10:28:54 -0700
commit77fa09d9a1ddc7f99b0cda10c26688fe6f2b5519 (patch)
treeb76927e6c8a1fd0388c574ff7dd2bdca289a4bf0 /src/librustdoc/html/static
parent9aabfd589251b62dacf83b201df122d98b933c45 (diff)
downloadrust-77fa09d9a1ddc7f99b0cda10c26688fe6f2b5519.tar.gz
rust-77fa09d9a1ddc7f99b0cda10c26688fe6f2b5519.zip
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.
Diffstat (limited to 'src/librustdoc/html/static')
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css18
-rw-r--r--src/librustdoc/html/static/js/main.js57
2 files changed, 67 insertions, 8 deletions
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index d978d5bcb75..c66425dfa9b 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -389,12 +389,14 @@ img {
 .sidebar {
 	font-size: 0.875rem;
 	flex: 0 0 var(--desktop-sidebar-width);
+	width: var(--desktop-sidebar-width);
 	overflow-y: scroll;
 	overscroll-behavior: contain;
 	position: sticky;
 	height: 100vh;
 	top: 0;
 	left: 0;
+	z-index: 100;
 }
 
 .rustdoc.src .sidebar {
@@ -403,7 +405,6 @@ img {
 	overflow-x: hidden;
 	/* The sidebar is by default hidden  */
 	overflow-y: hidden;
-	z-index: 1;
 }
 
 .hide-sidebar .sidebar,
@@ -415,8 +416,8 @@ img {
 	touch-action: none;
 	width: 9px;
 	cursor: col-resize;
-	z-index: 10;
-	position: absolute;
+	z-index: 200;
+	position: fixed;
 	height: 100%;
 	/* make sure there's a 1px gap between the scrollbar and resize handle */
 	left: calc(var(--desktop-sidebar-width) + 1px);
@@ -445,6 +446,14 @@ img {
 	cursor: col-resize !important;
 }
 
+.sidebar-resizing .sidebar {
+	position: fixed;
+	z-index: 100;
+}
+.sidebar-resizing > body {
+	padding-left: var(--resizing-sidebar-width);
+}
+
 .sidebar-resizer:hover,
 .sidebar-resizer:active,
 .sidebar-resizer:focus,
@@ -474,7 +483,7 @@ img {
 
 .sidebar-resizer.active {
 	/* make the resize tool bigger when actually resizing, to avoid :hover styles on other stuff
-	   while resizing */
+		while resizing */
 	padding: 0 140px;
 	width: 2px;
 	margin-left: -140px;
@@ -503,6 +512,7 @@ img {
 .src-sidebar-expanded .src .sidebar {
 	overflow-y: auto;
 	flex-basis: var(--src-sidebar-width);
+	width: var(--src-sidebar-width);
 }
 
 .src-sidebar-expanded .src .sidebar > *:not(#src-sidebar-toggle) {
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index e1d674e7d04..be314317209 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -1337,6 +1337,13 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
     // it gets the sidebar to restore its size.
     let desiredSidebarSize = null;
 
+    // Sidebar resize debouncer.
+    //
+    // The sidebar itself is resized instantly, but the body HTML can be too
+    // big for that, causing reflow jank. To reduce this, we queue up a separate
+    // animation frame and throttle it.
+    let pendingSidebarResizingFrame = false;
+
     // If this page has no sidebar at all, bail out.
     const resizer = document.querySelector(".sidebar-resizer");
     const sidebar = document.querySelector(".sidebar");
@@ -1360,12 +1367,26 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
         if (isSrcPage) {
             window.rustdocCloseSourceSidebar();
             updateLocalStorage("src-sidebar-width", null);
+            // [RUSTDOCIMPL] CSS variable fast path
+            //
+            // The sidebar width variable is attached to the <html> element by
+            // storage.js, because the sidebar and resizer don't exist yet.
+            // But the resize code, in `resize()`, sets the property on the
+            // sidebar and resizer elements (which are the only elements that
+            // use the variable) to avoid recalculating CSS on the entire
+            // document on every frame.
+            //
+            // So, to clear it, we need to clear all three.
             document.documentElement.style.removeProperty("--src-sidebar-width");
+            sidebar.style.removeProperty("--src-sidebar-width");
+            resizer.style.removeProperty("--src-sidebar-width");
         } else {
             addClass(document.documentElement, "hide-sidebar");
             updateLocalStorage("hide-sidebar", "true");
             updateLocalStorage("desktop-sidebar-width", null);
             document.documentElement.style.removeProperty("--desktop-sidebar-width");
+            sidebar.style.removeProperty("--desktop-sidebar-width");
+            resizer.style.removeProperty("--desktop-sidebar-width");
         }
     }
 
@@ -1384,15 +1405,27 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
         }
     }
 
-    // Call this to set the correct CSS variable and setting.
-    // This function doesn't enforce size constraints. Do that before calling it!
+    /**
+     * Call this to set the correct CSS variable and setting.
+     * This function doesn't enforce size constraints. Do that before calling it!
+     *
+     * @param {number} size - CSS px width of the sidebar.
+     */
     function changeSidebarSize(size) {
         if (isSrcPage) {
             updateLocalStorage("src-sidebar-width", size);
-            document.documentElement.style.setProperty("--src-sidebar-width", size + "px");
+            // [RUSTDOCIMPL] CSS variable fast path
+            //
+            // While this property is set on the HTML element at load time,
+            // because the sidebar isn't actually loaded yet,
+            // we scope this update to the sidebar to avoid hitting a slow
+            // path in WebKit.
+            sidebar.style.setProperty("--src-sidebar-width", size + "px");
+            resizer.style.setProperty("--src-sidebar-width", size + "px");
         } else {
             updateLocalStorage("desktop-sidebar-width", size);
-            document.documentElement.style.setProperty("--desktop-sidebar-width", size + "px");
+            sidebar.style.setProperty("--desktop-sidebar-width", size + "px");
+            resizer.style.setProperty("--desktop-sidebar-width", size + "px");
         }
     }
 
@@ -1424,6 +1457,19 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
             const constrainedPos = Math.min(pos, window.innerWidth - BODY_MIN, SIDEBAR_MAX);
             changeSidebarSize(constrainedPos);
             desiredSidebarSize = constrainedPos;
+            if (pendingSidebarResizingFrame !== false) {
+                clearTimeout(pendingSidebarResizingFrame);
+            }
+            pendingSidebarResizingFrame = setTimeout(() => {
+                if (currentPointerId === null || pendingSidebarResizingFrame === false) {
+                    return;
+                }
+                pendingSidebarResizingFrame = false;
+                document.documentElement.style.setProperty(
+                    "--resizing-sidebar-width",
+                    desiredSidebarSize + "px"
+                );
+            }, 100);
         }
     }
     // Respond to the window resize event.
@@ -1447,6 +1493,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
         window.removeEventListener("pointermove", resize, false);
         window.removeEventListener("pointerup", stopResize, false);
         removeClass(document.documentElement, "sidebar-resizing");
+        document.documentElement.style.removeProperty( "--resizing-sidebar-width");
         if (resizer.releasePointerCapture) {
             resizer.releasePointerCapture(currentPointerId);
             currentPointerId = null;
@@ -1472,6 +1519,8 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
         window.addEventListener("pointerup", stopResize, false);
         addClass(resizer, "active");
         addClass(document.documentElement, "sidebar-resizing");
+        const pos = e.clientX - sidebar.offsetLeft - 3;
+        document.documentElement.style.setProperty( "--resizing-sidebar-width", pos + "px");
         desiredSidebarSize = null;
     }
     resizer.addEventListener("pointerdown", initResize, false);