about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Howell <michael@notriddle.com>2023-09-13 15:08:45 -0700
committerMichael Howell <michael@notriddle.com>2023-09-15 07:40:17 -0700
commit7e86fd61e83717fc23b6141d2ba728aefbe5e168 (patch)
treef7000c35bcea979c3ad564f488dbdb6c97842486
parentcbccf800b85541187b3a8a17359c94c802e99748 (diff)
downloadrust-7e86fd61e83717fc23b6141d2ba728aefbe5e168.tar.gz
rust-7e86fd61e83717fc23b6141d2ba728aefbe5e168.zip
rustdoc: merge theme css into rustdoc.css
Based on
https://github.com/rust-lang/rust/pull/115812#issuecomment-1717960119

Having them in separate files used to make more sense, before the
migration to CSS variables made the theme files as small as they are
nowadays. This is already how docs.rs and mdBook do it.
-rw-r--r--src/bootstrap/test.rs2
-rw-r--r--src/librustdoc/config.rs24
-rw-r--r--src/librustdoc/html/render/context.rs15
-rw-r--r--src/librustdoc/html/static/css/noscript.css213
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css410
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css181
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css102
-rw-r--r--src/librustdoc/html/static/css/themes/light.css99
-rw-r--r--src/librustdoc/html/static/js/main.js3
-rw-r--r--src/librustdoc/html/static/js/storage.js26
-rw-r--r--src/librustdoc/html/static_files.rs3
-rw-r--r--src/librustdoc/html/templates/page.html9
-rw-r--r--src/librustdoc/lib.rs4
-rw-r--r--src/librustdoc/theme.rs3
-rw-r--r--src/librustdoc/theme/tests.rs2
-rw-r--r--src/tools/rustdoc-themes/main.rs44
-rw-r--r--src/tools/tidy/src/lib.rs1
-rw-r--r--src/tools/tidy/src/main.rs1
-rw-r--r--src/tools/tidy/src/rustdoc_css_themes.rs99
-rw-r--r--tests/run-make/issue-88756-default-output/output-default.stdout2
-rw-r--r--tests/run-make/rustdoc-themes/Makefile3
21 files changed, 798 insertions, 448 deletions
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 35e2e98e08e..96611ca873a 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -846,7 +846,7 @@ impl Step for RustdocTheme {
         let rustdoc = builder.bootstrap_out.join("rustdoc");
         let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
         cmd.arg(rustdoc.to_str().unwrap())
-            .arg(builder.src.join("src/librustdoc/html/static/css/themes").to_str().unwrap())
+            .arg(builder.src.join("src/librustdoc/html/static/css/rustdoc.css").to_str().unwrap())
             .env("RUSTC_STAGE", self.compiler.stage.to_string())
             .env("RUSTC_SYSROOT", builder.sysroot(self.compiler))
             .env("RUSTDOC_LIBDIR", builder.sysroot_libdir(self.compiler, self.compiler.host))
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 974dc1c5135..99aa979027f 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -410,9 +410,15 @@ impl Options {
 
         let to_check = matches.opt_strs("check-theme");
         if !to_check.is_empty() {
-            let paths = match theme::load_css_paths(
-                std::str::from_utf8(static_files::STATIC_FILES.theme_light_css.bytes).unwrap(),
-            ) {
+            let mut content =
+                std::str::from_utf8(static_files::STATIC_FILES.rustdoc_css.bytes).unwrap();
+            if let Some((_, inside)) = content.split_once("/* Begin theme: light */") {
+                content = inside;
+            }
+            if let Some((inside, _)) = content.split_once("/* End theme: light */") {
+                content = inside;
+            }
+            let paths = match theme::load_css_paths(content) {
                 Ok(p) => p,
                 Err(e) => {
                     diag.struct_err(e).emit();
@@ -550,9 +556,15 @@ impl Options {
 
         let mut themes = Vec::new();
         if matches.opt_present("theme") {
-            let paths = match theme::load_css_paths(
-                std::str::from_utf8(static_files::STATIC_FILES.theme_light_css.bytes).unwrap(),
-            ) {
+            let mut content =
+                std::str::from_utf8(static_files::STATIC_FILES.rustdoc_css.bytes).unwrap();
+            if let Some((_, inside)) = content.split_once("/* Begin theme: light */") {
+                content = inside;
+            }
+            if let Some((inside, _)) = content.split_once("/* End theme: light */") {
+                content = inside;
+            }
+            let paths = match theme::load_css_paths(content) {
                 Ok(p) => p,
                 Err(e) => {
                     diag.struct_err(e).emit();
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 736b6d7ebfa..97714afaa45 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -107,8 +107,8 @@ pub(crate) struct SharedContext<'tcx> {
     pub(super) module_sorting: ModuleSorting,
     /// Additional CSS files to be added to the generated docs.
     pub(crate) style_files: Vec<StylePath>,
-    /// Suffix to be added on resource files (if suffix is "-v2" then "light.css" becomes
-    /// "light-v2.css").
+    /// Suffix to add on resource files (if suffix is "-v2" then "search-index.js" becomes
+    /// "search-index-v2.js").
     pub(crate) resource_suffix: String,
     /// Optional path string to be used to load static files on output pages. If not set, uses
     /// combinations of `../` to reach the documentation root.
@@ -714,18 +714,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
                             You need to enable JavaScript be able to update your settings.\
                         </section>\
                      </noscript>\
-                     <script defer src=\"{static_root_path}{settings_js}\"></script>\
-                     <link rel=\"preload\" href=\"{static_root_path}{theme_light_css}\" \
-                         as=\"style\">\
-                     <link rel=\"preload\" href=\"{static_root_path}{theme_dark_css}\" \
-                         as=\"style\">\
-                     <link rel=\"preload\" href=\"{static_root_path}{theme_ayu_css}\" \
-                         as=\"style\">",
+                     <script defer src=\"{static_root_path}{settings_js}\"></script>",
                     static_root_path = page.get_static_root_path(),
                     settings_js = static_files::STATIC_FILES.settings_js,
-                    theme_light_css = static_files::STATIC_FILES.theme_light_css,
-                    theme_dark_css = static_files::STATIC_FILES.theme_dark_css,
-                    theme_ayu_css = static_files::STATIC_FILES.theme_ayu_css,
                 );
                 // Pre-load all theme CSS files, so that switching feels seamless.
                 //
diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css
index 93aa11a5852..fe0cf6dc8cc 100644
--- a/src/librustdoc/html/static/css/noscript.css
+++ b/src/librustdoc/html/static/css/noscript.css
@@ -28,3 +28,216 @@ nav.sub {
 	    https://github.com/rust-lang/rust/issues/102576 */
 	display: none;
 }
+
+/* Begin: styles for themes
+	Keep the default light and dark themes synchronized with the ones
+	in rustdoc.css */
+
+/* Begin theme: light */
+:root {
+	--main-background-color: white;
+	--main-color: black;
+	--settings-input-color: #2196f3;
+	--settings-input-border-color: #717171;
+	--settings-button-color: #000;
+	--settings-button-border-focus: #717171;
+	--sidebar-background-color: #f5f5f5;
+	--sidebar-background-color-hover: #e0e0e0;
+	--code-block-background-color: #f5f5f5;
+	--scrollbar-track-background-color: #dcdcdc;
+	--scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
+	--scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
+	--headings-border-bottom-color: #ddd;
+	--border-color: #e0e0e0;
+	--button-background-color: #fff;
+	--right-side-color: grey;
+	--code-attribute-color: #999;
+	--toggles-color: #999;
+	--toggle-filter: none;
+	--search-input-focused-border-color: #66afe9;
+	--copy-path-button-color: #999;
+	--copy-path-img-filter: invert(50%);
+	--copy-path-img-hover-filter: invert(35%);
+	--codeblock-error-hover-color: rgb(255, 0, 0);
+	--codeblock-error-color: rgba(255, 0, 0, .5);
+	--codeblock-ignore-hover-color: rgb(255, 142, 0);
+	--codeblock-ignore-color: rgba(255, 142, 0, .6);
+	--warning-border-color: #ff8e00;
+	--type-link-color: #ad378a;
+	--trait-link-color: #6e4fc9;
+	--assoc-item-link-color: #3873ad;
+	--function-link-color: #ad7c37;
+	--macro-link-color: #068000;
+	--keyword-link-color: #3873ad;
+	--mod-link-color: #3873ad;
+	--link-color: #3873ad;
+	--sidebar-link-color: #356da4;
+	--sidebar-current-link-background-color: #fff;
+	--search-result-link-focus-background-color: #ccc;
+	--search-result-border-color: #aaa3;
+	--search-color: #000;
+	--search-error-code-background-color: #d0cccc;
+	--search-results-alias-color: #000;
+	--search-results-grey-color: #999;
+	--search-tab-title-count-color: #888;
+	--search-tab-button-not-selected-border-top-color: #e6e6e6;
+	--search-tab-button-not-selected-background: #e6e6e6;
+	--search-tab-button-selected-border-top-color: #0089ff;
+	--search-tab-button-selected-background: #fff;
+	--stab-background-color: #fff5d6;
+	--stab-code-color: #000;
+	--code-highlight-kw-color: #8959a8;
+	--code-highlight-kw-2-color: #4271ae;
+	--code-highlight-lifetime-color: #b76514;
+	--code-highlight-prelude-color: #4271ae;
+	--code-highlight-prelude-val-color: #c82829;
+	--code-highlight-number-color: #718c00;
+	--code-highlight-string-color: #718c00;
+	--code-highlight-literal-color: #c82829;
+	--code-highlight-attribute-color: #c82829;
+	--code-highlight-self-color: #c82829;
+	--code-highlight-macro-color: #3e999f;
+	--code-highlight-question-mark-color: #ff9011;
+	--code-highlight-comment-color: #8e908c;
+	--code-highlight-doc-comment-color: #4d4d4c;
+	--src-line-numbers-span-color: #c67e2d;
+	--src-line-number-highlighted-background-color: #fdffd3;
+	--test-arrow-color: #f5f5f5;
+	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
+	--test-arrow-hover-color: #f5f5f5;
+	--test-arrow-hover-background-color: rgb(78, 139, 202);
+	--target-background-color: #fdffd3;
+	--target-border-color: #ad7c37;
+	--kbd-color: #000;
+	--kbd-background: #fafbfc;
+	--kbd-box-shadow-color: #c6cbd1;
+	--rust-logo-filter: initial;
+	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+	--crate-search-div-filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg)
+		brightness(114%) contrast(76%);
+	--crate-search-div-hover-filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg)
+		brightness(96%) contrast(93%);
+	--crate-search-hover-border: #717171;
+	--src-sidebar-background-selected: #fff;
+	--src-sidebar-background-hover: #e0e0e0;
+	--table-alt-row-background-color: #f5f5f5;
+	--codeblock-link-background: #eee;
+	--scrape-example-toggle-line-background: #ccc;
+	--scrape-example-toggle-line-hover-background: #999;
+	--scrape-example-code-line-highlight: #fcffd6;
+	--scrape-example-code-line-highlight-focus: #f6fdb0;
+	--scrape-example-help-border-color: #555;
+	--scrape-example-help-color: #333;
+	--scrape-example-help-hover-border-color: #000;
+	--scrape-example-help-hover-color: #000;
+	--scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1);
+	--scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
+}
+/* End theme: light */
+
+@media (prefers-color-scheme: dark) {
+	/* Begin theme: dark */
+	:root {
+		--main-background-color: #353535;
+		--main-color: #ddd;
+		--settings-input-color: #2196f3;
+		--settings-input-border-color: #999;
+		--settings-button-color: #000;
+		--settings-button-border-focus: #ffb900;
+		--sidebar-background-color: #505050;
+		--sidebar-background-color-hover: #676767;
+		--code-block-background-color: #2A2A2A;
+		--scrollbar-track-background-color: #717171;
+		--scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
+		--scrollbar-color: rgba(32,34,37,.6) #5a5a5a;
+		--headings-border-bottom-color: #d2d2d2;
+		--border-color: #e0e0e0;
+		--button-background-color: #f0f0f0;
+		--right-side-color: grey;
+		--code-attribute-color: #999;
+		--toggles-color: #999;
+		--toggle-filter: invert(100%);
+		--search-input-focused-border-color: #008dfd;
+		--copy-path-button-color: #999;
+		--copy-path-img-filter: invert(50%);
+		--copy-path-img-hover-filter: invert(65%);
+		--codeblock-error-hover-color: rgb(255, 0, 0);
+		--codeblock-error-color: rgba(255, 0, 0, .5);
+		--codeblock-ignore-hover-color: rgb(255, 142, 0);
+		--codeblock-ignore-color: rgba(255, 142, 0, .6);
+		--warning-border-color: #ff8e00;
+		--type-link-color: #2dbfb8;
+		--trait-link-color: #b78cf2;
+		--assoc-item-link-color: #d2991d;
+		--function-link-color: #2bab63;
+		--macro-link-color: #09bd00;
+		--keyword-link-color: #d2991d;
+		--mod-link-color:  #d2991d;
+		--link-color: #d2991d;
+		--sidebar-link-color: #fdbf35;
+		--sidebar-current-link-background-color: #444;
+		--search-result-link-focus-background-color: #616161;
+		--search-result-border-color: #aaa3;
+		--search-color: #111;
+		--search-error-code-background-color: #484848;
+		--search-results-alias-color: #fff;
+		--search-results-grey-color: #ccc;
+		--search-tab-title-count-color: #888;
+		--search-tab-button-not-selected-border-top-color: #252525;
+		--search-tab-button-not-selected-background: #252525;
+		--search-tab-button-selected-border-top-color: #0089ff;
+		--search-tab-button-selected-background: #353535;
+		--stab-background-color: #314559;
+		--stab-code-color: #e6e1cf;
+		--code-highlight-kw-color: #ab8ac1;
+		--code-highlight-kw-2-color: #769acb;
+		--code-highlight-lifetime-color: #d97f26;
+		--code-highlight-prelude-color: #769acb;
+		--code-highlight-prelude-val-color: #ee6868;
+		--code-highlight-number-color: #83a300;
+		--code-highlight-string-color: #83a300;
+		--code-highlight-literal-color: #ee6868;
+		--code-highlight-attribute-color: #ee6868;
+		--code-highlight-self-color: #ee6868;
+		--code-highlight-macro-color: #3e999f;
+		--code-highlight-question-mark-color: #ff9011;
+		--code-highlight-comment-color: #8d8d8b;
+		--code-highlight-doc-comment-color: #8ca375;
+		--src-line-numbers-span-color: #3b91e2;
+		--src-line-number-highlighted-background-color: #0a042f;
+		--test-arrow-color: #dedede;
+		--test-arrow-background-color: rgba(78, 139, 202, 0.2);
+		--test-arrow-hover-color: #dedede;
+		--test-arrow-hover-background-color: #4e8bca;
+		--target-background-color: #494a3d;
+		--target-border-color: #bb7410;
+		--kbd-color: #000;
+		--kbd-background: #fafbfc;
+		--kbd-box-shadow-color: #c6cbd1;
+		--rust-logo-filter: drop-shadow(1px 0 0px #fff)
+			drop-shadow(0 1px 0 #fff)
+			drop-shadow(-1px 0 0 #fff)
+			drop-shadow(0 -1px 0 #fff);
+		/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+		--crate-search-div-filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg)
+			brightness(90%) contrast(90%);
+		--crate-search-div-hover-filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg)
+			brightness(100%) contrast(91%);
+		--crate-search-hover-border: #2196f3;
+		--src-sidebar-background-selected: #333;
+		--src-sidebar-background-hover: #444;
+		--table-alt-row-background-color: #2a2a2a;
+		--codeblock-link-background: #333;
+		--scrape-example-toggle-line-background: #999;
+		--scrape-example-toggle-line-hover-background: #c5c5c5;
+		--scrape-example-code-line-highlight: #5b3b01;
+		--scrape-example-code-line-highlight-focus: #7c4b0f;
+		--scrape-example-help-border-color: #aaa;
+		--scrape-example-help-color: #eee;
+		--scrape-example-help-hover-border-color: #fff;
+		--scrape-example-help-hover-color: #fff;
+		--scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1);
+		--scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
+	}
+/* End theme: dark */
+}
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 84123f4e9d3..3b236641337 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -2098,3 +2098,413 @@ in src-script.js
 }
 
 /* End: styles for --scrape-examples feature */
+
+/* Begin: styles for themes
+
+	Keep the default light and dark themes synchronized with the ones
+	in noscript.css
+
+	The special "Begin theme" and "End theme" below are used by a lot of
+	tooling to ensure different themes all define all the variables. Do not
+	alter their formatting. */
+
+/* Begin theme: light */
+:root[data-theme="light"] {
+	--main-background-color: white;
+	--main-color: black;
+	--settings-input-color: #2196f3;
+	--settings-input-border-color: #717171;
+	--settings-button-color: #000;
+	--settings-button-border-focus: #717171;
+	--sidebar-background-color: #f5f5f5;
+	--sidebar-background-color-hover: #e0e0e0;
+	--code-block-background-color: #f5f5f5;
+	--scrollbar-track-background-color: #dcdcdc;
+	--scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
+	--scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
+	--headings-border-bottom-color: #ddd;
+	--border-color: #e0e0e0;
+	--button-background-color: #fff;
+	--right-side-color: grey;
+	--code-attribute-color: #999;
+	--toggles-color: #999;
+	--toggle-filter: none;
+	--search-input-focused-border-color: #66afe9;
+	--copy-path-button-color: #999;
+	--copy-path-img-filter: invert(50%);
+	--copy-path-img-hover-filter: invert(35%);
+	--codeblock-error-hover-color: rgb(255, 0, 0);
+	--codeblock-error-color: rgba(255, 0, 0, .5);
+	--codeblock-ignore-hover-color: rgb(255, 142, 0);
+	--codeblock-ignore-color: rgba(255, 142, 0, .6);
+	--warning-border-color: #ff8e00;
+	--type-link-color: #ad378a;
+	--trait-link-color: #6e4fc9;
+	--assoc-item-link-color: #3873ad;
+	--function-link-color: #ad7c37;
+	--macro-link-color: #068000;
+	--keyword-link-color: #3873ad;
+	--mod-link-color: #3873ad;
+	--link-color: #3873ad;
+	--sidebar-link-color: #356da4;
+	--sidebar-current-link-background-color: #fff;
+	--search-result-link-focus-background-color: #ccc;
+	--search-result-border-color: #aaa3;
+	--search-color: #000;
+	--search-error-code-background-color: #d0cccc;
+	--search-results-alias-color: #000;
+	--search-results-grey-color: #999;
+	--search-tab-title-count-color: #888;
+	--search-tab-button-not-selected-border-top-color: #e6e6e6;
+	--search-tab-button-not-selected-background: #e6e6e6;
+	--search-tab-button-selected-border-top-color: #0089ff;
+	--search-tab-button-selected-background: #fff;
+	--stab-background-color: #fff5d6;
+	--stab-code-color: #000;
+	--code-highlight-kw-color: #8959a8;
+	--code-highlight-kw-2-color: #4271ae;
+	--code-highlight-lifetime-color: #b76514;
+	--code-highlight-prelude-color: #4271ae;
+	--code-highlight-prelude-val-color: #c82829;
+	--code-highlight-number-color: #718c00;
+	--code-highlight-string-color: #718c00;
+	--code-highlight-literal-color: #c82829;
+	--code-highlight-attribute-color: #c82829;
+	--code-highlight-self-color: #c82829;
+	--code-highlight-macro-color: #3e999f;
+	--code-highlight-question-mark-color: #ff9011;
+	--code-highlight-comment-color: #8e908c;
+	--code-highlight-doc-comment-color: #4d4d4c;
+	--src-line-numbers-span-color: #c67e2d;
+	--src-line-number-highlighted-background-color: #fdffd3;
+	--test-arrow-color: #f5f5f5;
+	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
+	--test-arrow-hover-color: #f5f5f5;
+	--test-arrow-hover-background-color: rgb(78, 139, 202);
+	--target-background-color: #fdffd3;
+	--target-border-color: #ad7c37;
+	--kbd-color: #000;
+	--kbd-background: #fafbfc;
+	--kbd-box-shadow-color: #c6cbd1;
+	--rust-logo-filter: initial;
+	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+	--crate-search-div-filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg)
+		brightness(114%) contrast(76%);
+	--crate-search-div-hover-filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg)
+		brightness(96%) contrast(93%);
+	--crate-search-hover-border: #717171;
+	--src-sidebar-background-selected: #fff;
+	--src-sidebar-background-hover: #e0e0e0;
+	--table-alt-row-background-color: #f5f5f5;
+	--codeblock-link-background: #eee;
+	--scrape-example-toggle-line-background: #ccc;
+	--scrape-example-toggle-line-hover-background: #999;
+	--scrape-example-code-line-highlight: #fcffd6;
+	--scrape-example-code-line-highlight-focus: #f6fdb0;
+	--scrape-example-help-border-color: #555;
+	--scrape-example-help-color: #333;
+	--scrape-example-help-hover-border-color: #000;
+	--scrape-example-help-hover-color: #000;
+	--scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1);
+	--scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
+}
+/* End theme: light */
+
+/* Begin theme: dark */
+:root[data-theme="dark"] {
+	--main-background-color: #353535;
+	--main-color: #ddd;
+	--settings-input-color: #2196f3;
+	--settings-input-border-color: #999;
+	--settings-button-color: #000;
+	--settings-button-border-focus: #ffb900;
+	--sidebar-background-color: #505050;
+	--sidebar-background-color-hover: #676767;
+	--code-block-background-color: #2A2A2A;
+	--scrollbar-track-background-color: #717171;
+	--scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
+	--scrollbar-color: rgba(32,34,37,.6) #5a5a5a;
+	--headings-border-bottom-color: #d2d2d2;
+	--border-color: #e0e0e0;
+	--button-background-color: #f0f0f0;
+	--right-side-color: grey;
+	--code-attribute-color: #999;
+	--toggles-color: #999;
+	--toggle-filter: invert(100%);
+	--search-input-focused-border-color: #008dfd;
+	--copy-path-button-color: #999;
+	--copy-path-img-filter: invert(50%);
+	--copy-path-img-hover-filter: invert(65%);
+	--codeblock-error-hover-color: rgb(255, 0, 0);
+	--codeblock-error-color: rgba(255, 0, 0, .5);
+	--codeblock-ignore-hover-color: rgb(255, 142, 0);
+	--codeblock-ignore-color: rgba(255, 142, 0, .6);
+	--warning-border-color: #ff8e00;
+	--type-link-color: #2dbfb8;
+	--trait-link-color: #b78cf2;
+	--assoc-item-link-color: #d2991d;
+	--function-link-color: #2bab63;
+	--macro-link-color: #09bd00;
+	--keyword-link-color: #d2991d;
+	--mod-link-color:  #d2991d;
+	--link-color: #d2991d;
+	--sidebar-link-color: #fdbf35;
+	--sidebar-current-link-background-color: #444;
+	--search-result-link-focus-background-color: #616161;
+	--search-result-border-color: #aaa3;
+	--search-color: #111;
+	--search-error-code-background-color: #484848;
+	--search-results-alias-color: #fff;
+	--search-results-grey-color: #ccc;
+	--search-tab-title-count-color: #888;
+	--search-tab-button-not-selected-border-top-color: #252525;
+	--search-tab-button-not-selected-background: #252525;
+	--search-tab-button-selected-border-top-color: #0089ff;
+	--search-tab-button-selected-background: #353535;
+	--stab-background-color: #314559;
+	--stab-code-color: #e6e1cf;
+	--code-highlight-kw-color: #ab8ac1;
+	--code-highlight-kw-2-color: #769acb;
+	--code-highlight-lifetime-color: #d97f26;
+	--code-highlight-prelude-color: #769acb;
+	--code-highlight-prelude-val-color: #ee6868;
+	--code-highlight-number-color: #83a300;
+	--code-highlight-string-color: #83a300;
+	--code-highlight-literal-color: #ee6868;
+	--code-highlight-attribute-color: #ee6868;
+	--code-highlight-self-color: #ee6868;
+	--code-highlight-macro-color: #3e999f;
+	--code-highlight-question-mark-color: #ff9011;
+	--code-highlight-comment-color: #8d8d8b;
+	--code-highlight-doc-comment-color: #8ca375;
+	--src-line-numbers-span-color: #3b91e2;
+	--src-line-number-highlighted-background-color: #0a042f;
+	--test-arrow-color: #dedede;
+	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
+	--test-arrow-hover-color: #dedede;
+	--test-arrow-hover-background-color: #4e8bca;
+	--target-background-color: #494a3d;
+	--target-border-color: #bb7410;
+	--kbd-color: #000;
+	--kbd-background: #fafbfc;
+	--kbd-box-shadow-color: #c6cbd1;
+	--rust-logo-filter: drop-shadow(1px 0 0px #fff)
+		drop-shadow(0 1px 0 #fff)
+		drop-shadow(-1px 0 0 #fff)
+		drop-shadow(0 -1px 0 #fff);
+	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+	--crate-search-div-filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg)
+		brightness(90%) contrast(90%);
+	--crate-search-div-hover-filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg)
+		brightness(100%) contrast(91%);
+	--crate-search-hover-border: #2196f3;
+	--src-sidebar-background-selected: #333;
+	--src-sidebar-background-hover: #444;
+	--table-alt-row-background-color: #2a2a2a;
+	--codeblock-link-background: #333;
+	--scrape-example-toggle-line-background: #999;
+	--scrape-example-toggle-line-hover-background: #c5c5c5;
+	--scrape-example-code-line-highlight: #5b3b01;
+	--scrape-example-code-line-highlight-focus: #7c4b0f;
+	--scrape-example-help-border-color: #aaa;
+	--scrape-example-help-color: #eee;
+	--scrape-example-help-hover-border-color: #fff;
+	--scrape-example-help-hover-color: #fff;
+	--scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1);
+	--scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
+}
+/* End theme: dark */
+
+/* Begin theme: ayu */
+/*
+Based off of the Ayu theme
+Original by Dempfi (https://github.com/dempfi/ayu)
+*/
+:root[data-theme="ayu"] {
+	--main-background-color: #0f1419;
+	--main-color: #c5c5c5;
+	--settings-input-color: #ffb454;
+	--settings-input-border-color: #999;
+	--settings-button-color: #fff;
+	--settings-button-border-focus: #e0e0e0;
+	--sidebar-background-color: #14191f;
+	--sidebar-background-color-hover: rgba(70, 70, 70, 0.33);
+	--code-block-background-color: #191f26;
+	--scrollbar-track-background-color: transparent;
+	--scrollbar-thumb-background-color: #5c6773;
+	--scrollbar-color: #5c6773 #24292f;
+	--headings-border-bottom-color: #5c6773;
+	--border-color: #5c6773;
+	--button-background-color: #141920;
+	--right-side-color: grey;
+	--code-attribute-color: #999;
+	--toggles-color: #999;
+	--toggle-filter: invert(100%);
+	--search-input-focused-border-color: #5c6773; /* Same as `--border-color`. */
+	--copy-path-button-color: #fff;
+	--copy-path-img-filter: invert(70%);
+	--copy-path-img-hover-filter: invert(100%);
+	--codeblock-error-hover-color: rgb(255, 0, 0);
+	--codeblock-error-color: rgba(255, 0, 0, .5);
+	--codeblock-ignore-hover-color: rgb(255, 142, 0);
+	--codeblock-ignore-color: rgba(255, 142, 0, .6);
+	--warning-border-color: #ff8e00;
+	--type-link-color: #ffa0a5;
+	--trait-link-color: #39afd7;
+	--assoc-item-link-color: #39afd7;
+	--function-link-color: #fdd687;
+	--macro-link-color: #a37acc;
+	--keyword-link-color: #39afd7;
+	--mod-link-color: #39afd7;
+	--link-color: #39afd7;
+	--sidebar-link-color: #53b1db;
+	--sidebar-current-link-background-color: transparent;
+	--search-result-link-focus-background-color: #3c3c3c;
+	--search-result-border-color: #aaa3;
+	--search-color: #fff;
+	--search-error-code-background-color: #4f4c4c;
+	--search-results-alias-color: #c5c5c5;
+	--search-results-grey-color: #999;
+	--search-tab-title-count-color: #888;
+	--search-tab-button-not-selected-border-top-color: none;
+	--search-tab-button-not-selected-background: transparent !important;
+	--search-tab-button-selected-border-top-color: none;
+	--search-tab-button-selected-background: #141920 !important;
+	--stab-background-color: #314559;
+	--stab-code-color: #e6e1cf;
+	--code-highlight-kw-color: #ff7733;
+	--code-highlight-kw-2-color: #ff7733;
+	--code-highlight-lifetime-color: #ff7733;
+	--code-highlight-prelude-color: #69f2df;
+	--code-highlight-prelude-val-color: #ff7733;
+	--code-highlight-number-color: #b8cc52;
+	--code-highlight-string-color: #b8cc52;
+	--code-highlight-literal-color: #ff7733;
+	--code-highlight-attribute-color: #e6e1cf;
+	--code-highlight-self-color: #36a3d9;
+	--code-highlight-macro-color: #a37acc;
+	--code-highlight-question-mark-color: #ff9011;
+	--code-highlight-comment-color: #788797;
+	--code-highlight-doc-comment-color: #a1ac88;
+	--src-line-numbers-span-color: #5c6773;
+	--src-line-number-highlighted-background-color: rgba(255, 236, 164, 0.06);
+	--test-arrow-color: #788797;
+	--test-arrow-background-color: rgba(57, 175, 215, 0.09);
+	--test-arrow-hover-color: #c5c5c5;
+	--test-arrow-hover-background-color: rgba(57, 175, 215, 0.368);
+	--target-background-color: rgba(255, 236, 164, 0.06);
+	--target-border-color: rgba(255, 180, 76, 0.85);
+	--kbd-color: #c5c5c5;
+	--kbd-background: #314559;
+	--kbd-box-shadow-color: #5c6773;
+	--rust-logo-filter: drop-shadow(1px 0 0px #fff)
+		drop-shadow(0 1px 0 #fff)
+		drop-shadow(-1px 0 0 #fff)
+		drop-shadow(0 -1px 0 #fff);
+	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+	--crate-search-div-filter: invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg)
+		brightness(94%) contrast(94%);
+	--crate-search-div-hover-filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg)
+		brightness(113%) contrast(76%);
+	--crate-search-hover-border: #e0e0e0;
+	--src-sidebar-background-selected: #14191f;
+	--src-sidebar-background-hover: #14191f;
+	--table-alt-row-background-color: #191f26;
+	--codeblock-link-background: #333;
+	--scrape-example-toggle-line-background: #999;
+	--scrape-example-toggle-line-hover-background: #c5c5c5;
+	--scrape-example-code-line-highlight: #5b3b01;
+	--scrape-example-code-line-highlight-focus: #7c4b0f;
+	--scrape-example-help-border-color: #aaa;
+	--scrape-example-help-color: #eee;
+	--scrape-example-help-hover-border-color: #fff;
+	--scrape-example-help-hover-color: #fff;
+	--scrape-example-code-wrapper-background-start: rgba(15, 20, 25, 1);
+	--scrape-example-code-wrapper-background-end: rgba(15, 20, 25, 0);
+}
+
+:root[data-theme="ayu"] h1,
+:root[data-theme="ayu"] h2,
+:root[data-theme="ayu"] h3,
+:root[data-theme="ayu"] h4,
+:where(:root[data-theme="ayu"]) h1 a,
+:root[data-theme="ayu"] .sidebar h2 a,
+:root[data-theme="ayu"] .sidebar h3 a,
+:root[data-theme="ayu"] #source-sidebar > .title {
+	color: #fff;
+}
+
+:root[data-theme="ayu"] .docblock code {
+	color: #ffb454;
+}
+
+:root[data-theme="ayu"] .docblock a > code {
+	color: #39AFD7 !important;
+}
+
+:root[data-theme="ayu"] .code-header,
+:root[data-theme="ayu"] .docblock pre > code,
+:root[data-theme="ayu"] pre,
+:root[data-theme="ayu"] pre > code,
+:root[data-theme="ayu"] .item-info code,
+:root[data-theme="ayu"] .rustdoc.source .example-wrap {
+	color: #e6e1cf;
+}
+
+:root[data-theme="ayu"] .sidebar .current,
+:root[data-theme="ayu"] .sidebar a:hover,
+:root[data-theme="ayu"] #src-sidebar div.files > a:hover,
+:root[data-theme="ayu"] details.dir-entry summary:hover,
+:root[data-theme="ayu"] #src-sidebar div.files > a:focus,
+:root[data-theme="ayu"] details.dir-entry summary:focus,
+:root[data-theme="ayu"] #src-sidebar div.files > a.selected {
+	color: #ffb44c;
+}
+
+:root[data-theme="ayu"] .sidebar-elems .location {
+	color: #ff7733;
+}
+
+:root[data-theme="ayu"] .src-line-numbers .line-highlighted {
+	color: #708090;
+	padding-right: 7px;
+	border-right: 1px solid #ffb44c;
+}
+
+:root[data-theme="ayu"] .search-results a:hover,
+:root[data-theme="ayu"] .search-results a:focus {
+	color: #fff !important;
+	background-color: #3c3c3c;
+}
+
+:root[data-theme="ayu"] .search-results a {
+	color: #0096cf;
+}
+
+:root[data-theme="ayu"] .search-results a div.desc {
+	color: #c5c5c5;
+}
+
+:root[data-theme="ayu"] .result-name .primitive > i,
+:root[data-theme="ayu"] .result-name .keyword > i {
+	color: #788797;
+}
+
+:root[data-theme="ayu"] #search-tabs > button.selected {
+	border-bottom: 1px solid #ffb44c !important;
+	border-top: none;
+}
+:root[data-theme="ayu"] #search-tabs > button:not(.selected) {
+	border: none;
+	background-color: transparent !important;
+}
+:root[data-theme="ayu"] #search-tabs > button:hover {
+	border-bottom: 1px solid rgba(242, 151, 24, 0.3);
+}
+
+:root[data-theme="ayu"] #settings-menu > a img {
+	filter: invert(100);
+}
+/* End theme: ayu */
+
+/* End: styles for themes */
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
deleted file mode 100644
index 873a1668f8b..00000000000
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
-Based off of the Ayu theme
-Original by Dempfi (https://github.com/dempfi/ayu)
-*/
-
-:root {
-	--main-background-color: #0f1419;
-	--main-color: #c5c5c5;
-	--settings-input-color: #ffb454;
-	--settings-input-border-color: #999;
-	--settings-button-color: #fff;
-	--settings-button-border-focus: #e0e0e0;
-	--sidebar-background-color: #14191f;
-	--sidebar-background-color-hover: rgba(70, 70, 70, 0.33);
-	--code-block-background-color: #191f26;
-	--scrollbar-track-background-color: transparent;
-	--scrollbar-thumb-background-color: #5c6773;
-	--scrollbar-color: #5c6773 #24292f;
-	--headings-border-bottom-color: #5c6773;
-	--border-color: #5c6773;
-	--button-background-color: #141920;
-	--right-side-color: grey;
-	--code-attribute-color: #999;
-	--toggles-color: #999;
-	--toggle-filter: invert(100%);
-	--search-input-focused-border-color: #5c6773; /* Same as `--border-color`. */
-	--copy-path-button-color: #fff;
-	--copy-path-img-filter: invert(70%);
-	--copy-path-img-hover-filter: invert(100%);
-	--codeblock-error-hover-color: rgb(255, 0, 0);
-	--codeblock-error-color: rgba(255, 0, 0, .5);
-	--codeblock-ignore-hover-color: rgb(255, 142, 0);
-	--codeblock-ignore-color: rgba(255, 142, 0, .6);
-	--warning-border-color: #ff8e00;
-	--type-link-color: #ffa0a5;
-	--trait-link-color: #39afd7;
-	--assoc-item-link-color: #39afd7;
-	--function-link-color: #fdd687;
-	--macro-link-color: #a37acc;
-	--keyword-link-color: #39afd7;
-	--mod-link-color: #39afd7;
-	--link-color: #39afd7;
-	--sidebar-link-color: #53b1db;
-	--sidebar-current-link-background-color: transparent;
-	--search-result-link-focus-background-color: #3c3c3c;
-	--search-result-border-color: #aaa3;
-	--search-color: #fff;
-	--search-error-code-background-color: #4f4c4c;
-	--search-results-alias-color: #c5c5c5;
-	--search-results-grey-color: #999;
-	--search-tab-title-count-color: #888;
-	--search-tab-button-not-selected-border-top-color: none;
-	--search-tab-button-not-selected-background: transparent !important;
-	--search-tab-button-selected-border-top-color: none;
-	--search-tab-button-selected-background: #141920 !important;
-	--stab-background-color: #314559;
-	--stab-code-color: #e6e1cf;
-	--code-highlight-kw-color: #ff7733;
-	--code-highlight-kw-2-color: #ff7733;
-	--code-highlight-lifetime-color: #ff7733;
-	--code-highlight-prelude-color: #69f2df;
-	--code-highlight-prelude-val-color: #ff7733;
-	--code-highlight-number-color: #b8cc52;
-	--code-highlight-string-color: #b8cc52;
-	--code-highlight-literal-color: #ff7733;
-	--code-highlight-attribute-color: #e6e1cf;
-	--code-highlight-self-color: #36a3d9;
-	--code-highlight-macro-color: #a37acc;
-	--code-highlight-question-mark-color: #ff9011;
-	--code-highlight-comment-color: #788797;
-	--code-highlight-doc-comment-color: #a1ac88;
-	--src-line-numbers-span-color: #5c6773;
-	--src-line-number-highlighted-background-color: rgba(255, 236, 164, 0.06);
-	--test-arrow-color: #788797;
-	--test-arrow-background-color: rgba(57, 175, 215, 0.09);
-	--test-arrow-hover-color: #c5c5c5;
-	--test-arrow-hover-background-color: rgba(57, 175, 215, 0.368);
-	--target-background-color: rgba(255, 236, 164, 0.06);
-	--target-border-color: rgba(255, 180, 76, 0.85);
-	--kbd-color: #c5c5c5;
-	--kbd-background: #314559;
-	--kbd-box-shadow-color: #5c6773;
-	--rust-logo-filter: drop-shadow(1px 0 0px #fff)
-		drop-shadow(0 1px 0 #fff)
-		drop-shadow(-1px 0 0 #fff)
-		drop-shadow(0 -1px 0 #fff);
-	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
-	--crate-search-div-filter: invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg)
-		brightness(94%) contrast(94%);
-	--crate-search-div-hover-filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg)
-		brightness(113%) contrast(76%);
-	--crate-search-hover-border: #e0e0e0;
-	--src-sidebar-background-selected: #14191f;
-	--src-sidebar-background-hover: #14191f;
-	--table-alt-row-background-color: #191f26;
-	--codeblock-link-background: #333;
-	--scrape-example-toggle-line-background: #999;
-	--scrape-example-toggle-line-hover-background: #c5c5c5;
-	--scrape-example-code-line-highlight: #5b3b01;
-	--scrape-example-code-line-highlight-focus: #7c4b0f;
-	--scrape-example-help-border-color: #aaa;
-	--scrape-example-help-color: #eee;
-	--scrape-example-help-hover-border-color: #fff;
-	--scrape-example-help-hover-color: #fff;
-	--scrape-example-code-wrapper-background-start: rgba(15, 20, 25, 1);
-	--scrape-example-code-wrapper-background-end: rgba(15, 20, 25, 0);
-}
-
-h1, h2, h3, h4,
-h1 a, .sidebar h2 a, .sidebar h3 a,
-#src-sidebar > .title {
-	color: #fff;
-}
-h4 {
-	border: none;
-}
-
-.docblock code {
-	color: #ffb454;
-}
-.docblock a > code {
-	color: #39AFD7 !important;
-}
-.code-header,
-.docblock pre > code,
-pre, pre > code,
-.item-info code,
-.rustdoc.src .example-wrap {
-	color: #e6e1cf;
-}
-
-.sidebar .current,
-.sidebar a:hover,
-#src-sidebar div.files > a:hover, details.dir-entry summary:hover,
-#src-sidebar div.files > a:focus, details.dir-entry summary:focus,
-#src-sidebar div.files > a.selected {
-	color: #ffb44c;
-}
-
-.sidebar-elems .location {
-	color: #ff7733;
-}
-
-.src-line-numbers .line-highlighted {
-	color: #708090;
-	padding-right: 7px;
-	border-right: 1px solid #ffb44c;
-}
-
-.search-results a:hover,
-.search-results a:focus {
-	color: #fff !important;
-	background-color: #3c3c3c;
-}
-
-.search-results a {
-	color: #0096cf;
-}
-.search-results a div.desc {
-	color: #c5c5c5;
-}
-
-.result-name .primitive > i, .result-name .keyword > i {
-	color: #788797;
-}
-
-#search-tabs > button.selected {
-	border-bottom: 1px solid #ffb44c !important;
-	border-top: none;
-}
-#search-tabs > button:not(.selected) {
-	border: none;
-	background-color: transparent !important;
-}
-#search-tabs > button:hover {
-	border-bottom: 1px solid rgba(242, 151, 24, 0.3);
-}
-
-#settings-menu > a img {
-	filter: invert(100);
-}
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
deleted file mode 100644
index 2b6e28d35a5..00000000000
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ /dev/null
@@ -1,102 +0,0 @@
-:root {
-	--main-background-color: #353535;
-	--main-color: #ddd;
-	--settings-input-color: #2196f3;
-	--settings-input-border-color: #999;
-	--settings-button-color: #000;
-	--settings-button-border-focus: #ffb900;
-	--sidebar-background-color: #505050;
-	--sidebar-background-color-hover: #676767;
-	--code-block-background-color: #2A2A2A;
-	--scrollbar-track-background-color: #717171;
-	--scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
-	--scrollbar-color: rgba(32,34,37,.6) #5a5a5a;
-	--headings-border-bottom-color: #d2d2d2;
-	--border-color: #e0e0e0;
-	--button-background-color: #f0f0f0;
-	--right-side-color: grey;
-	--code-attribute-color: #999;
-	--toggles-color: #999;
-	--toggle-filter: invert(100%);
-	--search-input-focused-border-color: #008dfd;
-	--copy-path-button-color: #999;
-	--copy-path-img-filter: invert(50%);
-	--copy-path-img-hover-filter: invert(65%);
-	--codeblock-error-hover-color: rgb(255, 0, 0);
-	--codeblock-error-color: rgba(255, 0, 0, .5);
-	--codeblock-ignore-hover-color: rgb(255, 142, 0);
-	--codeblock-ignore-color: rgba(255, 142, 0, .6);
-	--warning-border-color: #ff8e00;
-	--type-link-color: #2dbfb8;
-	--trait-link-color: #b78cf2;
-	--assoc-item-link-color: #d2991d;
-	--function-link-color: #2bab63;
-	--macro-link-color: #09bd00;
-	--keyword-link-color: #d2991d;
-	--mod-link-color:  #d2991d;
-	--link-color: #d2991d;
-	--sidebar-link-color: #fdbf35;
-	--sidebar-current-link-background-color: #444;
-	--search-result-link-focus-background-color: #616161;
-	--search-result-border-color: #aaa3;
-	--search-color: #111;
-	--search-error-code-background-color: #484848;
-	--search-results-alias-color: #fff;
-	--search-results-grey-color: #ccc;
-	--search-tab-title-count-color: #888;
-	--search-tab-button-not-selected-border-top-color: #252525;
-	--search-tab-button-not-selected-background: #252525;
-	--search-tab-button-selected-border-top-color: #0089ff;
-	--search-tab-button-selected-background: #353535;
-	--stab-background-color: #314559;
-	--stab-code-color: #e6e1cf;
-	--code-highlight-kw-color: #ab8ac1;
-	--code-highlight-kw-2-color: #769acb;
-	--code-highlight-lifetime-color: #d97f26;
-	--code-highlight-prelude-color: #769acb;
-	--code-highlight-prelude-val-color: #ee6868;
-	--code-highlight-number-color: #83a300;
-	--code-highlight-string-color: #83a300;
-	--code-highlight-literal-color: #ee6868;
-	--code-highlight-attribute-color: #ee6868;
-	--code-highlight-self-color: #ee6868;
-	--code-highlight-macro-color: #3e999f;
-	--code-highlight-question-mark-color: #ff9011;
-	--code-highlight-comment-color: #8d8d8b;
-	--code-highlight-doc-comment-color: #8ca375;
-	--src-line-numbers-span-color: #3b91e2;
-	--src-line-number-highlighted-background-color: #0a042f;
-	--test-arrow-color: #dedede;
-	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
-	--test-arrow-hover-color: #dedede;
-	--test-arrow-hover-background-color: #4e8bca;
-	--target-background-color: #494a3d;
-	--target-border-color: #bb7410;
-	--kbd-color: #000;
-	--kbd-background: #fafbfc;
-	--kbd-box-shadow-color: #c6cbd1;
-	--rust-logo-filter: drop-shadow(1px 0 0px #fff)
-		drop-shadow(0 1px 0 #fff)
-		drop-shadow(-1px 0 0 #fff)
-		drop-shadow(0 -1px 0 #fff);
-	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
-	--crate-search-div-filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg)
-		brightness(90%) contrast(90%);
-	--crate-search-div-hover-filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg)
-		brightness(100%) contrast(91%);
-	--crate-search-hover-border: #2196f3;
-	--src-sidebar-background-selected: #333;
-	--src-sidebar-background-hover: #444;
-	--table-alt-row-background-color: #2a2a2a;
-	--codeblock-link-background: #333;
-	--scrape-example-toggle-line-background: #999;
-	--scrape-example-toggle-line-hover-background: #c5c5c5;
-	--scrape-example-code-line-highlight: #5b3b01;
-	--scrape-example-code-line-highlight-focus: #7c4b0f;
-	--scrape-example-help-border-color: #aaa;
-	--scrape-example-help-color: #eee;
-	--scrape-example-help-hover-border-color: #fff;
-	--scrape-example-help-hover-color: #fff;
-	--scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1);
-	--scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
-}
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
deleted file mode 100644
index 9c016db4502..00000000000
--- a/src/librustdoc/html/static/css/themes/light.css
+++ /dev/null
@@ -1,99 +0,0 @@
-:root {
-	--main-background-color: white;
-	--main-color: black;
-	--settings-input-color: #2196f3;
-	--settings-input-border-color: #717171;
-	--settings-button-color: #000;
-	--settings-button-border-focus: #717171;
-	--sidebar-background-color: #f5f5f5;
-	--sidebar-background-color-hover: #e0e0e0;
-	--code-block-background-color: #f5f5f5;
-	--scrollbar-track-background-color: #dcdcdc;
-	--scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
-	--scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
-	--headings-border-bottom-color: #ddd;
-	--border-color: #e0e0e0;
-	--button-background-color: #fff;
-	--right-side-color: grey;
-	--code-attribute-color: #999;
-	--toggles-color: #999;
-	--toggle-filter: none;
-	--search-input-focused-border-color: #66afe9;
-	--copy-path-button-color: #999;
-	--copy-path-img-filter: invert(50%);
-	--copy-path-img-hover-filter: invert(35%);
-	--codeblock-error-hover-color: rgb(255, 0, 0);
-	--codeblock-error-color: rgba(255, 0, 0, .5);
-	--codeblock-ignore-hover-color: rgb(255, 142, 0);
-	--codeblock-ignore-color: rgba(255, 142, 0, .6);
-	--warning-border-color: #ff8e00;
-	--type-link-color: #ad378a;
-	--trait-link-color: #6e4fc9;
-	--assoc-item-link-color: #3873ad;
-	--function-link-color: #ad7c37;
-	--macro-link-color: #068000;
-	--keyword-link-color: #3873ad;
-	--mod-link-color: #3873ad;
-	--link-color: #3873ad;
-	--sidebar-link-color: #356da4;
-	--sidebar-current-link-background-color: #fff;
-	--search-result-link-focus-background-color: #ccc;
-	--search-result-border-color: #aaa3;
-	--search-color: #000;
-	--search-error-code-background-color: #d0cccc;
-	--search-results-alias-color: #000;
-	--search-results-grey-color: #999;
-	--search-tab-title-count-color: #888;
-	--search-tab-button-not-selected-border-top-color: #e6e6e6;
-	--search-tab-button-not-selected-background: #e6e6e6;
-	--search-tab-button-selected-border-top-color: #0089ff;
-	--search-tab-button-selected-background: #fff;
-	--stab-background-color: #fff5d6;
-	--stab-code-color: #000;
-	--code-highlight-kw-color: #8959a8;
-	--code-highlight-kw-2-color: #4271ae;
-	--code-highlight-lifetime-color: #b76514;
-	--code-highlight-prelude-color: #4271ae;
-	--code-highlight-prelude-val-color: #c82829;
-	--code-highlight-number-color: #718c00;
-	--code-highlight-string-color: #718c00;
-	--code-highlight-literal-color: #c82829;
-	--code-highlight-attribute-color: #c82829;
-	--code-highlight-self-color: #c82829;
-	--code-highlight-macro-color: #3e999f;
-	--code-highlight-question-mark-color: #ff9011;
-	--code-highlight-comment-color: #8e908c;
-	--code-highlight-doc-comment-color: #4d4d4c;
-	--src-line-numbers-span-color: #c67e2d;
-	--src-line-number-highlighted-background-color: #fdffd3;
-	--test-arrow-color: #f5f5f5;
-	--test-arrow-background-color: rgba(78, 139, 202, 0.2);
-	--test-arrow-hover-color: #f5f5f5;
-	--test-arrow-hover-background-color: rgb(78, 139, 202);
-	--target-background-color: #fdffd3;
-	--target-border-color: #ad7c37;
-	--kbd-color: #000;
-	--kbd-background: #fafbfc;
-	--kbd-box-shadow-color: #c6cbd1;
-	--rust-logo-filter: initial;
-	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
-	--crate-search-div-filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg)
-		brightness(114%) contrast(76%);
-	--crate-search-div-hover-filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg)
-		brightness(96%) contrast(93%);
-	--crate-search-hover-border: #717171;
-	--src-sidebar-background-selected: #fff;
-	--src-sidebar-background-hover: #e0e0e0;
-	--table-alt-row-background-color: #f5f5f5;
-	--codeblock-link-background: #eee;
-	--scrape-example-toggle-line-background: #ccc;
-	--scrape-example-toggle-line-hover-background: #999;
-	--scrape-example-code-line-highlight: #fcffd6;
-	--scrape-example-code-line-highlight-focus: #f6fdb0;
-	--scrape-example-help-border-color: #555;
-	--scrape-example-help-color: #333;
-	--scrape-example-help-hover-border-color: #000;
-	--scrape-example-help-hover-color: #000;
-	--scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1);
-	--scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
-}
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 822d22946b4..097aa0b940d 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -204,9 +204,6 @@ function preLoadCss(cssUrl) {
         // Sending request for the CSS and the JS files at the same time so it will
         // hopefully be loaded when the JS will generate the settings content.
         loadScript(getVar("static-root-path") + getVar("settings-js"));
-        preLoadCss(getVar("static-root-path") + getVar("theme-light-css"));
-        preLoadCss(getVar("static-root-path") + getVar("theme-dark-css"));
-        preLoadCss(getVar("static-root-path") + getVar("theme-ayu-css"));
         // Pre-load all theme CSS files, so that switching feels seamless.
         //
         // When loading settings.html as a standalone page, the equivalent HTML is
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index af3ca42a6c0..ec34f5e8bf9 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -5,6 +5,7 @@
 // the page, so we don't see major layout changes during the load of the page.
 "use strict";
 
+const builtinThemes = ["light", "dark", "ayu"];
 const darkThemes = ["dark", "ayu"];
 window.currentTheme = document.getElementById("themeStyle");
 
@@ -119,19 +120,22 @@ function switchTheme(newThemeName, saveTheme) {
         updateLocalStorage("theme", newThemeName);
     }
 
-    let newHref;
+    document.documentElement.setAttribute("data-theme", newThemeName);
 
-    if (newThemeName === "light" || newThemeName === "dark" || newThemeName === "ayu") {
-        newHref = getVar("static-root-path") + getVar("theme-" + newThemeName + "-css");
+    if (builtinThemes.indexOf(newThemeName) !== -1) {
+        if (window.currentTheme) {
+            window.currentTheme.parentNode.removeChild(window.currentTheme);
+            window.currentTheme = null;
+        }
     } else {
-        newHref = getVar("root-path") + newThemeName + getVar("resource-suffix") + ".css";
-    }
-
-    if (!window.currentTheme) {
-        document.write(`<link rel="stylesheet" id="themeStyle" href="${newHref}">`);
-        window.currentTheme = document.getElementById("themeStyle");
-    } else if (newHref !== window.currentTheme.href) {
-        window.currentTheme.href = newHref;
+        const newHref = getVar("root-path") + newThemeName +
+            getVar("resource-suffix") + ".css";
+        if (!window.currentTheme) {
+            document.write(`<link rel="stylesheet" id="themeStyle" href="${newHref}">`);
+            window.currentTheme = document.getElementById("themeStyle");
+        } else if (newHref !== window.currentTheme.href) {
+            window.currentTheme.href = newHref;
+        }
     }
 }
 
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index 7742646f81a..ca9a78f51b3 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -108,9 +108,6 @@ static_files! {
     rust_favicon_svg => "static/images/favicon.svg",
     rust_favicon_png_16 => "static/images/favicon-16x16.png",
     rust_favicon_png_32 => "static/images/favicon-32x32.png",
-    theme_light_css => "static/css/themes/light.css",
-    theme_dark_css => "static/css/themes/dark.css",
-    theme_ayu_css => "static/css/themes/ayu.css",
     fira_sans_regular => "static/fonts/FiraSans-Regular.woff2",
     fira_sans_medium => "static/fonts/FiraSans-Medium.woff2",
     fira_sans_license => "static/fonts/FiraSans-LICENSE.txt",
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index ad63571c6d0..b4b9c319165 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -33,9 +33,6 @@
          data-channel="{{rust_channel}}" {#+ #}
          data-search-js="{{files.search_js}}" {#+ #}
          data-settings-js="{{files.settings_js}}" {#+ #}
-         data-theme-light-css="{{files.theme_light_css}}" {#+ #}
-         data-theme-dark-css="{{files.theme_dark_css}}" {#+ #}
-         data-theme-ayu-css="{{files.theme_ayu_css}}" {#+ #}
     > {# #}
     <script src="{{static_root_path|safe}}{{files.storage_js}}"></script> {# #}
     {% if page.css_class.contains("crate") %}
@@ -52,12 +49,6 @@
     {% endif %}
     <noscript> {# #}
         <link rel="stylesheet" {#+ #}
-           media="(prefers-color-scheme:light)" {#+ #}
-           href="{{static_root_path|safe}}{{files.theme_light_css}}"> {# #}
-        <link rel="stylesheet" {#+ #}
-           media="(prefers-color-scheme:dark)" {#+ #}
-           href="{{static_root_path|safe}}{{files.theme_dark_css}}"> {# #}
-        <link rel="stylesheet" {#+ #}
            href="{{static_root_path|safe}}{{files.noscript_css}}"> {# #}
     </noscript> {# #}
     {% if layout.css_file_extension.is_some() %}
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 92e06f3ab0f..2f88f6dc6e0 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -430,8 +430,8 @@ fn opts() -> Vec<RustcOptGroup> {
             o.optopt(
                 "",
                 "resource-suffix",
-                "suffix to add to CSS and JavaScript files, e.g., \"light.css\" will become \
-                 \"light-suffix.css\"",
+                "suffix to add to CSS and JavaScript files, e.g., \"search-index.js\" will \
+                 become \"search-index-suffix.js\"",
                 "PATH",
             )
         }),
diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs
index 722e01cd1fc..8c1acbd7347 100644
--- a/src/librustdoc/theme.rs
+++ b/src/librustdoc/theme.rs
@@ -185,6 +185,9 @@ pub(crate) fn parse_selectors(
     while let Some(c) = iter.next() {
         match c {
             '{' => {
+                if selector.trim().starts_with(":root[data-theme") {
+                    selector = String::from(":root");
+                }
                 let s = minifier::css::minify(selector.trim()).map(|s| s.to_string())?;
                 parse_rules(content, s, iter, paths)?;
                 selector.clear();
diff --git a/src/librustdoc/theme/tests.rs b/src/librustdoc/theme/tests.rs
index 2a28c19c3fe..56f40b8046d 100644
--- a/src/librustdoc/theme/tests.rs
+++ b/src/librustdoc/theme/tests.rs
@@ -100,7 +100,7 @@ fn check_invalid_css() {
 
 #[test]
 fn test_with_minification() {
-    let text = include_str!("../html/static/css/themes/dark.css");
+    let text = include_str!("../html/static/css/noscript.css");
     let minified = minifier::css::minify(&text).expect("CSS minification failed").to_string();
 
     let against = load_css_paths(text).unwrap();
diff --git a/src/tools/rustdoc-themes/main.rs b/src/tools/rustdoc-themes/main.rs
index 7cac985a9a3..cc13df1f5ba 100644
--- a/src/tools/rustdoc-themes/main.rs
+++ b/src/tools/rustdoc-themes/main.rs
@@ -1,25 +1,37 @@
 use std::env::args;
-use std::fs::read_dir;
+use std::fs::File;
+use std::io::{BufRead, BufReader, BufWriter, Write};
 use std::path::Path;
 use std::process::{exit, Command};
 
-const FILES_TO_IGNORE: &[&str] = &["light.css"];
-
-fn get_folders<P: AsRef<Path>>(folder_path: P) -> Vec<String> {
+fn get_themes<P: AsRef<Path>>(style_path: P) -> Vec<String> {
     let mut ret = Vec::with_capacity(10);
 
-    for entry in read_dir(folder_path.as_ref()).expect("read_dir failed") {
-        let entry = entry.expect("Couldn't unwrap entry");
-        let path = entry.path();
+    const BEGIN_THEME_MARKER: &'static str = "/* Begin theme: ";
+    const END_THEME_MARKER: &'static str = "/* End theme: ";
+
+    let timestamp =
+        std::time::SystemTime::UNIX_EPOCH.elapsed().expect("time is after UNIX epoch").as_millis();
 
-        if !path.is_file() {
-            continue;
+    let mut in_theme = None;
+    for line in BufReader::new(File::open(style_path).expect("read rustdoc.css failed")).lines() {
+        let line = line.expect("read line from rustdoc.css failed");
+        let line = line.trim();
+        if line.starts_with(BEGIN_THEME_MARKER) {
+            let theme_name = &line[BEGIN_THEME_MARKER.len()..].trim().trim_end_matches("*/").trim();
+            let filename = format!("build/tmp/rustdoc.bootstrap.{timestamp}.{theme_name}.css");
+            in_theme = Some(BufWriter::new(
+                File::create(&filename).expect("failed to create temporary test css file"),
+            ));
+            ret.push(filename);
+        }
+        if let Some(in_theme) = in_theme.as_mut() {
+            in_theme.write_all(line.as_bytes()).expect("write to temporary test css file");
+            in_theme.write_all(b"\n").expect("write to temporary test css file");
         }
-        let filename = path.file_name().expect("file_name failed");
-        if FILES_TO_IGNORE.iter().any(|x| x == &filename) {
-            continue;
+        if line.starts_with(END_THEME_MARKER) {
+            in_theme = None;
         }
-        ret.push(format!("{}", path.display()));
     }
     ret
 }
@@ -32,10 +44,10 @@ fn main() {
         exit(1);
     }
     let rustdoc_bin = &argv[1];
-    let themes_folder = &argv[2];
-    let themes = get_folders(&themes_folder);
+    let style_path = &argv[2];
+    let themes = get_themes(&style_path);
     if themes.is_empty() {
-        eprintln!("No theme found in \"{}\"...", themes_folder);
+        eprintln!("No themes found in \"{}\"...", style_path);
         exit(1);
     }
     let arg_name = "--check-theme".to_owned();
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 9b19b8eecc7..ca160017202 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -64,6 +64,7 @@ pub mod fluent_alphabetical;
 pub mod mir_opt_tests;
 pub mod pal;
 pub mod primitive_docs;
+pub mod rustdoc_css_themes;
 pub mod rustdoc_gui_tests;
 pub mod style;
 pub mod target_specific_tests;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 5fa91715a07..5585e125f2d 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -104,6 +104,7 @@ fn main() {
         check!(ui_tests, &tests_path);
         check!(mir_opt_tests, &tests_path, bless);
         check!(rustdoc_gui_tests, &tests_path);
+        check!(rustdoc_css_themes, &librustdoc_path);
 
         // Checks that only make sense for the compiler.
         check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose);
diff --git a/src/tools/tidy/src/rustdoc_css_themes.rs b/src/tools/tidy/src/rustdoc_css_themes.rs
new file mode 100644
index 00000000000..852d6e14e91
--- /dev/null
+++ b/src/tools/tidy/src/rustdoc_css_themes.rs
@@ -0,0 +1,99 @@
+//! Tidy check to make sure light and dark themes are synchronized between
+//! JS-controlled rustdoc.css and noscript.css
+
+use std::path::Path;
+
+pub fn check(librustdoc_path: &Path, bad: &mut bool) {
+    let rustdoc_css = "html/static/css/rustdoc.css";
+    let noscript_css = "html/static/css/noscript.css";
+    let rustdoc_css_contents = std::fs::read_to_string(librustdoc_path.join(rustdoc_css))
+        .unwrap_or_else(|e| panic!("failed to read librustdoc/{rustdoc_css}: {e}"));
+    let noscript_css_contents = std::fs::read_to_string(librustdoc_path.join(noscript_css))
+        .unwrap_or_else(|e| panic!("failed to read librustdoc/{noscript_css}: {e}"));
+    compare_themes_from_files(
+        "light",
+        rustdoc_css_contents.lines().enumerate().map(|(i, l)| (i + 1, l.trim())),
+        noscript_css_contents.lines().enumerate().map(|(i, l)| (i + 1, l.trim())),
+        bad,
+    );
+    compare_themes_from_files(
+        "dark",
+        rustdoc_css_contents.lines().enumerate(),
+        noscript_css_contents.lines().enumerate(),
+        bad,
+    );
+}
+
+fn compare_themes_from_files<'a>(
+    name: &str,
+    mut rustdoc_css_lines: impl Iterator<Item = (usize, &'a str)>,
+    mut noscript_css_lines: impl Iterator<Item = (usize, &'a str)>,
+    bad: &mut bool,
+) {
+    let begin_theme_pat = format!("/* Begin theme: {name}");
+    let mut found_theme = None;
+    let mut found_theme_noscript = None;
+    while let Some((rustdoc_css_line_number, rustdoc_css_line)) = rustdoc_css_lines.next() {
+        if !rustdoc_css_line.starts_with(&begin_theme_pat) {
+            continue;
+        }
+        if let Some(found_theme) = found_theme {
+            tidy_error!(
+                bad,
+                "rustdoc.css contains two {name} themes on lines {rustdoc_css_line_number} and {found_theme}",
+            );
+            return;
+        }
+        found_theme = Some(rustdoc_css_line_number);
+        while let Some((noscript_css_line_number, noscript_css_line)) = noscript_css_lines.next() {
+            if !noscript_css_line.starts_with(&begin_theme_pat) {
+                continue;
+            }
+            if let Some(found_theme_noscript) = found_theme_noscript {
+                tidy_error!(
+                    bad,
+                    "noscript.css contains two {name} themes on lines {noscript_css_line_number} and {found_theme_noscript}",
+                );
+                return;
+            }
+            found_theme_noscript = Some(noscript_css_line_number);
+            compare_themes(name, &mut rustdoc_css_lines, &mut noscript_css_lines, bad);
+        }
+    }
+}
+
+fn compare_themes<'a>(
+    name: &str,
+    rustdoc_css_lines: impl Iterator<Item = (usize, &'a str)>,
+    noscript_css_lines: impl Iterator<Item = (usize, &'a str)>,
+    bad: &mut bool,
+) {
+    let end_theme_pat = format!("/* End theme: {name}");
+    for (
+        (rustdoc_css_line_number, rustdoc_css_line),
+        (noscript_css_line_number, noscript_css_line),
+    ) in rustdoc_css_lines.zip(noscript_css_lines)
+    {
+        if noscript_css_line.starts_with(":root {")
+            && rustdoc_css_line.starts_with(&format!(r#":root[data-theme="{name}"] {{"#))
+        {
+            // selectors are different between rustdoc.css and noscript.css
+            // that's why they both exist: one uses JS, the other uses media queries
+            continue;
+        }
+        if noscript_css_line.starts_with(&end_theme_pat)
+            && rustdoc_css_line.starts_with(&end_theme_pat)
+        {
+            break;
+        }
+        if rustdoc_css_line != noscript_css_line {
+            tidy_error!(
+                bad,
+                "noscript.css:{noscript_css_line_number} and rustdoc.css:{rustdoc_css_line_number} contain copies of {name} theme that are not the same",
+            );
+            eprintln!("- {noscript_css_line}");
+            eprintln!("+ {rustdoc_css_line}");
+            return;
+        }
+    }
+}
diff --git a/tests/run-make/issue-88756-default-output/output-default.stdout b/tests/run-make/issue-88756-default-output/output-default.stdout
index de8ff0e5f89..f5981045b03 100644
--- a/tests/run-make/issue-88756-default-output/output-default.stdout
+++ b/tests/run-make/issue-88756-default-output/output-default.stdout
@@ -100,7 +100,7 @@ Options:
                         check if given theme is valid
         --resource-suffix PATH
                         suffix to add to CSS and JavaScript files, e.g.,
-                        "light.css" will become "light-suffix.css"
+                        "search-index.js" will become "search-index-suffix.js"
         --edition EDITION
                         edition to use when compiling rust code (default:
                         2015)
diff --git a/tests/run-make/rustdoc-themes/Makefile b/tests/run-make/rustdoc-themes/Makefile
index a6d9a43addf..a4980eb0b3e 100644
--- a/tests/run-make/rustdoc-themes/Makefile
+++ b/tests/run-make/rustdoc-themes/Makefile
@@ -5,6 +5,7 @@ include ../tools.mk
 OUTPUT_DIR := "$(TMPDIR)/rustdoc-themes"
 
 all:
-	cp $(S)/src/librustdoc/html/static/css/themes/light.css $(TMPDIR)/test.css
+	awk '/Begin theme: light/ {in_theme=1;next} /End theme:/ {in_theme=0} { if (in_theme) print }' \
+		< '$(S)/src/librustdoc/html/static/css/noscript.css' > '$(TMPDIR)/test.css'
 	$(RUSTDOC) -o $(OUTPUT_DIR) foo.rs --theme $(TMPDIR)/test.css
 	$(HTMLDOCCK) $(OUTPUT_DIR) foo.rs