使用top/left/margin和CSS3 translate两种方法实现标题居中的性能差异详解

techbrood 发表于 2016-05-19 14:51:25

标签: css3, center, performance, 渲染引擎

- +

要实现标题全屏居中(同时在垂直和水平方向居中),有若干种方法,包括使用弹性布局、表格单元、绝对定位、自动外边距和CSS3平移变换等。

你可能已经使用了这些方法,但很可能没有意识到性能上的差别,因为这涉及到浏览器渲染引擎的一些幕后的工作原理。

使用top/left和margin来居中

其中目前比较流行也比较容易理解的方法是使用绝对定位+外边距实现。也就是分两步来把元素居中:

1. 第一步通过top/left先把元素放在离视口左上角(坐标原点)50%视口宽和50%视口高的地方;

2. 第二步通过margin把元素反向偏移其自身宽高的50%。

html,body{background: #333;height:100%; width:100%;margin:0;padding:0;}  
h1 {  
    margin-left: -200px;  
    margin-top: -35px;/* h1元素边框的高度一半: (30px+20px*2)/2 */  
    color: white;  
    width: 400px;  
    height: 30px;  
    text-align: center;  
    position: absolute;  
    left: 50%;  
    top: 50%;  
    padding: 20px 0;  
    border: 1px solid #666;  
}

上述代码使用绝对定位,top: 50%, left: 50%完成第一步,margin-left和margin-top完成第二步。

注意标题元素宽度使用百分比,可在水平方向自适应屏幕宽度。最好设置下min-width,以免屏幕过小时,标题文本溢出。

这样的代码是可以工作的。但是吹毛求疵的话,代码的性能并不好。当然在这种简单用例下不太会被暴露出来。

但是如果你想给这个标题添加一些动画效果,比如上下晃动的话,那么就很有必要优化一下代码。

性能优化的版本

上面的第一步没有问题,第二步完成相对自身尺寸的偏移,可以使用CSS3变换中的translate(使用百分比取值时,以其边框border box尺寸为参照)来替代。

我们先给出代码,然后说明为什么要这样,有什么好处和坏处。

*{margin:0;padding:0;}  
html,body{background: #333;height:100%; width:100%;}  
h1 {  
    -ms-transform: translate3d(-50%, -50%, 0);  
    -webkit-transform: translate3d(-50%, -50%, 0);  
    transform: translate3d(-50%, -50%, 0);  
    color: white;  
    width: 50%;  
    text-align: center;  
    position: absolute;  
    left: 50%;  
    top: 50%;  
}

要明白为什么这么优化,我们首先需要了解浏览器的渲染过程:

解析DOM Tree,创建一个或多个渲染层(layer)

将每个层独立地绘制进位图(bitmap)中(计算样式->布局->栅格化)

将层作为纹理(texture)上传至 GPU

复合(composite)多个层来生成最终的屏幕图像

每个层的样式出现调整后,要重新计算样式->重新布局(可能没有)->重新栅格化(可能没有)->重新组合

使用top/left只会创建一个层,而使用translate方法将促使浏览器(webkit)把h1元素提取出来放在GPU单独的渲染层中(RenderLayer),这样有3点好处:

1. 该元素任何合成属性(Composite Property)的变化将不会影响原有文档,不会导致原文档被重新布局(relayout或reflow),所谓重新布局就是重新计算位置和尺寸,这是前端性能的杀手。位置和角度就是典型的合成属性。

2. 该层将由GPU(Compositor Thread)负责渲染,从而节省CPU资源,不会阻塞主线程JS代码的执行。

3. 动画更为平滑,这是因为使用translate将可以以小于像素的单位(sub-pixel)来绘制,并在帧之间加入了blur(模糊)效果。

可能带来的负作用是额外的渲染层导致更多的线程间通信,如果过度使用,导致生成成百上千的渲染层,那反而会导致组合各层图像的成本迅速上升成为主要矛盾,且我们需要记住GPU也是有内存限制的。当然还有一个前提是translate方法得到了浏览器支持,这在移动端没有问题。

另外使用translate的3D版本和translate 2d版本的区别在于可以强迫在声明后就创建独立的渲染层,这样一旦动画开始,无需等待。

在线实例

这里有一个在线用例是居中标题区块的完整实现

http://wow.techbrood.com/fiddle/6908

还有两个在线用例用来比较top/left和translate方法的性能(你需要学会使用Chrome DevTools):

http://wow.techbrood.com/fiddle/17737

http://wow.techbrood.com/fiddle/17739


possitive(15) views19554 comments0

发送私信

最新评论

请先 登录 再评论.
相关文章
  • 增强现实引擎ARToolKit工作原理简介

    ARToolkit是一个基于CV(计算机视觉)和Marker(标识)的开源增强现实引擎。其具备如下功能特性:A. 鲁棒跟踪,包括基于标记的跟踪与基于特征的跟踪;

  • ARCore基本概念和工作原理简介

    谷歌的WebAROnARCore项目基于Android手机提供的ARCore增强现实引擎,要了解WebAROnARCore,需要先了解ARCore的工作原理。基本上ARCore做了两件事,首先跟踪手机...

  • CentOS6 Apache2.2用域名配置多虚拟机

    在CentOS下使用域名配置多虚拟机的步骤如下:
    1. 使用

  • 如何使用BabylonJS加载OBJ或STL模型

    BabylonJS(也就是babylon.js,这是一个和three.js类似的WebGL开发框架),更多的用在游戏领域。
    本文说明和演示如何使用babylon.js来加载一个标准3d模型文...

  • A-Frame WebVR(网页虚拟现实)快速开发入门教程

    WebVR和WebGL应用程序接口使得我们已经可以在浏览器上创建虚拟现实(VR)体验,但从工程化的角度而言,开发社区还需要更多方便强大的开发库来简化编程,Mozilla的

  • Web界面编程状态变化和JS开发框架(React/Angular/Ember)

    UI编程中的一个关键课题就是界面组件化(可复用)以及组件状态管理。稍早一些的windows程序员可能接触过MFC,其界面编程中有一个DDX(DoDataExchange)的机制,...

  • 使用SVG和CSS3创建圆形进度条动画

    圆形进度条是一个经典的控制面板元素,常用于显示任务进度,比如用户档案的完整程度,或者升级状态。有很多方法来实现圆形进度条,比如用JS, CSS3, Canvas, SVG...

  • 粒子运动模拟 - Verlet积分算法简介

    Verlet算法是经典力学(牛顿力学)中的一种最为普遍的积分方法,被广泛运用在分子运动模拟(Molecular Dynamics Simulation),行星运动以及织物变形模拟等领域...

  • 纹理基础知识和过滤模式详解

    1、 为什么在纹理采样时需要texture filter(纹理过滤)。
    我们的纹理是要贴到三维图形表面的,而三维图形上的pixel中心和纹理上的texel中心并不一至(pixe...

  • Three.js入门教程4 - 创建粒子系统动画

    嗨,又见面了。这么说我们已经开始学习Three.js了,如果你还没有看过之前三篇教程,建议你先读完。如果你已经读完前面的教程了,你可能会想做一些关于粒子的东西。让我们直面这个话题吧,每个人都爱粒子效果。不管你是否知道,你可以很轻易地创建它们。

  • 如何实现SVG clipPath自适应被裁剪对象

    CSS3中引入的clip-path(裁剪路径)属性是一个很强大的特性。
    clip-path的含义如下图所示,好比剪纸一样,你用剪刀沿着某条路径把目标对象(图像或元素)裁...

  • Canvas实例教程:图像移动、大小调整和裁剪

    本文介绍如何使用JavaScript和HTML5 Canvas元素来移动、调整大小和...

  • 使用CSS3实现流星雨动画教程

    很多营销页面中需要实现类似流星雨的动画背景,营造节日浪漫的气氛。要实现这样的效果,有两种方法,一个是使用Canvas,一个是使用纯CSS3,我们这里介绍第2种方...

  • 更多...