I'm developing a web interface that involves a lot of scrolling, utilizing sticky positioning, which works beautifully except for one little detail. Below is a minimalist example. You can try it on CodePen to see how the stickies work when scrolling horizontally and vertically.
<header>
<nav>
<ul id=menu class=flex><li><a href="#">Menu bar item</a></li></ul>
</nav>
<div class=flex>
<div id=button>Button</div>
<div id=bar>Bar wider than the window</div>
</div>
</header>
<main class=flex>
<div id=leftbar></div>
<div id=content></div>
</main>
* {line-height: 2em; background-position: center center}
body {margin: 0; padding: 0}
body, a {color: #fff}
ul,li {margin: 0; padding: 0; list-style-type: none}
.flex {display: flex}
.flex > * {flex: 0 0 auto}
header {display: block; position: sticky; top: 0; left: 0; z-index: 1;
width: min-content; min-width: 100%; background: #000066}
#menu {flex-wrap: wrap; position: sticky; left: 0; width: 100vw;
background: #006600}
#button {position: sticky; left: 0; width: 4em; background: #000066}
#bar {width: 150vw}
main {min-height: 100vh} /* Ensure scrollbar */
#leftbar {position: sticky; left: 0; width: 4em; background: #444444}
#content {width: 150vw}
/* Background grid to visualize scrolling parts */
#bar, #leftbar, #content {
background-image: url(data:image/gif;base64,R0lGODlhEAAQAIABAO7u7v///yH5BAEKAAEA
LAAAAAAQABAAAAIdhI9pwe0PnnRxzmphlniz7oGbmJGWeXmU2qAcyxQAOw==)}
The problem is in the topmost menu bar, which should always remain in place like a fixed header but must be sticky. 100vw width works perfectly until scrolling all the way to the right. At that point the leftmost part of the menu bar scrolls out of view, presumably due to the vertical scrollbar not being counted in 100vw.
Fixed positioning is out of the question, because the height of the menu bar will vary, so that'd need a pile of very ugly JS reading offsetHeight
and moving the elements below after every DOM change – yuck!
Surely there is a way to fix this tiny problem in pure CSS or by altering the document structure?
Edit: I see JS solutions starting to pour in, so let's put a stop to that with these 3 lines of JS that fix the problem easily. I'd just prefer a CSS/HTML solution to avoid code maintenance problems in the future.
var f=function() {document.getElementById('menu').style.width=document.body.clientWidth+'px';};
window.addEventListener('DOMContentLoaded',f);
window.addEventListener('resize',f);