再谈layout viewport
而对于移动浏览器来说,作者引入了两个viewport的概念,一个layout viewport,是页面排版是参考的大小,另一个是visual viewport,是用户可视的区域,都是以CSS像素为单位。
George Cummins用拿着边框看画的比喻生动地描述了这两个viewport的区别。
其实,我们认为桌面浏览器也可以引入这两个viewport的概念,只是需要加上一个限制条件,桌面浏览器的layout viewport的大小始终和visual viewport的大小相等。但是,visual viewport其实还包含了滚动偏移的信息。
Fix元素的排版
根据前面的介绍,网页排版是以layout viewport的宽度为标准来排版。还是以这个包含蓝色banner条的网页为例,这里蓝条的宽度为width:100%,所以它根据viewport的宽度来排版,在桌面浏览器上viewport的宽度就是窗口的宽度,而这时如果网页在窗口之外还有内容,滚动横向滚动条,就会发现蓝条的宽度固定为窗口的宽度。
那么,如果蓝条的position属性为fixed又会是怎样呢?
从上图中我们发现,position:fixed; width:100%的蓝条判断宽度依旧是窗口的宽度,并且排版的起始坐标也是相对于窗口的,这里我们可以认为fixed元素是以visual layout为参考来排版的,只是对于桌面浏览器来说layout viewport和visual viewport的大小始终是相等的,都等于窗口的大小。
那么对于移动浏览器来说又是怎么样的呢?我们知道无论是旋转屏幕,缩放页面,移动浏览器的layout viewport大小都是固定不变的(width=device-width情况除外),而visual viewport会随着页面的缩放,屏幕旋转和滚动发生变化。
于是,我们就会发现移动浏览器上fixed元素和其它元素的排版宽度不一致的现象。我用Ipad上的Safari测试如下页面:
<head>
<style>
body {
height:2000px;
}
div#overflow {
width:2000px;
height:50px;
}
div#relative {
width:100%;
height:50px;
background-color:green;
}
div#fix {
width:100%;
height:40px;
top:200px;
left:0px;
background-color:yellow;
position:fixed;
text-align:center;
}
div#fix div {
width:100px;
height:40px;
background-color:blue;
position:relative;
display:inline-block;
}
</style>
</head>
<body>
<div id="overflow">
</div>
<div id="relative">
</div>
<div id="fix">
<div>
</div>
</div>
</div>
</body>
</html>
其中,绿条是position:static的元素,它的宽度为width:100%;黄条是position:fixed的元素,它的宽度也是width:100%,并且在它下面放了一个居中的蓝色方块。
当缩放比例为1时,layout viewport和visual viewport相等,两个元素排版的宽度也是一样:
此时window.innerWidth = document.documentElement.clientWidth
而缩小页面时,layout viewport保持不变,visual viewport变小。这时,页面的排版结果就变成了如下样子:
此时window.innerWidth > document.documentElement.clientWidth
可以看到,position:fixed元素排版是以visual viewport为标准,而其它元素排版时是以layout viewport为标准。
从w3c上fixed元素的定义也可以看出,fixed元素的排版应该是相对于这里提到的visual viewport概念:
Fixed positioning is really just a specialized form of absolute positioning; elements with fixed positioning are fixed relative to the viewport/browser window rather than the containing element; even if the page is scrolled, they stay in exactly the same position inside the browser window.