浅议内滚动布局

zhang xinxu

一、什么是内滚动布局?

所谓“内滚动布局”,顾名思义就是主滚动条在页面内部的布局,是相对于传统的<html>滚动而言的,例如,下图所示滚动条,是从头部下方开始:

内滚动示意

传统的页面滚动,基本上是相对于整个浏览器窗体,例如,QQ视频首页:

通常滚动示意

二、为什么会有内滚动布局?

随着显示器设备越大越宽越密,以及现代web技术的发展。web站点已经开始有了从传统的瀑布式网页向类桌面软件风格站点转变的趋势。比方说,QQ音乐的首页目前是这样子的:

QQ音乐首页截图

以后可能就会变成这样子:

QQ音乐软件截图

“纳尼,这不就是现在的QQ音乐软件界面截图?”“这位同学眼神很犀利,没错,这就是有着全国最大的正版高质量乐库的QQ音乐PC版截图”。

我们可以局部放大,会发现,是个实打实的内滚动布局。

QQ音乐PC软件内滚动截图

不仅是QQ音乐,其他很多桌面软件都是这种内滚动布局,比方说QQ软件管家等等。

QQ软件管家内滚动截图

有此可见,一旦强交互的传统web页面桌面软件化,内滚动布局是绕不开的一堵墙,了解之还是很有必要的。

三、如何实现内滚动布局?

既然是内滚动,就有必要干掉浏览器原生<html>的滚动条,这个很简单:

html { overflow: hidden; }

“然后呢?”我想了想,好像然后就没有“然后”了,让一个div容器滚动就完事了。

然而,事非经过不知难,原理虽然简单没说头,但是细节操作还是有些上手成本的。

为了更好理解,我们拿实例说话。最近半年一直在参与企业QQ账户中心改版的项目,你可以看成是企业后台管理系统。这里有几个关键字,一是企业,二是管理系统

1. 企业

这里为什么要强调是“企业”呢?因为企业产品的用户一般都是购买了企业QQ产品的企业的员工,有一定IT技能的人。因此,用户的浏览器的现代感就比Qzone用户强不少。下图为同事在2015-05-20这个爱意满满的日子拉的userAgent数据:

企业QQ用户浏览器数据

如果我们将支持CSS3 animation的浏览器称之为现代浏览器,可以发现,企业产品的用户,70%~80%的用户都是使用的现代浏览器。亲们,近8成的用户都是使用现代浏览器,这就意味着,企业产品其实可以作为现代web技术的试验田,在为用户提供更好体验更高质量产品的同时,为日后其他产品的现代化改造提供了宝贵的借鉴经验。而本文的内滚动布局,就是万千经验中的一小个。

2. 管理系统

“管理系统”意味着站点以强交互为主,会有很多类似办公软件的交互操作在里面。如果是更偏重浏览的站点,例如企业QQ官网,显然,传统的垂直瀑布式的网站是更适合的,滚动浏览,再滚动,再浏览。但是,企业管理系统如此庞大,操作如此频繁,交互如此之多,传统的上下式网站显然很难让用户用得非常得心应手。下图为以前企业QQ账户中心组织结构页面(测试页面)的真容:

旧企业账户中心组织架构页面

看着此页面,立马让我想起了6年前刚毕业那会的青葱岁月,那时候的页面的基本上就是这样的调调,小小的空间里有着小小的世界。时代发展,再辉煌的过去,如果没有改变,终将会被埋汰。

正是由于以上两点,设计师设计的时候,大胆创新,设计成了全屏自适应半响应类PC软件风格(内滚动)的管理站点,下图为上面老页面同样数据的新测试页面截图:

新企业账户中心成员与权限页面

回到内滚动布局本身。

新版企业账户中心全站,顶部以及左侧固定,不跟随滚动,右侧主体内滚动,如何实现呢?

由于企业产品不用管0.4%的IE6用户,因此,事件就变得简单地多了。我们可以利用绝对定位元素的拉伸特性,使内滚动容器高度自适应匹配。HTML主结构示意如下:

body
 -- page
    -- header
    -- side
    -- content

其中page扮演传统页面<body>的角色。这是一个预留设计,防止为了满足某些功能或交互体验需要,一个页面同时出现多个类似结构页面的情况。或者这么说吧,把所有页面内容放在一个page中,此时page就好比一个可以移动的房子,回头你跳槽来腾讯了,房子可以一起带过来,原来的位置可以被其他房子代替。但是,你如果直接放在<body>中,由于<body>只能是一个,不动产,此时想要做整体迁移,难度就较大,同时项目几乎成型,全局修改成本高高风险大。不过凡事都有两面性,这样的折腾可以减少你白头发的数目,因为你会因操劳过度头发直接脱掉的。

page相关CSS如下:

.page { position: absolute; top: 0; right: 0; bottom: 0; left: 0; }

应该很好理解,绝对定位,满屏拉伸,等同于:

.page { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }

由于省了好几个字节,所以我舍弃了IE6使用了上面写法。

对于固定的头部header或者固定的侧边side, 你可以使用语义明确的position:fixed定位,或者直接使用position:absolute,因为滚动容器跟他们平级,所以,absolute其实就是fixed效果。

讲到这里就不得不说点题外话,很多人会遇到移动端position:fixed的底部输入框定位的头疼问题,如何解决?就是使用本文介绍的内滚动布局,然后底部使用position:absolute模拟fixed效果。

代码方面,同样就是拉伸拉伸:

.header { height: 62px; position: absolute; top: 0; right: 0; left: 0; }
.side { width: 200px; position: absolute; top: 62px; bottom: 0; left: 0; }

最后就是高能的content, 还是一样的套路:

.content { position: absolute; top: 62px; right: 0; bottom: 0; left: 200px; overflow: auto; }

主体内容全部都在content里面玩耍。于是,一个高宽均自适应浏览器窗体的内滚动布局就成型了。

四、内滚动布局的赏与罚

我们站在上帝视角审视一下内滚动布局,本质上就是滚动容器的迁移,职能下发。所以绝大部分情况下,跟我们平常玩转页面的路数没什么区别。

但是,毕竟江山易主,差异还是存在的。最简单的例子就是对滚动事件的影响。很多滚动插件,包括以前的脚本,我们可能都是这么写的:

$(window).scroll(function() {
    // 跟我一起翻滚吧,骚年……
});

但是,在内滚动布局下,由于滚动的容器不是window窗体,不是<html>元素,因此,上面滚动事件八辈子都不会执行。我们需要调整,由于现在,页面的主滚动条是.content, 因此,我们可以:

$(".content").scroll(function() {
    // 跟我一起翻滚吧,骚年 again……
});

你以为事情就这么完了吗?太天真了!以前我们的滚动条是跟浏览器上边缘是靠在一起的,但是,自从变成了内滚动,滚动条是跟网站公用头部下边缘排排站,这会造成什么问题呢?就是一些offset的计算要发生一些变化。举个例子,我们希望表格头部操作区域有类似position:sticky效果,也就是视区内一起翻滚,要被滚出去的时候,fixed固定,不跟随。

表格头部操作区域固定

此时,我们的最大滚动高度值,就需要把网站头部的高度考虑进去(传统窗体滚动不需要,因为值是0):

var maxScrollTop = $("#tableHeader").offset().top - $(".header").height();

以上这个,我们可以称之为“变化”,与原本的实现相比无功无过,一种变化一种转移。实际上,内滚动布局还会带来带有质变性质的一些特性。

无法滚动的弹出层

基本上,是个像样的web2.0网站都会有弹框web组件,一个黑色半透明的overlay层,上面摇曳着弹框面板,例如这样的:

弹框示意

对于黑色半透明覆盖层,传统实现是这样的:如果要兼容IE6浏览器,一般是absolute绝对定位,高度由JS计算赋予;如果不需要管IE6, 则可以使用fixed固定定位。

然而,在内滚动布局下,“赏”就出来了,就算需要兼容IE6浏览器,黑色半透明高宽100%自适应覆盖也不需要任何JS计算的帮助,也不需要监听windowresize事件,直接CSS就可以搞定。很简单:

.overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; }

为啥一行CSS就能搞定所有场景?因为使用的是内滚动布局,如下图示意,屏幕就这么高,滚动在里面,自然自适应:

半透明覆盖层原理示意

看上去是内滚动布局带来的一个小小的“赏”,但是,实际上,埋下了一个不小的“罚”。

随意改变滚动容器最大的问题在于,当存在覆盖层的时候,会影响背后页面内容的滚动。

100%尺寸的position:absolute/fixed的覆盖层,会覆盖任何非<html>元素(包括<body>)(包括这些元素的滚动条),因此,只要覆盖+滚动容器改变,页面就无法滚动。

内滚动布局是典型的改变浏览器默认滚动容器的布局,自然覆盖层一出现,就没法滚动。不过这也没什么,对吧,弹框出现时候,页面背景没法滚也挺好的。

但是,麻烦的事情是,如果弹框自身高度很高,却又没法滚动呢(浏览器可用高度700像素,弹框有900像素高)?

传统布局下的弹框,如果高度很高,直接设置弹框容器position:absolute就可以愉快地上下翻滚了。但是,在内滚动布局下,弹框根本就不在滚动容器里面,翻滚一说从何谈起?

大危机!怎么办!?

我们新版企业账户中心就遇到这个问题,我是这么解决的——overlay和dialog合体

合体与滚动

合体是什么意思呢?基本上,90%+的弹框组件,半透明覆盖层overlay和弹框dialog是两个并列的兄弟关系的独立的元素,这种设计的好处在于overlay组件可以复用。实际上,我们要实现一个弹框效果,只要一层div标签就可以了,核心就是使用兼容的RGBA背景色技巧,然后弹框HTML放在里面:

.container {
    position: absolute; top: 0; left: 0; bottom: 0; width: 100%;
    background-color: rgba(0,0,0,.5);
    filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7F000000,endcolorstr=#7F000000);
    overflow: auto;
}
:root .container {
    /* IE9 无 filter */
    filter: none;
}

HTML结构示意如下:

<div class="container">
    <dialog></dialog>
</div>

此时,弹框在一个可滚动的容器之中,妈妈再也不用担心我不能愉快地翻滚了!

五、结束语

由于传统窗体滚动已经深入人心,所以我们可能会觉得内滚动布局似乎有些坑;但是,如果当年是内滚动布局天下,我们又该如何看待新兴的窗体滚动布局呢?然后,从产品的角度讲,内滚动布局在操作如此频繁的重交互项目中所带来的交互体验上的改进,要远比经验不足带来的额外开发成本要大很多很多。

我相信,这种交互形式以及web布局上的创新一定会带来很多正面的反馈和积极的影响,产品即将上线,我们可以拭目以待。

内滚动布局,更现代,更移动,如果您的项目合适,不妨也试试这种看似新颖的布局方式。

感谢阅读,欢迎交流!

Tags: , , ,

zhang xinxu
zhang xinxu
音乐不是你想卖,想卖他就买:提升用户购买欲的设计探索
上一遍
小处显逼格:细节提升气质
下一遍
20,312
QQ空间 新浪微博 Facebook Google+

相关推荐

留下你的想法吧

  1. 感谢分享。不过我觉得,弹窗本身高度很高,以至于需要滚动,这本身就不是一个好的体验。这种时候是不是应该考虑一下,这种设计是否真的合适,这种情况真的应该用弹窗吗?

  2. Carson says:

    好文,关注isux挺久了,加油,支持你们!

  3. echo_kinchao says:

    带着信仰的团队 梦寐以求

  4. ethanchen says:

    这行文不像是zhangxinxu的风格

  5. Eric Poon says:

    不解最大高度的计算机制。
    另外,弹窗为什么不能在dialog内滚动,要将整个dialog滚动?

  6. 潇意 says:

    弹窗太高的话,利用position:absolute; left: 50%; top: 50%; margin-left: -width/2; margin-top: -height/2; 也没有办法避免内容显示不完全的问题,请问大神有什么好的办法吗?

  7. jie4038 says:

    zxx发表在这里的文章,个性收敛了不少

  8. 一直再看张老师的文章,和楼上一件一致。
    是不是因为这篇文章他领导要看,所以不敢骚起来呢?

  9. LSZH says:

    这么严肃真的好吗

  10. riskers says:

    在下个项目里试试

  11. Mask says:

    完全是zhangxinxu的风格啊~ 只是比自己博客上写的正式了不少,但是依然是唠叨话一大堆,不过好玩的也就是这些唠叨话,哈哈!我也表示对于需要滚动的弹框,可能本身就是设计上有什么问题,总觉得哪里不对劲~

  12. flicat says:

    不兼容IE6好多年

  13. 浅眠 says:

    一直不知怎么处理那个滚动条,每次都是跟着不同的浏览器在变效果,丑爆了!本人是新手,能分享下具体的代码(看了还是不懂怎么写)参考下吗?

  14. 请问那个滚动高度用原生js怎么写

  15. chasonma says:

    不像是张老师的风格←_←,说好的卖萌打滚呢2333

  16. Bulandent says:

    没demo差评

  17. zjzhome says:

    在移动端的话, ratchet好像就是body固定然后滚动content, 但我试了下在低端的手机下会有些卡, 不如body滚动顺畅...有什么好的实践么.....

  18. Bulandent says:

    我发现个问题。内滚动布局里的滚动条因为是overflow-y:auto;出来的,就是说在滚动条不滚动的时候是不能像正常滚动条那样隐藏的。这点在app下体验不好。如何解决?

  19. 一线天 says:

    什么时候上线?发个链接学习下。