本篇文章翻译自The fifth position value,是关于移动端中的定位元素 fixed 的值的问题。这里只做部分翻译。前言省略,只是讲述关于浏览器产商历史及 fixed 在桌面和移动端的差异性问题。

fixed 元素统称为绝对定位元素。

position: fixed

引用自 CSS2.1 的规范:

绝对定位是 绝对定位的一个子类。唯一的区别是 fixed 定位是相对于视口的定位。在连续的媒体文档中,fixed 定位的盒子不会随着文档滚动。从这方面上看他们更像是固定的背景图片。

规范和移动端的实际情况分歧越来越大。「fixed 定位的元素没有随着文档流动」被大多数的移动端浏览器所忽略。规范忽略了缩放功能。

什么是视口?在桌面浏览器中是浏览器窗口,这样 fixed 元素会相对于窗口定位当文档滚动的时候不会滚动。我们需要在移动浏览器中也实现。

然而移动浏览器有两个视口:视觉视口和布局视口。浏览器应该相对于哪个视口来定位元素呢?

没有人会感到奇怪如果这是视不同的浏览器而定的。大多数的浏览器会相对于布局视口(layout viewport)。只有诺基亚 Webkit 内核浏览器不是这样的。可以在这个页面测试.也可以在兼容表中查看。

视觉视口

当你为 fixed 元素写bottom: 0的样式的时候你就可以更好地看出两种定位方案的区别了。它是被相对定位在盒子的底部。

以下是绝对定位元素相对于视觉视口:

绝对定位元素会像桌面端一样当页面滚动的时候保持不动。

虽然这是移动浏览器是很大程度上受到了桌面浏览器的上绝对定位元素的影响,但是在大多数移动浏览器上只有 Nokia WebKit 实现了但是并不是在所有的情况下都是这样的效果。之前讨论过,桌面端的绝对定位元素相对于最小的视觉窗口并不适用于移动浏览器。

当用户缩放的时候会发生什么?Nokia N8 移除了整个的绝对定位元素。这并不是最好的行为。那么应该去如何展现呢?文档上没说,浏览器也不知道如何去处理。

布局视口

其它浏览器尤其是 iOS 上的 Safari,把元素相对于布局视口定位随着文档滚动。这样他们就忽略了文档的最重要的关于绝对定位元素的定义。

(从本质上来说这样导致position: fixed元素和position: absolute都是是相对于布局视口的,如果position: absolute没有祖先元素是position: realtive定位的,打开测试页面来观察。

绝对定位元素设置为bottom: 0会被放置在布局视口的底部,随着页面滚动。这样他的固定的本质就丢失了,但是是因为它和页面的剩余部分一起滚动和缩放这样就可读性仍然是非常强的。

这个方案也不是完美的。绝对元素也许会覆盖住重要的页面内容。设计师们确定absolute元素不可以覆盖任何元素,但是他们可能会忽略掉绝对定位元素因为他们假设用户始终可以滚动一段距离来看元素。如果滚动元素随着页面滚动,那么在滚动元素下的内容将永远不可能被看到。

hopping(跳跃)

其它浏览器尤其是 Opera 和 黑莓 WebKit 浏览器,试图融合这两种技术。初始化的时候会相对于布局窗口定位元素,但是当用户滚动元素的时候会让元素跳到到相对于目前视觉视口的底部。当用户再次滚动的时候又会保持在视觉视口的底部。

问题是这个跳跃只发生在用户停止滚动半秒之后。这个效果会非常的让人奇怪,在用户没有做出任何命令的时候,绝对定位元素发生了变化。(这里的命令指的是滚动,但是对于大多数普通用户来说可能是不起眼的)。这就解决了绝对元素覆盖住重要信息的问题了。

缩放怎么办?Opera 移动浏览器表现是最为合理的:当用户放大的时候,绝对定位的元素没有改变其位置。这样用户就可以观察于是它。只有当用户再次缩小的时候,它才会跳跃。

与此相反,黑莓 WebKit 以复杂的方法试图让元素保持在视力中,但是这个效果很有问题。有时候元素直接消失了,有时候会偏离定位几个像素。然后结果导致绝对定位的元素的内容溢出并且变得不可读。

其它发现

安卓就很诡异了。Nexus One 2.2 使用布局视口方案,但是 HTC Legend 2.1 使用 hopping(跳跃)方案(有问题)。我不知道是不是 2.2 和 2.1 版本的问题还是谷哥和 HTC 的差别。

Samsung Dolfin, Android WebKit, Nokia WebKit 当页面中有<meta viewport>的时候会改变对于绝对定位元素的行为。Nexus One 实现真实的绝对定位(即相对于视觉视口)当你写上<meta name="viewport" content="width=device-width, user-scalable=no" />,换种说法即如果你不想要优秀的 UI 交互的话。

position: device-fixed

两种方案都并不特别地完美。相应地,不妨给出定位的第五个属性device-fixed。这样就可以用来一劳永逸地解决最大的问题。

如果移动浏览器支持device-fixed并且桌面端不支持,开发者就可以为其中之一创建绝对定位的方案。

定义

position: device-fixed即像是真实的绝对定位元素相对于视觉视口。无论用户滚动或者缩放都不会改变位置。

另外,device-fixed元素和其后代元素使用的CSS 像素单位不是 CSS 像素而是物理设备像素(或者如果设备实现了即逻辑像素)。可见这里查看三种像素。

本质上说这样就会让device-fixed元素不可缩放。缩放对于device-fixed元素是没有任何意义的因为这会使里面的内容溢出并且不可读。

不可缩放是最重要的。不然将和绝对定位元素一样。

示例

可以用 Safari 和 黑莓 WebKit 来浏览示例,因为只有这些 浏览器暴露了视觉视口和布局视口的分辨率,这样就可以用来计算缩放倍数。

支持

这里是假设桌面浏览器不支持device-fixed,移动端浏览器不支持fixed。这样开发者就可以使用fixeddevice-fixed这两种效果,确保桌面浏览器和移动浏览器只会对一种样式起效果。

如果桌面浏览器使用device-fixed或者移动浏览器使用fixed呢?那将不会是绝对定位的元素,应该隐藏还是让其像页面一般的块级元素呢?

老的黑莓浏览器完全隐藏。平板浏览器支持fixeddevice-fixed吗?目前尚不可知。

讨论

事实上device-fixed处理了一种可以被目前的关于定位的定义的规范处理的例子而反对这个device-fixed的定义。虽然规范没有定义缩放而导致规范不完整。

开发仍然是需要这个真实的绝对定位属性的。与此同时,移动浏览器产商是不会实现这个真实的绝对定位提案的。

device-fixed提供了解决这个方案的方式。首先这是实验性的属性。我理解关于这个提议是不合理的观点。

结论

有一点是确定的是没有position: device-fixed属性或者类似的方案在移动并不是真正的绝对定位。

思考

在实际工作过程中会遇到 ios 的fixed问题,即当在页面的底部是 fixed 元素的时候,元素里面有 input 框的时候,当点击输入框输入法会遮盖住输入框,通过上面的学习和这个文档可知当输入法弹出的时候,由于绝对定位元素是相对于布局视口定位的所以这个时候输入法会遮盖住绝对定位的元素。因为 ios 中当输入法弹出的时候,布局视口并没有滚动,而 ios 中绝对定位元素是相对于 layout viewport(布局视口)来定位,会随着布局视口的滚动而滚动的。这里的解决方案就是可以把元素设置为绝对定位或者滚动窗口即可。不知道是不是这个理?^。^