前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >zoom 和 transform: scale(x)

zoom 和 transform: scale(x)

原创
作者头像
kmokidd
发布2019-04-15 16:50:55
2K0
发布2019-04-15 16:50:55
举报

- 2015年的老文,搬运存档用 -

在做企鹅 FM 鬼节活动页面(请扫二维码~)的时候,需要兼容不同分辨率的屏幕。

一般设计师给到UI工程师的设计稿是基于 iPhone6 的,也就是说我们一般会先按照 375x667 的分辨率来定位页面上的元素。一开始在做活动页面的时候,我是很担心兼容问题的:一个元素基本靠 position 定位的页面,到底要怎么在 iPhone4 上还能不遮挡到位于页面底部的按钮呢?路过的同事教给了我 zoom 大法,还有 scale 大法。嗯,所以这篇文章就是来讨论一下 zoom 和 transform: scale(x) 的。

搜了一下,km 上有玩转HTML5移动页面前沿穿越 -- 视差滚动 经验&总结分享两篇分享提到了如何使用 zoom 和 scale 实现兼容,不过对于原理方面我还是摸不着头脑,总把两个概念混淆,决定要好好研究看,于是就有了这篇文章啦。

zoom 和 scale 的区别

先来看一下 zoom 和 scale 的说明:

Specifies the initial zoom factor for the window or viewing area. This is a magnifying glass type of zoom. Interactively changing the zoom factor from the initial zoom factor does not affect the size of the initial or the actual viewport.

从定义上看 zoom 缩放的是被 zoom 的容器的视口,可以把它想象成放大镜的效果,这个属性是可以继承的(inherited),所以我们做设备屏幕兼容的时候,可以在 body 标签下加一个 div 包裹住页面上的其他元素,然后在这个 div 上加 zoom,达到的视觉效果就是页面上其他元素也被缩放了。但是有些元素并不支持 zoom。

A two-dimensional transformation is applied to the coordinate system an element renders in through the ‘transform’ property. This property contains a list of transform functions. The final transformation value for a coordinate system is obtained by converting each function in the list to its corresponding matrix (either defined in this specification or by reference to the SVG specification), then multiplying the matrices.

在说 scale 应该要先看看 transform。transform 属性应用到元素的过程其实是矩阵变换的过程,在渲染的时候,元素的坐标就会被确定下来,然后和 transform 的属性值进行矩阵运算(rotate,translate,scale,skew 都是变形矩阵)得到最终的坐标(不过你会发现,一个元素如果是绝对定位,然后通过 transform 改变了它的显示位置,审查元素时,这个元素的 tbrl 值并不会被更新),且 transform 属性不可继承的。

The value of the transform property is a list of applied in the order provided. … specifies a scale operation using the [sx,1] scaling vector, where sx is given as the parameter. … specifies a scale operation using the [1,sy] scaling vector, where sy is given as the parameter.

scale 是 transform 的一个属性值,这是一个缩放矩阵。当一个元素被定义了 transfrom: scale(x); 后,还是再结合它的 transfrom-origin,才能确定最后的缩放效果。依然是兼容屏幕分辨率的问题,要想 transfrom: scale(x) 达到和 zoom 相似的效果,要记得把 transfrom-origin 设置成 0 0,之所以这么设置,是因为在文档流中的元素,是以它的左上角为中心,进行 zoom 的(当元素脱离文档流时,要使 transform: scale(x) 和 zoom 达到相同的效果,还要具体分析 transform-origin 要如何设置)。

大概你也注意到了,在前一句中,我说的是“相似的效果”而不用“一样的效果”,这是因为使用 scale 的时候可能遇到下面这样的问题(左图为 scale,右图为 zoom,两者的缩放值都是 0.85):

下面这段是外层容器的样式,背景是定义在 switch-wh 动画中,通过绝对定位让浏览器自行计算,保证容器大小占满整个屏幕:

代码语言:javascript
复制
.sf-index{
  overflow: hidden;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 0;

  -webkit-animation: switch-wh 400ms linear 2 forwards;
  -o-animation: switch-wh 400ms linear 2 forwards;
  animation: switch-wh 400ms linear 2 forwards;
}

因为 zoom 是作用在 body 下面这个占满了屏幕空间的容器,所以根据定义以及 zoom 的继承性,我们可以说在这个页面上使用 zoom 其实是缩放了整个屏幕(也就是视口),可以想象成在浏览器中打开了页面,然后放大这个页面的效果:

为什么 scale 会留下那两块迷の白色呢?让我们回到 transform 的定义中,“applied to the coordinate system an element renders in through the ‘transform’ property”。当元素都进行渲染了,坐标已经确定了,再进行缩放,也就是在原来元素基础上改变大小。所以 .sf-index 虽然在渲染时四个角的位置分别是(0,0)、(100%,0)、(0,100%)、(100%, 100%),经过以 (0,0) 为变换中心的 scale,就变成了(0,0)、(85%,0)、(0,85%)、(85%,85%)。我们就会看到页面右边出现宽度为15%的一条白边,以及页面下方高度为15%的白边。

好像 zoom 无敌了呢

看起来,好像兼容的时候应该用 zoom 呢。嗯看到 scale 之后的结果我就是这么想的。接着就发现 zoom 之后的页面,文字似乎怪怪的(左边是被 zoom 的 iPhone4,右边是没有被 zoom 的 iPhone6):

由于页面是被整体缩放了,所以文字也自然出现了缩放,刚好这种好像被砍了一刀的文字效果还蛮适合鬼节的活动页面,所以我并没有做处理。正常来说,如果需要做处理就是调整文字的 line-height 和容器的 height,使其不出现遮挡。

正如页面元素经过 zoom 后,实际的大小会发生改变,图片的大小也发生了改变,使用雪碧图就出现了一些问题。雪碧图是把各种小图拼合到一张大图上面,通过 width、height 和 background-position 定位到图片,看下图可以发现相邻图片的边界也一起显示出来了。

审查元素发现,用于显示图片的元素尺寸也不对啊:

可以看出这个元素正确的尺寸应该是 198x52,经过 zoom 放大后(这个页面是 iPhone 6+ 的,zoom 值为 1.10)容器反而变小了,后来将 zoom 值调整到 1.104(414/375),图片的边界问题算是解决了。

关于图片没有正常显示的问题,我的推断是,原因在于 zoom 值设定偏小,图片经过 zoom 后没有被正确地计算,而图片的容器又偏大,所以相邻图片的边就被显示了出来。后来 zoom 值是根据比例设定了,就不会出现这个问题。

但是页面明明是放大的,容器尺寸却变小的问题,还没有找到原因。

最后,zoom 对性能不友好,下面两个 gif 分别是 zoom 和 scale 引起的重绘(第一张是 zoom,第二张是 scale):

很明显,在文档流中 zoom 加在任意一个元素上都会引起一整个页面的重新渲染,而 scale 只是在当前的元素上重绘。

还有没有更好的兼容方法呢

这样说来,简直两个方法都不能用了嘛…还有没有什么别的兼容的方法呢?

像需要大量图片的页面,做兼容的时候我们常常担心的是什么?当然是图片比例出问题咯,所以也会使用通过伪元素设置 padding-top 的方法,保证图片比例正常地显示出来。只是这样的写法通常要结合 background-size:cover; 而我们常用的工具 CssGaga 在生成雪碧图了之后会覆盖 background-size。目前的这个方案的话……就不合成雪碧图了。

还有一个方案是使用 media query 结合 rem (或者百分比)完成这样的布局,不过目前 gaga 不支持 background-size 的 rem,所以要采用什么方式合成雪碧图以及如何生成新的样式,还需要寻找新的方向。在不需要合成雪碧图的时候,可以用这两种方法。

以上就是这次关于 zoom 和 scale 的分析和思考,如有不对请不吝指出,拜谢 _|\○

参考资料

  1. What’s the difference between “Zoom” and “Scale” in GIMP?
  2. zoom
  3. Zoom versus -transform scale
  4. Zoom Vs. Scale in CSS3
  5. The ‘zoom’ property
  6. CSS 2D Transforms

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • zoom 和 scale 的区别
  • 好像 zoom 无敌了呢
  • 还有没有更好的兼容方法呢
  • 参考资料
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档