🔷关于CSS:transform

515 阅读5分钟

先来看MDN给出的定义

MDN

CSS transform属性允许你旋转,缩放,倾斜或平移给定元素。这是通过修改CSS视觉格式化模型的坐标空间来实现的。


The transform CSS property lets you rotate, scale, skew, or translate an element. It modifies the coordinate space of the CSS visual formatting model.

一点简介

  • 取值

    默认值|none

    矩阵|matrix()\matrix3d()

    转换|translate\translateX\translateY\translateZ\translate3d

    缩放|scale\scaleX\scaleY\scaleZ\scale3d

    旋转|rotate\rotateX\rotateY\rotateZ\rotate3d

    倾斜|skew\skewX\skewY

    透视|perspective

    tips:

    1.可组合使用,值与值间空格隔开,组合值`transform:skew() rotate() scale()...`,执行顺序从右至左(待考究)

    2.skew没有3D属性

    支持性

  • 2D

  • 3D

2D兼容性良好可以放心使用,3D需在IE上注意

相关属性

transform-origin

transform-box

其它\可以用来做些什么

  • transform 不会引起回流与重绘

    关于回流(reflow)与重绘(repaint),网上的文章基本都是定义以及如何避免等文字性描述,如何确定是否产生了回流or重绘却很少有人提及,我自己写了个小例子

    Chrome开一个匿名窗口

    先来看不使用transform实现的动画,这边直接用改变top值来做

    <head>
        <style>
            #test{
                height:20px;
                width:20px;
                animation:test1 ease-in-out 3s infinite;
                background:#000;
                position:absolute
            }
            @keyframes test1{
                0%{
                    top:0
                }
                100%{
                    top:200px
                }
            }
        </style>
    </head>
    <body>
        <div id="test">
        </div>
    </body>
    

    打开Chrome控制台进到Performance页点击Record开始

    这边随缘停止了一下看到以下结果

    首先来看Summary的结果

    可以看到rendering和painting占用了不少时间

    进到event log看下

    可以看到浏览器一直在paint和composite layers 也就是一直在重绘(repaint)

    改用transform试一下

    <head>
        <style>
            #test{
                height:20px;
                width:20px;
                animation:test1 ease-in-out 3s infinite;
                background:#000;
                position:absolute
            }
            @keyframes test1{
                0%{
                    transform:translateY(0)
                }
                100%{
                   transform:translateY(200px)
                }
            }
        </style>
    </head>
    <body>
        <div id="test">
        </div>
    </body>
    

    直接来看Summary

    时间差了一点不过影响不大,会发现paint和render事件消失了,可以证明transform确实是不会触发重绘

    其实除了我写的这处区别外在performance控制台还有好几处区别,具体的大家可以自己试一哈

  • transform实现水平垂直居中

    由第一个例子可以了解到,使用transform:translate()改变位置与直接改变元素top值效果一样,所以transform也可以用来实现水平垂直居中

        {
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%,-50%);
        }
    
  • transform:scale()来满足各种需求

    最近换了工作,一起配合的UI设计师非常严格,会把你的实现和UI设计稿叠在一起check,很是头痛,尤其是出了一个0.3px圆角边框的需求,试过很多种方法效果都不是十分满意(和UI图对不上),最后选择用scale()来做,感动的设计师都哭了

    这边用到的是after伪类来做边框

    	.test::after{
            	            position:absolute;
            	            top:0;
            	            left:0;
            	            box-sizing:border-box;
            	            width:300%;
            	            height:300%;
            	            border:1px solid #b4b4b4;
            	            border-radius:9px;
            	            content:" ";
            	            transform:scale(.33333,.33333);
            	            transform-origin:0 0
    	            }
    	            
    

    需要注意的是不光长宽需要等比放大,圆角的值也是需要的

    另外在Android手机,小于12px的文字垂直居中有着怪异的表现(偏上),除了用table布局外还可以用transform:scale先把元素放大在缩小的方式来解

    其实13px的字体在某些机型的安卓上垂直居中也不行,也可以用这种方法解决

  • transform:transition()模拟列表滚动

    最后要说的是我最近遇到的一个比较棘手的问题,需求简单来说就是在微信和QQ里禁止滑动漏出“由xx.xx.xx提供的网页”的这句话,但是页面里还有一个滑动的列表。

    简单说一下出现的问题:

      办法1:全局禁止滑动,列表touchstart时取消禁止,touchend时恢复禁止,touchmove方向位置等做监听
      问题:我能想到的第一个办法,但在Android的QQ里触摸事件和我想象的完全不一样,在列表直接下拉确实没问题,先向上滑再往下滑居然就不行了
      办法2:touch-action限制滑动行为
      问题:看到这个css属性我以为救星来了,但不适用于此处,都是y方向动的,要禁止都禁止了
    

    各种方案最后都在安卓QQ上折了,没办法只能转换思路,放弃浏览器默认的overflow:scroll,改用transform来做

    以为我这边是用vue做的所以代码的话就不直接给出了

    简单的实现方案就是

    // html

    <div class="外部">
        <div class"内部">
            其他滚动元素
        </div>
    </div>
    
    
        当前滚动值 = transformY
        上一次touch事件滚动值 = lastY
        当前touchstart时Y点 = startY
        当前touchmove时Y值 = moveY
    
    

    1.依旧全局禁止滑动,把外部元素原来的overflow:scroll改为hidden

    2.监听touchstart事件获得startY

    3.监听touchmove事件获得moveY

    4.lastY 初始值为0

    5.touchmove非顶部与底部时:transformY = lastY + moveY - startY

    6.touchmove时顶部判断与底部判断

      //顶部向上滑
      
      ```
          if(transformY >= 0 && moveY > startY){
              transformY = 0
      	    lastY = 0
      		touchY = curY
          }
      ```
      
      //底部向下滑
      
      ```
          if(内部.clientHeight - 外部.clientHeight + transformY <= 0)&&moveY < startY){
      		transformY = -(内部.clientHeight - 外部.clientHeight);
      		lastY = transformY
      		startY = moveY
          }
      ```
    

    7.监听touchend事件,lastY = transformY

    大功告成,亲测在棘手的安卓qq上可完美实现滑动列表效果,至于回弹等效果也可以扩展。