这篇文章发布于 2015年01月25日,星期日,23:08,归类于 CSS相关。 阅读 208268 次, 今日 21 次 71 条评论
by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=4552
补充于2022-01-12
Chrome 浏览器支持了一个新的 CSS 属性 scrollbar-gutter
专门解决此问题,详见这篇文章。
一、水平居中布局与滚动条跳动的千年难题
当前web届,绝大多数的页面间布局都是水平居中布局,主体定个宽度,然后margin: 0 auto
的节奏~
例如,妇女之友大淘宝的首页:
然而,这种布局有一个存在一个影响用户体验的隐患。应该都知道,现代浏览器滚动条默认是overflow:auto
类型的,也就是如果尺寸不足一屏,没有滚动条;超出,出现滚动条。于是,问题来了:
- 信息流页面,如新浪微博,是从上往下push渲染的。开始只有头部一些信息加载,此时页面高度有限,没有滚动条;然后,更多内容显示,滚动条出现,占据可用宽度,
margin: 0 auto
主体元素自然会做偏移——跳动产生。 - JS交互,本来默认页面高度不足一屏,结果点击了个“加载更多”,内容超过一屏,滚动条出现,页面主体就会左侧跳动。
- 结构类似几个页面通过头部的水平导航刷新切换,结果有的页面有滚动条,有的没有。造成的结果就是,导航尼玛怎么跳来跳去!
当前优化这种体验问题,一般有两种解决方法:
- 高度尺寸不确定的,例如,新浪微博,使用:
body { overflow-y: scroll; }
- 高度确定的,例如淘宝网首页。使用CSS把页面尺寸布局骨架搭好,再在里面吐数据。于是,要么没有滚动条,要么滚动条直接出现。不会出现跳动。
然而,然而,后面的策略只适合一些特殊的定制性很强的页面。你说像知乎这样子,高度随内容而定的页面,显然就无法驾驭;而第1种方法overflow-y: scroll
,在页面高度较小的时候,依然会保留一个丑陋的灰色的滚动栏,这其实又回到了IE当道的旧社会时代。现代浏览器做的那些默认视觉优化岂不是白费了,想想就好痛心。
大师,难道就没有一了百了、两全其美、三生有幸的方法了吗?
阿弥陀佛,骚年,请看我手中的这盏灯……
二、CSS3计算calc和vw单位巧妙实现滚动条出现页面不跳动
很简单,只要一行代码就搞定了:
.wrap-outer { margin-left: calc(100vw - 100%); }
或者:
.wrap-outer { padding-left: calc(100vw - 100%); }
然后就可以庆祝放鞭炮啦!!
首先,.wrap-outer
指的是居中定宽主体的父级,如果没有,创建一个(使用主体也是可以实现类似效果,不过本着宽度分离原则,不推荐);
然后,calc
是CSS3中的计算,IE10+浏览器支持,IE9浏览器基本支持(不能用在background-position
上);
最后,100vw
相对于浏览器的window.innerWidth
,是浏览器的内部宽度,注意,滚动条宽度也计算在内!而100%
是可用宽度,是不含滚动条的宽度。
于是,calc(100vw - 100%)
就是浏览器滚动条的宽度大小(如果有,如果没有滚动条则是0
)!左右都有一个滚动条宽度(或都是0
)被占用,主体内容就可以永远居中浏览器啦,从而没有任何跳动!
您可以狠狠地点击这里(IE10+):页面出现滚动条的时候没有跳动demo
demo页面中,标题和下面的妹子都是居中效果。其中,妹子做了本文所述的“滚动无跳动”处理,而标题没有,结果,你会发现,滚动条出现与否会让标题文字跳动,但是,妹子却女神般岿然不动:
兼容性
支持:IE9+以及其他现代浏览器。
窄屏幕宽度下的处理
上面CSS还是有一点瑕疵的,浏览器宽度比较小的时候,左侧留的白明显与右边多,说不定会显得有点傻。此时,可能需要做点响应式处理会更好一点:
@media screen and (min-width: 1150px) { .wrap-outer { margin-left: calc(100vw - 100%); } }
更新于2016年9月28日
经过一些列项目实践,关于浏览器出现滚动条和消失页面不滚动有了更加终极的解决方案,经过大型项目实践已经验证相当具有可行性,这里特意分享下:
html { overflow-y: scroll; } :root { overflow-y: auto; overflow-x: hidden; } :root body { position: absolute; } body { width: 100vw; overflow: hidden; }
大家随意取走,不用谢!
三、结束语
本文参考自:Fix ‘jumping scrollbar’ issue using only CSS
说点八卦吧,本文原作者名叫Ayke van Laëthem, 才开始写博客,就是因为写了这篇文章,搞掉了他1G的带宽流量,文章至少访问了15,000次,着实被吓着了,还是蛮搞的!哈哈!
如果你也有精彩创意且使用的前端tips, 不妨也拿出来共享下,会有很多意外的收获与成长的。
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:http://www.zhangxinxu.com/wordpress/?p=4552
(本篇完)
- 小tip: IE下zoom或Matrix矩阵滤镜中心点变换实现 (0.272)
- 如何使用JS检测用户是否缩放了页面? (0.272)
- 视区相关单位vw, vh..简介以及可实际应用场景 (0.190)
- 等宽字体在web布局中应用以及CSS3 ch单位嘿嘿 (0.186)
- CSS流体(自适应)布局下宽度分离原则 (0.181)
- 聊聊CSS世界中的margin-box (0.181)
- 基于vw等viewport视区单位配合rem响应式排版和布局 (0.114)
- 理解SVG viewport,viewBox,preserveAspectRatio缩放 (0.109)
- CSS值类型文档大全 (0.109)
- CSS百分比padding实现比例固定图片自适应布局 (0.078)
- 贝塞尔曲线与CSS3动画、SVG和canvas的基情 (RANDOM - 0.004)
overflow: hidden; 会导致 position: sticky; 失效。
overflow: hidden;
会导致部分元素,比如下拉列表不显示了
怎么让页面内一个普通div的滚动条,不抖动,一个普通div用不了100vw
试试scrollbar-gutter属性:https://www.zhangxinxu.com/wordpress/2022/01/css-scrollbar-gutter/
前辈,MDN上说,:root表示html元素,除了更高级别之外,与html选择器相同。那对html和root伪类分别设置了overflow-y,有什么意义呢?我不是很理解,希望能得到讲解。
兼容IE8
只考虑 chrome / safari / opera,不考虑 firefox 的话 可以用overflow: overlay 这个实验属性 解一解燃眉之急
macOS 上开发时发现,系统偏好设置将影响滚动条是否占据实际水平空间,通用 > 显示滚动条如果不是为始终,出现滚动条将不占据空间,bodyWidth : 100% = 100vw,不会出现跳动的情况。
旭哥,能否讲一下终极方案的原理
我猜想 :root body 所做的处理就是让body新建一个层,这个层的内容和 滚动条的内容不会相互影响,此时给:root加上滚动样式,可以完成效果
其实就是和别的方案一样先把滚动条的位置留出来(对HTML设置scroll)。因为position的缘故,在下面对body设置width: 100vw;的时候一方面这个100就不是相对整个视窗了;另一方面这时候body已经脱离文档流在一个单独的渲染层中了。如果还不理解可以参考张大之前关于HTML、body关系的文章
css确实博大精深,能够解决很多浏览器体验不好的问题,但是重视的人不多
2016年9月的大神分享的,今天2020年10月依然管用 我是wordpress
真·优质文章
困扰了很久的滚动条抖动问题终于解决了,用的是最新更新的方案。虽然解决了,但原理不是很懂,前端之路对小白来说真是道阻且长。。
所以我才说,CSS真的是门玄学。JS好歹有问题就是有问题,没问题就是没问题。该怎样怎样。CSS真的是又爱又恨,估计也只有张大神才能把它玩弄于鼓掌中。
完美解决我的问题哦,谢谢
这样写的话,弹框下的页面页可以滚动啦~
用了一个比较贱贱的方法来解决了当网站缩小时,横向滚动条没有显示
@media screen and (min-width: 1040px) {
:root {
overflow-x: hidden;
}
body {
overflow: hidden;
}
}
html {
overflow-y: scroll;
}
:root {
overflow-y: auto;
}
:root body {
position: absolute;
}
body {
width: 100vw;
}
.wrap-outer {
padding-left: calc(100vw – 100%);
}
这个方案有什么缺陷吗
有个bug,当网站缩小时,横向滚动条没有显示,请问一下怎么解决???
终极方案会使横向滚动条失效,当窗体缩小的时候,如果中间容器有最小宽度的话,无法左右滚动看全所有内容
查了下:root是选择器指html,那么
html {
overflow-y: scroll;
}
不是会被
:root {
overflow-y: auto; //被这句覆盖?为什么要一起写呢?
overflow-x: hidden;
}
后面倒感觉理解一点,body设置width:100vw是为了让body撑满整个页面包括滚动条宽度,这样出现滚动条也不会让页面内容向左跳动,而:root body定位本来不能理解后来试了一下是为了解决当body设置width:100vw造成页面内容足够宽而被滚动条遮挡的问题。
看到下面评论360不支持的,碰到这种好多人在用的个别浏览器我们该怎么办呢?
:root 和 html 的支持版本不一样,概念其实也有区别,这里应该就是考虑到兼容性问题
在 Bootstrap3 中,弹出模态框 Modal,手动拉伸浏览器高度,滚动条出现不抖动。
但是当模态框里面的内容改变引起的高度变化,则会抖动。
Bootstrap 实现上是计算滚动条宽度,然后给 body 设置 overflow:hidden; padding-right: 17px;(滚动条宽度),以此保证 body 内容不滚动。
但是弹出层是 fixed 全屏覆盖的,里面是滚动 auto
因为 body 上设置了 overflow:hidden,导致计算为 0;
抖的好蛋疼..
有兴趣的看看
http://v3.bootcss.com/javascript/#动态实例
我想到一个新方法,既然中间部分是左右居中的,为什么不使用:
margin-left: 50vw;
transform: translateX(-50%);
这样可以不需要关心父级的滚动条
:root 是什么呢
如果主体部分设置了最小宽度比如:1200px,终极解决方案不会出现水平滚动条,而vw方案,在1250-1150的范围内还是会发生跳动,求大神解疑
当position:fixed的时候,终极代码就不起作用了。求解
类似
left:100%; margin-left:-200px
? 或者不设置left
和right
属性进行定位。程序猿之宝,张大婶
最终解决方案里为何要加body绝对定位呢?
:root body {
position: absolute;
}
+1 我也想问下
这样可以overflow:hidden任意元素(除了fixed元素)
太感动了,,找了那么久终于找到了完美解决方案,,感动哭,,从此以后你是我偶像~~~~
厉害啊,大赞一个!
终极解决方案可用,已收藏
更新于2016年9月28日 可用
亲,表格出现滚动条的时候,不影响表格内容的宽度应该怎么写呢??
还有另外一种解决思路,http://blog.w3cedu.net/chenhao/blog/2016-11-30/51.html
根据2016年9月28日更新,我写了一个demo,从demo得知,页面在没有滚动条时,工作很好,当页面出现滚动条时,靠右对齐的内容会被滚动条挡住,求教博主这样的缺陷你们是如何修复的呢?
或者是我的例子有问题?
相关demo可点击查看:https://jsfiddle.net/c32wswzL/
在开发者工具中尝试收缩页面高度,当 result 部分出现滚动条会遮挡靠右对齐的文字内容。
期待您的回复。
一般网页都会在左右留有一点的间隙的。
后面想明白了,感谢您的回复!
之所以会这么问,是刚好有个后台管理的页面,宽度100%的,也有类似的滚动条有无时候页面跳动的问题,所以想这么用一下。
我觉得针对这种问题,可能最好的方案就是垂直滚动条始终显示。
解决思路,http://blog.w3cedu.net/chenhao/blog/2016-11-30/51.html
水平滚动条跳动问题修复
这里确定是padding-left,而不是padding-right吗
你的方法我试了下,特定的情况的确可行,可是有些情况下,就没有效果了;
我一直用的方法都是直接在body加上width:100vw就解决任何情况下这个跳动的问题了,我不知道是不是我这个方法有什么缺陷,还是什么,就是没人用过这方法,所以咨询你一下
还好我看到你的评论了
这样主体内容并不是水平居中啊
你这样不会出现横向滚动条?不过上述方法,其实并不居中啊
padding-left: calc((100vw – 100%)/2);
padding-left: -webkit-calc((100vw – 100%)/2);
padding-right: calc((100vw – 100%)/2);
padding-right: -webkit-calc((100vw – 100%)/2);
这样就能居中了,而且不用考虑窄屏的问题
额。这样不行,搞错了
还是得用响应式布局吧,宽屏的时候用这句
看到有人抄你的文章,而且,图片都不带换的,呵呵哒http://blogread.cn/it/article/7377?f=wb
张大大,您好,刚看了这个例子,但我的总是达不到这个效果,不知道怎么回事
然后效果http://codepen.io/bmxklYzj/pen/VabqEv
这个在最外面加一层。
然后把样式加在wrap上面就行。
.wrap {padding-left: calc(100vw – 100%);}
或者
.wrap {margin-left: calc(100vw – 100%);}
为什么在demo中给main加上margin-left: calc(100vw – 100%);还是会跳动呢?
margin-left: -webkit-calc(100vw – 100%);
margin-left: calc(100vw – 100%);
原理:vw是浏览器视口的宽度,包括滚动条,100%是不包括滚动条的视口宽度。
这样如果有滚动条,两者之差就是滚动条的宽度;margin-left一个向左滚动条的宽度,让两边都有一个滚动条宽度。
如果没有滚动条,两者之差就是0
优点:纯css3实现,简洁高效。
缺点:IE10以下无效,设计图如果有背景会存在问题,因为有margin-left存在。
主体需要定最小宽度时还是会跳动
LZ写多一个适用浏览器或者浏览器实测就会更加好了!
mac 下貌似滚动条不会影响页面的宽度 发现标题也没有出现跳动 safari 和chrome 都看过了
是啊,我也发现了,一开始会跳,后来不管有没有设置都不会跳的
GG浏览器 依然抖动中
美女还是抖动了,浏览器为360版本7.1.1.556,内核版本31.0
不晃动的文字完全被遮挡,根本看不到是否跳动了.
刚好用到~谢谢张老师
demo里还是抖动了呀
chrome33 linux
1366*768
@双 你好,是妹子抖动吗?为了有对比,标题文字没处理,所以是抖动的;妹子处理,所以处变不惊。
感人,哈哈
感觉应该是 margin-right: calc(100vw – 100%);
感觉有问题啊,demo里还是有偏移的
你一定没仔细看…
自荐一篇文章,补充 JS 来检测滚动条宽度避免页面偏振的方法: http://yujiangshui.com/review-how-to-make-popup-mask-effect/#去掉滚动条但是避免页面内容偏移