尝试制作一个具有标题的布局,可以像平常一样垂直滚动页面。但是,如果使用 HTML 滚动条(重要的是它是 HTML 滚动条,因此不必寻找水平滚动条,HTML 滚动条始终显示在视口的底部),标题水平固定。这是一种内容比视口宽的布局,但人们希望标题始终水平显示,但允许其垂直滚动到屏幕外以获得屏幕空间。
当向右滚动时,标题旁边通常是一个空白的空间,我希望标题保持水平粘性(但如前面提到的垂直滚动)。
在这里您可以看到,当我在桌面上水平滚动时,金色标题停留在该位置并填充整个宽度。
但是一旦你切换到移动设备,它就不再起作用,当我水平滚动时,你可以看到这里的白色间隙,而不是标题仍然卡在原处:
此代码片段不会切换到移动视图,因此如果您想查看移动设备中发生了什么,您必须将其复制并粘贴到文件中并亲自尝试:
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"><!-- For mobile device scaling -->
<style>
* {
box-sizing: border-box;
}
html {
overflow-y: scroll;
width: max-content;
}
body {
margin: 0;
}
header {
background: goldenrod;
border-right: 1px solid red;
position: sticky;
left: 0;
width: calc(100vw - 15px);
}
main {
width: 120vw;
height: 120vh;
background: gray;
}
</style>
</head>
<body>
<header> Header
</header>
<main>
<div>Main stuff</div>
<div>Paragraph that is very wide, so wide it should go beyond the width of the viewport, loooooooooooooooooooooooooooooooooooooooong</div>
</main>
</body>
</html>
此代码片段不切换到移动视图并显示问题,只是为了完整性而提供。
* {
box-sizing: border-box;
}
html {
overflow-y: scroll;
width: max-content;
}
body {
margin: 0;
}
header {
background: goldenrod;
border-right: 1px solid red;
position: sticky;
left: 0;
width: calc(100vw - 12px);
}
main {
width: 200vw;
height: 120vh;
background: gray;
}
<header>Header, should stick horizontally, scroll vertically as usual
</header>
<main>
<div>Main stuff</div>
<div>Paragraph that is very wide, so wide it should go beyond the width of the viewport, loooooooooooooooooooooooooooooooooooooooong</div>
</main>
问题是滚动条,在移动设备上滚动条不占用屏幕右侧的任何空间。
为此,您必须使用 javascript,这是一个示例:
document.addEventListener("DOMContentLoaded", function () {
function getScrollBarWidth() {
let el = document.createElement("div");
el.style.cssText = "overflow:scroll; visibility:hidden; position:absolute;";
document.body.appendChild(el);
let width = el.offsetWidth - el.clientWidth;
el.remove();
return width;
}
let siteHeader = document.getElementById("siteHeader");
siteHeader.style.width = `calc(100vw - ${getScrollBarWidth()}px)`;
});
* {
box-sizing: border-box;
}
html {
overflow-y: scroll;
width: max-content;
}
body {
margin: 0;
}
header {
background: goldenrod;
border-right: 1px solid red;
position: sticky;
left: 0;
}
#siteHeader {
width: 100vw;
}
main {
width: 200vw;
height: 120vh;
background: gray;
}
<header id="siteHeader">Header, should stick horizontally, scroll vertically as usual</header>
<main>
<div>Main stuff</div>
<div>Paragraph that is very wide, so wide it should go beyond the width of the viewport, loooooooooooooooooooooooooooooooooooooooong</div>
</main>
归功于这篇文章的 getScrollBarWidth 函数
简单明了:纯粹使用 CSS 和 HTML 来满足您的所有要求是不可能的。自从 2012 年引入视口单位(
vw
、vh
、svh
等)以来,这个问题就众所周知了。
您可能需要考虑的几个解决方案:
正如其他人已经建议的那样,一种常见的方法是动态计算滚动条宽度并相应地调整标题的宽度。迄今为止其他人提出的解决方案已经过时,可以改进。我提出以下建议:
(function() {
const scrollbarSize = window.innerWidth - document.documentElement.clientWidth;
document.getElementById("header").style.setProperty("width", `calc(100vw - ${scrollbarSize}px)`);
})();
* {
box-sizing: border-box;
}
html {
overflow-y: scroll;
width: max-content;
}
body {
margin: 0;
}
header {
background: goldenrod;
position: sticky;
left: 0;
}
main {
width: 200vw;
height: 120vh;
background: gray;
}
<header id="header">Header</header>
<main>
<div>Main stuff</div>
<div>
Paragraph that is very wide, so wide it should go beyond the width of the
viewport, loooooooooooooooooooooooooooooooooooooooong
</div>
</main>
更优雅的方法是将滚动条宽度设置为 CSS 变量,使其可在整个 CSS 代码中重用:
(function() {
const scrollbarSize = window.innerWidth - document.documentElement.clientWidth;
document.querySelector(':root').style.setProperty("--scrollbarSize", `${scrollbarSize}px`);
})();
:root {
/* Use this variable anywhere you want! */
--scrollbarSize: 0;
}
* {
box-sizing: border-box;
}
html {
overflow-y: scroll;
width: max-content;
}
body {
margin: 0;
}
header {
background: goldenrod;
position: sticky;
left: 0;
width: calc(100vw - var(--scrollbarSize));
}
main {
width: 200vw;
height: 120vh;
background: gray;
}
<header id="header">Header</header>
<main>
<div>Main stuff</div>
<div>
Paragraph that is very wide, so wide it should go beyond the width of the
viewport, loooooooooooooooooooooooooooooooooooooooong
</div>
</main>
虽然有时想要避免使用 JavaScript 是可以理解的,但仅靠 CSS 无法完全满足这些要求。使用一个小的 JavaScript 片段来计算滚动条宽度并动态调整样式是最可靠的方法。