模态框固定位置的内容移动

8
经过大量的研究,我无法找到一个合适的解决方案来解决固定定位元素、封面图片和标准内容向右移动的问题,当模态窗口打开时。 注意: 我正在寻找一个通用的、干净的解决方案,而不是一个只能在特定布局上工作的硬编码修复方法。
有人知道如何解决这个问题吗?请参考这个例子: http://codepen.io/microcipcip/pen/kXdRWK
body {
  height: 2500px;
  &.-modal-open {
      overflow: hidden;
  }
}
.fixed {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  padding: 20px 0;
  background: #FF0000;
}
.modal {
    overflow-x: hidden;
    overflow-y: scroll;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.4);
    opacity: 0;
    transition: opacity .2s ease-in-out;
    body.-modal-open & {
        opacity: 1;
    }
}

这是因为 &.-modal-open {overflow: hidden;}。通过注释它来检查! - Pugazh
那会给我两个滚动条。我不能从body中删除overflow: hidden;,因为这也会允许在移动设备上滚动(基本上你将无法滚动模态框)。 - Microcipcip
3个回答

5
解决方案非常简单,只需使用纯CSS即可修复:
.-modal-open .fixed,
.-modal-open .content {
  overflow-y:scroll;
}

然而,这需要您的内容以不同的样式进行排版。您不应该使用margin来设置内容,而是将其包裹在容器中并使用padding。

滚动条的宽度并不总是17px...17像素是针对Firefox的,但是对于Chrome是15px,有时根据代码IE甚至没有滚动条宽度。

这是更新后的代码片段: http://codepen.io/scooterlord/pen/KgKLwB

编辑:我忘了说,这是一个跨浏览器解决方案,在我测试的所有地方都能完美工作。如果浏览器是移动设备,则根本不会因为添加/删除额外的滚动条而改变宽度,并且根据浏览器创建的新的内容/固定元素滚动条始终与初始body滚动条相同。


这是一个非常聪明的解决方案!基本上,您正在通过在内容容器中添加滚动条来弥补从主体中删除滚动条的影响。 - Microcipcip
就是这样了。 - scooterlord
有没有可能的解决方案来解决封面背景的移动?我试图将其移动到容器内部,但它仍然在移动。 - Microcipcip
你在背景上使用了background-size:cover。可能这不是你想在最终项目中使用的实际背景,所以根据实际背景可能有一种方法可以解决 - 但必须先看到它。 - scooterlord
我认为使用什么背景并不重要,通常我将其设置为background-size: cover;,当模态框打开时会发生偏移。我尝试将背景移动到容器中,但这并不能解决问题。显然,我更愿意使用background-attachment: fixed;,但我仍然看到了这个问题:http://codepen.io/microcipcip/pen/pEvZrV - Microcipcip
这与主题无关,但是attachment:fixed会导致移动设备性能严重问题,因此通常应避免使用。封面背景大小取决于容器宽度,因此当滚动条消失时,背景会重新调整大小;我能想到的唯一解决方案(虽然不适用于移动设备)是在内容顶部使用一个溢出的固定容器,并将body设置为overflow:hidden,并将所有modal-open类附加到溢出的容器上。除此之外,我建议您使用像tiny-scrollbar这样的许多添加自定义滚动条的插件。 - scooterlord

2
主要的技巧是不要使用 body 作为你的内容包装器。使用专门的 div 作为包装器,并将你的模态框放在外面,这样滚动条就不会互相干扰了。

var $btnShow = document.querySelector('.show');
var $btnHide = document.querySelector('.hide');
var $body = document.querySelector('.modal');
$btnShow.addEventListener('click', function() {
    $body.classList.toggle('-modal-open')
});
$btnHide.addEventListener('click', function() {
    $body.classList.toggle('-modal-open')
});
.wrapper {
  position: fixed;
  top: 0;
  left: 0;
  bottom:0;
  right:0;
  overflow: auto;
}
.content {
  background: url('https://www.dropbox.com/s/m16kxhb2jg5jwwh/bear-800x450.jpg?dl=0&raw=1');
  background-size: cover;
  background-position: center center;
  height: 2500px;
  width: 100%; 
}

.clickme {
  position: fixed;
  top: 50%;
  left: 50%;
  padding: 10px;
  border: none;
  background: #000000;
  color: #ffffff;
  text-transform: uppercase;
  transform: translate(-50%, -50%);
}
.clickme:hover {
  background: grey;
  cursor:pointer
}

.modal {
  overflow-x: hidden;
  overflow-y: scroll;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.4);
  display: none;
  transition: opacity .2s ease-in-out;
  z-index: 3;
}
.modal.-modal-open {
  display:block;
}
.modal-content {
  min-height: 1500px;
  margin: 100px;
  background: url('https://www.dropbox.com/s/u520y7yo711uaxi/poster2.jpg?dl=0&raw=1');
  background-size: cover;
}
<div class="modal">
    <div class="modal-content">Content
    <button class="clickme hide">Toggle Modal HIDE!</button>
    </div>
</div>
<div class="wrapper">
    <div class="content">
<button class="clickme show">Toggle Modal SHOW!</button>
    </div>
</div>


这几乎是我想要的,但整个内容区现在是一个固定定位元素,我会看看是否可以将此解决方案用于页面的正常流程。 - Microcipcip
可以确保它是第一个div,并将其视为body标签。 - Rudi Urbanek

-1

每次打开模态框时,给 body 添加 17px 的右边距如何?这将模拟为滚动条预留的空间。(17px 是标准浏览器宽度)

body.-modal-open {
    margin-right: 17px;
}

同时,对于固定元素,您需要重新计算其宽度;

.-modal-open .fixed {
    width: calc(100% - 17px);
}

然而还有一个问题,CSS背景图片仍然偏移,解决方法是将其放置在div容器中而不是body中。


滚动条的宽度取决于浏览器和操作系统。在Chrome/Linux中为15px,在Windows上相同的宽度为17px。对于Firefox在Linux上为13px。我猜在Mac上这些数字都不同。 - AA2992

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接