Skip to content

Commit ed2a442

Browse files
committed
drustdoc: add three-column layout for large desktops
This commit adds a floating TOC box to the right, leaving the sibling/module/crate navigation on the left. This kicks in at a size a little below 1920x1080, where desktops with very wide monitors are: it's also around the point where the content area can be full width while allowing two sidebars. It only kicks in if the browser supports grid layouts, but that should be most of them, and we can't get rid of the two-column layout anyway, since it's the layout you get on something like a portrait iPad. This design, where it can be used, is meant to clearly split up the table of contents and the site navigation, so the right side floating box has the same color as the page while the left sidebar does not. It also pushes it down further, so that it's not as high as the search bar, though that's a bit more subtle than the color.
1 parent d7e17c4 commit ed2a442

File tree

9 files changed

+205
-72
lines changed

9 files changed

+205
-72
lines changed

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

+122-8
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\
3434
</g></svg>');
3535
--button-left-margin: 4px;
3636
--button-border-radius: 2px;
37+
--width-limiter-width: 960px;
38+
--desktop-grid-column-gap: 45px;
3739
}
3840

3941
/* See FiraSans-LICENSE.txt for the Fira Sans license. */
@@ -336,7 +338,7 @@ button#toggle-all-docs {
336338
main {
337339
position: relative;
338340
flex-grow: 1;
339-
padding: 10px 15px 40px 45px;
341+
padding: 10px 15px 40px var(--desktop-grid-column-gap);
340342
min-width: 0; /* avoid growing beyond the size limit */
341343
}
342344

@@ -345,7 +347,7 @@ main {
345347
}
346348

347349
.width-limiter {
348-
max-width: 960px;
350+
max-width: var(--width-limiter-width);
349351
margin-right: auto;
350352
}
351353

@@ -460,7 +462,7 @@ img {
460462
.sidebar-resizing .sidebar {
461463
position: fixed;
462464
}
463-
.sidebar-resizing > body {
465+
.sidebar-resizing .rustdoc {
464466
padding-left: var(--resizing-sidebar-width);
465467
}
466468

@@ -534,7 +536,7 @@ img {
534536
scrollbar-width: initial;
535537
scrollbar-color: var(--scrollbar-color);
536538
}
537-
.sidebar {
539+
.sidebar, #TOC section, #ModNav section {
538540
scrollbar-width: thin;
539541
scrollbar-color: var(--scrollbar-color);
540542
}
@@ -543,17 +545,24 @@ img {
543545
::-webkit-scrollbar {
544546
width: 12px;
545547
}
546-
.sidebar::-webkit-scrollbar {
548+
.sidebar::-webkit-scrollbar,
549+
#TOC section::-webkit-scrollbar,
550+
#ModNav section::-webkit-scrollbar {
547551
width: 8px;
548552
}
549553
::-webkit-scrollbar-track {
550554
-webkit-box-shadow: inset 0;
551555
background-color: var(--scrollbar-track-background-color);
552556
}
553-
.sidebar::-webkit-scrollbar-track {
557+
.sidebar::-webkit-scrollbar-track,
558+
#TOC section::-webkit-scrollbar-track,
559+
#ModNav section::-webkit-scrollbar-track {
554560
background-color: var(--scrollbar-track-background-color);
555561
}
556-
::-webkit-scrollbar-thumb, .sidebar::-webkit-scrollbar-thumb {
562+
::-webkit-scrollbar-thumb,
563+
.sidebar::-webkit-scrollbar-thumb,
564+
#TOC section::-webkit-scrollbar-thumb,
565+
#ModNav section::-webkit-scrollbar-thumb {
557566
background-color: var(--scrollbar-thumb-background-color);
558567
}
559568

@@ -742,7 +751,7 @@ ul.block, .block li, .block ul {
742751
overflow-wrap: break-word;
743752
}
744753

745-
.sidebar-crate + .version {
754+
.sidebar > .version {
746755
margin-top: -1rem;
747756
margin-bottom: 1rem;
748757
}
@@ -2006,6 +2015,111 @@ However, it's not needed with smaller screen width because the doc/code block is
20062015

20072016
/* Media Queries */
20082017

2018+
/* Very-large-screen mode. */
2019+
@supports (display: grid) and (display: contents) {
2020+
@media (min-width: 1600px) and (min-height: 800px) {
2021+
.rustdoc:not(.src) {
2022+
display: grid;
2023+
grid-template-columns:
2024+
var(--desktop-sidebar-width)
2025+
var(--width-limiter-width)
2026+
minmax(0, 1fr);
2027+
grid-template-rows: min-content 1fr;
2028+
grid-template-areas:
2029+
"sidebar-title main sidebar-cratenav"
2030+
"sidebar-modnav main sidebar-toc";
2031+
grid-column-gap: var(--desktop-grid-column-gap);
2032+
}
2033+
.sidebar-resizing .rustdoc:not(.src) {
2034+
padding-left: 0;
2035+
}
2036+
.hide-sidebar .rustdoc:not(.src) {
2037+
grid-template-columns:
2038+
var(--width-limiter-width)
2039+
minmax(0, 1fr);
2040+
grid-template-rows: minmax(min-content, calc(64px + 0.75rem)) 1fr;
2041+
grid-template-areas:
2042+
"main sidebar-cratenav"
2043+
"main sidebar-toc";
2044+
padding-left: var(--desktop-grid-column-gap);
2045+
}
2046+
.rustdoc:not(.src) .sidebar,
2047+
.rustdoc:not(.src) main {
2048+
display: contents;
2049+
}
2050+
.width-limiter {
2051+
grid-area: main;
2052+
width: var(--width-limiter-width);
2053+
--desktop-sidebar-width: 0;
2054+
}
2055+
.rustdoc:not(.src) nav.sub {
2056+
padding-top: 10px;
2057+
}
2058+
.rustdoc:not(.src) .doc-sidebar-title {
2059+
grid-area: sidebar-title;
2060+
background: var(--sidebar-background-color);
2061+
position: sticky;
2062+
top: 0;
2063+
}
2064+
.rustdoc:not(.src) .sidebar-crate {
2065+
margin-bottom: 0.5rem;
2066+
}
2067+
.rustdoc:not(.src) #TOC,
2068+
.rustdoc:not(.src) #CrateNav {
2069+
grid-area: sidebar-toc;
2070+
background: var(--main-background-color);
2071+
padding-left: 0;
2072+
}
2073+
.rustdoc:not(.src) #CrateNav {
2074+
grid-area: sidebar-cratenav;
2075+
align-self: middle;
2076+
}
2077+
.rustdoc:not(.src) #ModNav {
2078+
grid-area: sidebar-modnav;
2079+
background: var(--sidebar-background-color);
2080+
padding-left: 0;
2081+
}
2082+
.rustdoc:not(.src) #ModNav .in-crate {
2083+
display: none;
2084+
}
2085+
.rustdoc:not(.src) #TOC section,
2086+
.rustdoc:not(.src) #ModNav section {
2087+
position: sticky;
2088+
top: 0;
2089+
bottom: 0;
2090+
overflow-y: scroll;
2091+
overscroll-behavior: contain;
2092+
max-height: 100vh;
2093+
padding-left: 24px;
2094+
}
2095+
.rustdoc:not(.src) #TOC .location,
2096+
.rustdoc:not(.src) #ModNav h2 {
2097+
margin-top: 0;
2098+
}
2099+
.rustdoc:not(.src) #ModNav section {
2100+
top: calc(64px + 0.75rem);
2101+
max-height: calc(100vh - 64px - 0.75rem);
2102+
background: var(--sidebar-background-color);
2103+
border-top: solid 1px var(--border-color);
2104+
}
2105+
.rustdoc:not(.src) #TOC section {
2106+
max-height: calc(100vh - 0.5rem);
2107+
top: 0.25rem;
2108+
margin: 0 var(--desktop-grid-column-gap) var(--desktop-grid-column-gap) 0;
2109+
border: solid 1px var(--border-color);
2110+
padding: 0.25rem;
2111+
}
2112+
.rustdoc:not(.src) #CrateNav .block:last-child,
2113+
.rustdoc:not(.src) #TOC .block:last-child {
2114+
margin-bottom: 0;
2115+
}
2116+
.rustdoc:not(.src) #CrateNav a:hover,
2117+
.rustdoc:not(.src) #TOC a:hover {
2118+
background-color: var(--sidebar-background-color);
2119+
}
2120+
}
2121+
}
2122+
20092123
/* Make sure all the buttons line wrap at the same time */
20102124
@media (max-width: 850px) {
20112125
#search-tabs .count {

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

+18-4
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ function preLoadCss(cssUrl) {
493493
if (!window.SIDEBAR_ITEMS) {
494494
return;
495495
}
496-
const sidebar = document.getElementById("rustdoc-modnav");
496+
const sidebar = document.querySelector("#rustdoc-modnav section");
497497

498498
/**
499499
* Append to the sidebar a "block" of links - a heading along with a list (`<ul>`) of items.
@@ -533,8 +533,9 @@ function preLoadCss(cssUrl) {
533533
const li = document.createElement("li");
534534
// Don't "optimize" this to just use `path`.
535535
// We want the browser to normalize this into an absolute URL.
536-
if (link.href === current_page) {
537-
li.classList.add("current");
536+
if (link.href.toString() === current_page) {
537+
link.className = "current";
538+
li.className = "current";
538539
}
539540
li.appendChild(link);
540541
ul.appendChild(li);
@@ -880,7 +881,7 @@ function preLoadCss(cssUrl) {
880881
if (!window.ALL_CRATES) {
881882
return;
882883
}
883-
const sidebarElems = document.getElementById("rustdoc-modnav");
884+
const sidebarElems = document.querySelector("#rustdoc-modnav section");
884885
if (!sidebarElems) {
885886
return;
886887
}
@@ -1546,6 +1547,15 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
15461547
// At half-way past the minimum size, vanish the sidebar entirely
15471548
const SIDEBAR_VANISH_THRESHOLD = SIDEBAR_MIN / 2;
15481549

1550+
// When running in grid layout mode, we have to change sizes
1551+
// on the parent element. Otherwise, we can resize the sidebar
1552+
// independently.
1553+
//
1554+
// This is less bad than it otherwise would be, since if you are in grid
1555+
// mode, resizing the sidebar will resize the floating TOC, not the huge
1556+
// content area.
1557+
let gridMode = window.getComputedStyle(document.querySelector(".rustdoc")).display === "grid";
1558+
15491559
// Toolbar button to show the sidebar.
15501560
//
15511561
// On small, "mobile-sized" viewports, it's not persistent and it
@@ -1666,6 +1676,9 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
16661676
updateLocalStorage("desktop-sidebar-width", size);
16671677
sidebar.style.setProperty("--desktop-sidebar-width", size + "px");
16681678
resizer.style.setProperty("--desktop-sidebar-width", size + "px");
1679+
if (gridMode) {
1680+
document.documentElement.style.setProperty("--desktop-sidebar-width", size + "px");
1681+
}
16691682
}
16701683
}
16711684

@@ -1717,6 +1730,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
17171730
if (window.innerWidth < RUSTDOC_MOBILE_BREAKPOINT) {
17181731
return;
17191732
}
1733+
gridMode = window.getComputedStyle(document.querySelector(".rustdoc")).display === "grid";
17201734
stopResize();
17211735
if (desiredSidebarSize >= (window.innerWidth - BODY_MIN)) {
17221736
changeSidebarSize(window.innerWidth - BODY_MIN);

src/librustdoc/html/templates/page.html

+17-15
Original file line numberDiff line numberDiff line change
@@ -87,22 +87,24 @@
8787
{% endif %}
8888
<nav class="sidebar"> {# #}
8989
{% if page.css_class != "src" %}
90-
<div class="sidebar-crate">
91-
{% if !layout.logo.is_empty() || page.rust_logo %}
92-
<a class="logo-container" href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html"> {# #}
93-
{% if page.rust_logo %}
94-
<img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
95-
{% else if !layout.logo.is_empty() %}
96-
<img src="{{layout.logo}}" alt="logo"> {# #}
90+
<div class="doc-sidebar-title">
91+
<div class="sidebar-crate">
92+
{% if !layout.logo.is_empty() || page.rust_logo %}
93+
<a class="logo-container" href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html"> {# #}
94+
{% if page.rust_logo %}
95+
<img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
96+
{% else if !layout.logo.is_empty() %}
97+
<img src="{{layout.logo}}" alt="logo"> {# #}
98+
{% endif %}
99+
</a> {# #}
97100
{% endif %}
98-
</a> {# #}
99-
{% endif %}
100-
<h2> {# #}
101-
<a href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html">{{display_krate|wrapped|safe}}</a> {# #}
102-
{% if !display_krate_version_number.is_empty() %}
103-
<span class="version">{{+ display_krate_version_number}}</span>
104-
{% endif %}
105-
</h2> {# #}
101+
<h2> {# #}
102+
<a href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html">{{display_krate|wrapped|safe}}</a> {# #}
103+
{% if !display_krate_version_number.is_empty() %}
104+
<span class="version">{{+ display_krate_version_number}}</span>
105+
{% endif %}
106+
</h2> {# #}
107+
</div> {# #}
106108
</div> {# #}
107109
{% if !display_krate_version_extra.is_empty() %}
108110
<div class="version">{{+ display_krate_version_extra}}</div> {# #}

src/librustdoc/html/templates/sidebar.html

+13-10
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
<div class="sidebar-elems">
2-
{% if is_crate %}
3-
<ul class="block"> {# #}
1+
{% if is_crate %}
2+
<div class="sidebar-elems" id="rustdoc-cratenav">
3+
<ul class="block">
44
<li><a id="all-types" href="all.html">All Items</a></li> {# #}
55
</ul>
6-
{% endif %}
7-
8-
{% if self.should_render_blocks() %}
9-
<section id="rustdoc-toc">
6+
</div>
7+
{% endif %}
8+
{% if self.should_render_blocks() %}
9+
<div class="sidebar-elems" id="rustdoc-toc">
10+
<section>
1011
{% if !title.is_empty() %}
1112
<h2 class="location"> {# #}
1213
<a href="#">{{title_prefix}}{{title|wrapped|safe}}</a> {# #}
@@ -52,12 +53,14 @@ <h3> {# #}
5253
{% endif %}
5354
{% endfor %}
5455
</section>
55-
{% endif %}
56-
<div id="rustdoc-modnav">
56+
</div>
57+
{% endif %}
58+
<div class="sidebar-elems" id="rustdoc-modnav">
59+
<section>
5760
{% if !path.is_empty() %}
5861
<h2{% if parent_is_crate +%} class="in-crate"{% endif %}> {# #}
5962
<a href="{% if is_mod %}../{% endif %}index.html">In {{+ path|wrapped|safe}}</a> {# #}
6063
</h2>
6164
{% endif %}
62-
</div> {# #}
65+
</section> {# #}
6366
</div>

tests/rustdoc-gui/sidebar-modnav-position.goml

+6-6
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,26 @@ define-function: (
1919
block {
2020
go-to: "file://" + |DOC_PATH| + |url|
2121
// Checking results colors.
22-
assert-position: ("#rustdoc-modnav > h2", {"x": |h2_x|, "y": |h2_y|})
22+
assert-position: ("#rustdoc-modnav > section > h2", {"x": |h2_x|, "y": |h2_y|})
2323
assert-position: (
24-
"#rustdoc-modnav > ul:first-of-type > li:first-of-type",
24+
"#rustdoc-modnav > section > ul:first-of-type > li:first-of-type",
2525
{"x": |x|, "y": |y|}
2626
)
2727
},
2828
)
2929

3030
// First, at test_docs root
3131
go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html"
32-
store-position: ("#rustdoc-modnav > h2", {"x": h2_x, "y": h2_y})
33-
store-position: ("#rustdoc-modnav > ul:first-of-type > li:first-of-type", {"x": x, "y": y})
32+
store-position: ("#rustdoc-modnav > section > h2", {"x": h2_x, "y": h2_y})
33+
store-position: ("#rustdoc-modnav > section > ul:first-of-type > li:first-of-type", {"x": x, "y": y})
3434
call-function: ("check-positions", {"url": "/test_docs/enum.WhoLetTheDogOut.html"})
3535
call-function: ("check-positions", {"url": "/test_docs/struct.StructWithPublicUndocumentedFields.html"})
3636
call-function: ("check-positions", {"url": "/test_docs/codeblock_sub/index.html"})
3737

3838
// Now in a submodule
3939
go-to: "file://" + |DOC_PATH| + "/test_docs/fields/struct.Struct.html"
40-
store-position: ("#rustdoc-modnav > h2", {"x": h2_x, "y": h2_y})
41-
store-position: ("#rustdoc-modnav > ul:first-of-type > li:first-of-type", {"x": x, "y": y})
40+
store-position: ("#rustdoc-modnav > section > h2", {"x": h2_x, "y": h2_y})
41+
store-position: ("#rustdoc-modnav > section > ul:first-of-type > li:first-of-type", {"x": x, "y": y})
4242
call-function: ("check-positions", {"url": "/test_docs/fields/struct.Struct.html"})
4343
call-function: ("check-positions", {"url": "/test_docs/fields/union.Union.html"})
4444
call-function: ("check-positions", {"url": "/test_docs/fields/enum.Enum.html"})

0 commit comments

Comments
 (0)