首页 > 解决方案 > 滚动容器内的右侧固定侧边栏

问题描述

听起来这可能已经被问过一百万次了,但我还没有找到真正解决我试图解决的所有问题的任何东西。有了这个免责声明,这就是我想要实现的目标:

  1. 侧边栏,固定在右侧
  2. 一个内容区域,可能是可滚动的
  3. 内容区的滚动条需要在侧边栏的右侧
  4. 应该可以显示覆盖
  5. 叠加层也应该是可滚动的
  6. 虽然覆盖层是可见的,但底层内容区域不应该是可滚动的
  7. 显示带有滚动条的覆盖不应导致底层内容区域的重新布局,例如,因为overflow: hidden

所有这些要求的结合打破了我尝试过的每个解决方案。

我现在有两个解决方案,它们很接近但仍然不够好:
解决方案 1 没有解决要求 7。
解决方案 2 在覆盖可见时有两个滚动条。

解决方案1:

function showOverlay() {
  var style = document.body.style;
  style.overflow = 'hidden';
  document.getElementById('overlay').style.display = 'block';
}

function closeOverlay() {
  var style = document.body.style;
  style['overflow-y'] = 'scroll';
  document.getElementById('overlay').style.display = 'none';
}
* {
  margin: 0;
  box-sizing: border-box
}
html {
}
body {
  position: relative;
  width: 100%;
  overflow-y: scroll;
}

.content {
  position: relative;
  display: block;
  background-color: lightblue;
  border: 2px solid white;
  width: calc(100% - 60px)
}

.fixed {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 1000;
  background-color: lightgreen;
  width: 60px;
  border: 2px solid black;
  text-align: right;
}

#overlay {
  display: none;
  position: fixed;
  z-index: 10000;
  left: 0;
  top: 0;
  bottom: 0;
  right: 0;
  background-color: rgba(32,32,32,0.5);
  overflow-y: scroll;
}

.overlay-content {
  margin: 50px auto;
  height: 1000px;
  width: 80%;
  background-color: yellow;
}
<div class="content">
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    <button onclick="showOverlay()">show overlay</button>
  </div>
<div class="fixed">A<br/>B<br/>C</div>
<div id="overlay">
  <div class="overlay-content">
    <button onclick="closeOverlay()">Close overlay</button>
  </div>
</div>

解决方案2:

function showOverlay() {
  var style = document.body.style;
  style.top = '-' + document.documentElement.scrollTop + 'px';
  style.position = 'fixed';
  document.getElementById('overlay').style.display = 'block';
}

function closeOverlay() {
  var style = document.body.style;
  style.position = 'relative';
  style.top = 0;
  document.getElementById('overlay').style.display = 'none';
}
* {
  margin: 0;
  box-sizing: border-box
}
html {
}
body {
  position: relative;
  width: 100%;
  overflow-y: scroll;
}

.content {
  position: relative;
  display: block;
  background-color: lightblue;
  border: 2px solid white;
  width: calc(100% - 60px)
}

.fixed {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 1000;
  background-color: lightgreen;
  width: 60px;
  border: 2px solid black;
  text-align: right;
}

#overlay {
  display: none;
  position: fixed;
  z-index: 10000;
  left: 0;
  top: 0;
  bottom: 0;
  right: 0;
  background-color: rgba(32,32,32,0.5);
  overflow-y: scroll;
}

.overlay-content {
  margin: 50px auto;
  height: 1000px;
  width: 80%;
  background-color: yellow;
}
<div class="content">
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    Body<br/>
    <button onclick="showOverlay()">show overlay</button>
  </div>
<div class="fixed">A<br/>B<br/>C</div>
<div id="overlay">
  <div class="overlay-content">
    <button onclick="closeOverlay()">Close overlay</button>
  </div>
</div>

我认为解决方案 1 是两者中更好的一个,但是否有可能阻止重新布局的发生?

请注意,我正在尝试找到一个不使用 Javascript 来检测滚动条宽度的解决方案。

标签: htmlcss

解决方案


解决办法是把内容和修复部分包裹起来,防止从body.

此外,您使用包装器包装修复部分position: absolute。不同之处在于不同position的 s 处理方式right: 0。是相对于absolute父级(带有position: relative),并且fixed总是相对于窗口。

此时浏览器将阻止您在侧边栏上的鼠标滚轮事件(因为position: fixed),因此我们将添加.fixed-innerwithpointer-events: auto以允许用户与侧边栏内容进行交互。

我只在最新的 Chrome 上测试过。

function showOverlay() {
  //  var style = document.body.style;
  //  style.overflow = 'hidden';
  document.getElementById('overlay').style.display = 'block';
}

function closeOverlay() {
  //  var style = document.body.style;
  //  style['overflow-y'] = 'scroll';
  document.getElementById('overlay').style.display = 'none';
}
* {
  margin: 0;
  box-sizing: border-box
}

html,
body {
  position: relative;
  height: 100%;
  overflow-y: hidden;
}

.wrapper {
  overflow-y: auto;
  position: relative;
  height: 100%;
}

.content {
  position: relative;
  display: block;
  background-color: lightblue;
  border: 2px solid white;
  width: calc(100% - 60px)
}

.fixed-wrapper {
  position: absolute;
  top: 0;
  right: 0;
  width: 60px;
  height: 100%;
}

.fixed {
  position: fixed;
  z-index: 1000;
  background-color: lightgreen;
  width: 60px;
  border: 2px solid black;
  text-align: right;
  height: 100%;
  top: 0;
  pointer-events: none;
}

.fixed .fixed-inner {
  pointer-events: auto;
}

#overlay {
  display: none;
  position: fixed;
  z-index: 10000;
  left: 0;
  top: 0;
  bottom: 0;
  right: 0;
  background-color: rgba(32, 32, 32, 0.5);
  overflow-y: scroll;
}

.overlay-content {
  margin: 50px auto;
  height: 1000px;
  width: 80%;
  background-color: yellow;
}
<div class="wrapper">
  <div class="content">
    Body<br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/> Body
    <br/>
    <button onclick="showOverlay()">show overlay</button>
  </div>
  <div class="fixed-wrapper">
    <div class="fixed">
      <div class="fixed-inner">
        <a href="https://google.com">A</a>
        <br/>B<br/>C
      </div>
    </div>
  </div>
</div>
<div id="overlay">
  <div class="overlay-content">
    <button onclick="closeOverlay()">Close overlay</button>
  </div>
</div>


推荐阅读