许多程序员问过如何在margin: 0 auto;出现垂直滚动条时停止其网页内容(尤其是居中的网页内容())在水平方向移动(被推动)。对于Ajax用户和像我这样使用隐藏的div和选项卡来组织数据的人,这一直是一个持续存在的问题。
margin: 0 auto;
当当前显示的页面发生更改,使得显示的材料的高度(内部窗口高度)突然大于物理窗口高度时,就会出现问题。
并非所有滚动条都相等的现实使问题更加严重。不同的浏览器为其滚动条提供不同的宽度,并且无法(或至少不应)预测该差异。简而言之,理想的解决方案是与滚动条宽度无关。
因此,这是一个自我解答的问题,截至2017年8月5日,所有这些答案以及对它们的实用性的评论(如果可能)以及我自己的解决方案都将汇总为一个答案。我可以找到以前的问题,以便人们可以对该问题进行全面的讨论。
_请注意,此答案解决了BODY内容转移的问题。 如果您有一个固定高度的DIV且存在移动问题,则应将DIV宽度设置为固定(px)宽度,以便其滚动条浮在文本上方,并添加一些右手边距以防止文本掉入其下方。
px
在讨论单个解决方案之前,应该提到它们分为三类:基于CSS的解决方案,基于CSS3的解决方案和基于Javascript的解决方案。
CSS解决方案往往比较复杂,但是非常可预测且得到很好的支持。
CSS3解决方案像Javascript一样具有CPU计算成本,但是易于实现。但是,在2017年之前的几年中,它们在浏览器中得到了零星的支持。随着时间的推移,这种情况正在改善。最终,它们将可能是最好的解决方案,但是我今天的调查表明,这种支持还远远不够一致,此外,还不存在传统的浏览器支持。
Javascript解决方案(无论是直接Javascript还是jQuery)都需要额外的编码以使其健壮,因为它们不固有支持(例如)窗口大小调整。但是,它们是最可预测且最向后兼容的,同时仍保留页面的美感。我认为旧版浏览器的产品线介于IE6和IE7之间。坦白说,我对仍然使用旧版浏览器的人表示哀悼。
请注意,我 没有 包括以前发布到Stack Exchange的所有CSS3和Javascript解决方案。有些虽然很新颖,但有很多弱点,因此这里不包括在内。
解决方案1:CSS解决方案
强制滚动条始终处于打开状态。
<style> html { overflow-y: scroll; } </style>
基本上可以保证此解决方案始终有效(有一些例外,但它们很少见),但从美学上讲是令人不愉快的。无论是否需要,总是可以看到滚动条。虽然共识是要在html标签中使用此解决方案,但有人建议在body标签中使用它。
html
body
后果
Microsoft(IE10 +)具有浮动滚动条,这意味着您的页面可能不会像在其他浏览器中那样居中。但是,这似乎是一个很小的问题。
当使用诸如FancyBox,Flex-Box或TwitterBootstrapModal之类的结构化界面时,这会导致双滚动条出现,因为这些接口创建了自己的滚动条。
程序员应避免使用,overflow: scroll因为这会导致垂直和水平滚动条同时出现。
overflow: scroll
解决方案1a:替代方法
一个聪明的选择是,这样做是:
<style> html { height: 101%; } </style>
这将激活滚动条 背景, 但不会激活滚动条 选项卡, 除非您的垂直内容实际上溢出了窗口的底部边缘。然而,它具有相同的缺点,即无论是否需要,滚动条空间都会被永久占用。
解决方案1b:更现代的解决方案
浏览器开始overlay模仿IE10 +的浮动滚动条,开始使用滚动条的值。
overlay
<style> html { overflow-y: overlay; } </style>
该解决方案模仿IE10 +中的浮动滚动条,但并非在所有浏览器中都可用,并且仍然具有一些实现上的怪癖。众所周知,该解决方案不适用于Bootstrap Modal之类的基础架构环境。
解决方案2:CSS3解决方案
使用CSS3计算宽度。这样做有很多方法,每种方法各有利弊。大多数缺点是由于(a)不知道实际的滚动条宽度,(b)处理屏幕大小调整,以及(c)CSS正在慢慢成为另一种功能齐全的编程语言(如Javascript),但具有尚未完全演变成这样。使其变得如此有意义是否是另一个问题的争论。
用户可能禁用Java脚本,因此首选CSS唯一解决方案的论点变得无关紧要。客户端编程已变得无处不在,以至于只有最偏执的人仍在禁用Javascript。就我个人而言,我不再认为这是一个站得住脚的论点。
应该注意的是,某些解决方案会修改,margin而其他解决方案会修改padding。那些修改的对象margin有一个普遍的问题:如果导航栏,标题,边框等使用的颜色与页面背景颜色不同,则此解决方案将暴露出不希望的边框。使用的任何解决方案都有可能margin被重新设计以使用padding,反之亦然。
margin
padding
解决方案2a:基于HTML的解决方案
<style> html { margin-left: calc(100vw - 100%); margin-right: 0; } </script>
解决方案2b:基于身体的解决方案
<style> body { padding-left: 17px; width: calc(100vw - 17px); } @media screen and (min-width: 1058px) { body { padding-left: 17px; width: calc(100vw - 17px); } } </style>
100vw 是视口宽度的100%。
100vw
一些用户建议在调整窗口大小时此解决方案会产生不希望的屏幕噪音(也许在调整大小过程中,计算过程会多次发生)。可能的解决方法是避免使用margin: 0 auto;到中心内容,而使用下面的(在1000px与500px在所示的例子中表示内容的最大宽度和一半量,分别地):
1000px
500px
<style> body { margin-left: calc(50vw - 500px); } @media screen and (max-width: 1000px) { body { margin-left: 0; } } </style>
这是固定滚动条宽度的解决方案,它与浏览器无关。要使其独立于浏览器,必须包含Javascript以确定滚动条的宽度。计算宽度但不重新合并值的示例是:
请注意,以下代码段已多次在Stack Exchange和Internet上的其他位置上多次张贴,没有明确的署名。
function scrollbarWidth() { var div = $('<div style="width:50px;height:50px;overflow:hidden;position:absolute;top:-200px;left:-200px;"><div style="height:100px;"></div>'); // Append our div, do our calculation and then remove it $('body').append(div); var w1 = $('div', div).innerWidth(); div.css('overflow-y', 'scroll'); var w2 = $('div', div).innerWidth(); $(div).remove(); return (w1 - w2); }
解决方案2c:基于DIV的解决方案
使用直接应用于容器DIV元素的CSS3计算。
<body> <div style="padding-left: calc(100vw - 100%);"> My Content </div> </body>
像所有CSS3解决方案一样,并非所有浏览器都支持此功能。即使是那些支持视口计算的浏览器(截至撰写本文时)也不支持其任意使用。
解决方案2d:自举模式
Twitter Bootstrap Modal的用户发现将以下CSS3应用于其HTML元素很有用。
<style> html { width: 100%; width: 100vw; } </style>
另一个建议是在内容包装器周围创建一个包装器,该包装器用于自动检测视口宽度的变化。
<style> body { overflow-x: hidden; } #wrap-wrap { width: 100vw; } #content-wrap { margin: 0 auto; width: 800px; } </style>
我没有尝试过任何一种,因为我没有使用Bootstrap。
解决方案#3:Javascript解决方案
这是我最喜欢的解决方案,因为它可以处理所有问题,并且可以合理地向后兼容旧版浏览器。最重要的是,它与滚动条宽度无关。
<script> function updateWindow(){ document.body.style.paddingLeft = (window.innerWidth - document.body.clientWidth); document.body.onclick=function(){ document.body.style.paddingLeft = (window.innerWidth - document.body.clientWidth); } } window.onload=updateWindow(); window.addEventListener("resize", updateWindow()); updateWindow(); </script>
最终命令to updateWindow();应该出现在</body>标记之前,以避免动态加载内容(例如Facebook Like- Boxes)出现问题。看来这对window.onload事件是多余的,但是并不是每个浏览器都onload以相同的方式对待。有些等待异步事件。其他人没有。
updateWindow();
</body>
window.onload
onload
每当用户在网页中单击时,都会执行该功能。感激的是,现代计算机的速度足够快,因此这不是什么大问题。仍然…。
最后,应在异步更新任何div(AJAX)之后执行该函数。在此示例中未显示,但这将是就绪状态条件的一部分。例如:
xmlhttp.onreadystatechange=function(){ if(xmlhttp.readyState==4 && xmlhttp.status==200){ if(xmlhttp.responseText == 'false'){ //Error processing here } else { //Success processing here updateWindow(); } } }
解决方案#3a:测量滚动条宽度
这是一种不太有价值的解决方案,需要花费时间来测量滚动条的宽度。
<script> var checkScrollBars = function(){ var b = $('body'); var normalw = 0; var scrollw = 0; if(b.prop('scrollHeight')>b.height()){ normalw = window.innerWidth; scrollw = normalw - b.width(); $('#container').css({marginRight:'-'+scrollw+'px'}); } } </script> <style> body { overflow-x: hidden; } </style>
与其他解决方案一样,此解决方案将永久禁用水平滚动条。