transform
是諸多css3新特性中最打動我的,因為它讓方方正正的box module變得真實了。
transform通過一組函數實現了對盒子大小、位置、角度的2D或者3D變換。不過很長時間內,我對以下問題都想不太明白:
1、尺寸縮放scale
與zoom
變換有何不同,為什么被scale
的盒子里的內容不會錯位,但zoom不是。
2、位移(transform:translate
)與相對定位、絕對定位(position:relative | absolute
)有何關系?
3、在實際項目中發現,位圖(無論是background-image
還是img
)在被transform后會模糊掉,尤其是scale
;不僅如此,在一些網站,比如tmall.com,即使是矢量的svg文件在使用transform后,依然模糊了,transform是否對作用的盒子進行了類似柵格化的操作?
4、在實際項目中發現,如果父級元素使用了transform
且其中的子元素進行了position:fixed
定位,那么設置了position:fixed
的子元素將不再基于窗口定位。
5、這種場景暫時未能重現,在chrome下:父級元素使用了position:fixed
,子元素<a href=".."></a>
設置了:hover
偽類、transition
過渡動畫、并使用javascript動態添加/刪除其class,此時會出現:hover
樣式失效或添加的class樣式失效且transition
過渡動畫失效的現象。
等等。
先說原理吧。
在網上查看了一些大神的博客,transform
是通過一系列矩陣變換完成的,scale等transform-function都是對matrix的封裝,w3c里沒找到有關說明。對于線性代數里的東西,博主表示非常小白,其中的數學原理,還是交給其他人去解釋吧o(︶︿︶)o
w3里的解釋是,transform基于可視化格式模型(visual formatting model,這樣翻譯對不對啊)并為其繪制出一個坐標系,而且所有在這個坐標系內進行的操作,如向右向下,都是在這個坐標系內以像素方式表示,原文:
The CSS visual formatting model describes a coordinate system within each element is positioned. Positions and sizes in this coordinate space can be thought of as being expressed in pixels, starting in the origin of point with positive values proceeding to the right and down.
那是不是意味著scale縮放,是否只是像素意義上的縮放呢?由此,因縮放導致的svg等矢量內容模糊失真是情理之中了??_?
個人猜測,應該先轉換成像素,然后進行渲染,這應該和每個瀏覽器具體渲染過程有關,相關文檔我沒有查,如果有知道的,請給我留言。
要理解transform,還有一個事情要搞清楚,就是visual formatting model,借助谷歌度娘,找到了w3chelp上的中文版解釋:
可視化格式模型是非常抽象的概念。它是 CSS 布局的核心,通過它,框( box )可以獲得應有的尺寸,放到需要的位置。
我們通常所看到的頁面都是平面 2D 的效果,但可視化模型卻是 3D 的,除了 X 軸,Y 軸,還有決定元素顯示順序1的 Z 軸。 Z 軸垂直穿過計算機屏幕,面向用戶的一側是正軸,框在 Z 軸方向上離用戶越近,顯示越是靠前。
可視化格式模型的官方說法是,它規定了用戶端在媒介中如何處理文檔樹( document tree )
……
本部分會涉及很多新概念,如包含塊、元素的類型、定位體系、塊級格式化上下文、行內格式化上下文、浮動、絕對定位和 z-index,以及可視化格式模型的細節部分,自動寬度高度的計算等。
博主第一次聽到visual formatting model這個概念,但看了解釋應該知道,這不是一個新概念,姿勢水平捉急了?_?
根據這個解釋,元素設置了transform
并不會改變元素所在的文檔流,其布局仍然受盒模型支配,因此這里的變換的效果是可以與浮動、定位并存的。
-
當元素設置了transform后,會為該元素定義一個坐標系,并且在該坐標系內進行矩陣變換,將變換結果映射到用戶坐標系(也就是實際上的上下文)中。
-
多個矩陣變換函數將依次從左到右計算,如
transform:translate(80px, 80px) scale(1.5, 1.5)
,瀏覽器會先計算位移,再縮放1.5倍。以下兩種代碼效果相同:html <div style="transform: translate(80px, 80px)"> <div style="transform: scale(1.5, 1.5)"> <div style="transform: rotate(45deg)"></div> </div> </div>
html <div style="transform: translate(80px, 80px) scale(1.5, 1.5) rotate(45deg);"> </div>
-
坐標原點的位置受屬性
transform-origin
的影響。 -
如果是3D變換,則還會將其加入一個3D渲染上下文(3D rendering context)。根據個人理解,無論有多少個轉換為3D的元素,其將始終在這個上下文內并可能相互影響,類似一個文檔中的多個被絕對定位的元素。
-
任何非none的transform值都會導致一個堆疊上下文(stacking context)和包含塊(containing block)的創建。
不過,并不意味著和諧,不然怎么會有那么多坑問題嘛!(,,?▽?,,)
如果元素因為transform而撐開了父級元素,父級元素會根據自身的overflow
屬性決定是否出現滾動條、隱藏溢出的部分或是別的什么。
另外,根據規范,由于堆疊上下文的創建,該元素會影響其子元素的固定定位:被設置position:fixed
的子元素將不會基于viewport定位,而是基于這個父元素。
我們知道,一般情況下,所有的position值不為static的元素都會被放到同一個堆疊上下文內(ie不高級瀏覽器不算),也就是說,只存在 一個堆疊上下文。而設置了transform的元素則不同,由于它創建了一個新的堆疊上下文,也就是說,其內部被定位的元素的z-index會放在一個完 全獨立的空間內。
但是這個堆疊上下文不包含被定義transform的元素本身,它仍被放在更大的堆疊上下文(如果有的話)里。
說到這,開篇提到的問題2、4都已經找到答案了,但目前,Chrome還存在一個bug:rendering bug : position:fixed AND -webkit-transform。
上面提得另一個問題重現場景比較麻煩,先不討論了。
留幾個坑回頭填:
- 當
transform
遇見display:table | table-row | table-cell
- 3D渲染上下文是個什么玩意
- 陌生又熟悉的backface-visibility
- transform 與 css3動畫
- transform 與 canvas
- transform 與 svg