CSS的transforn詳解
位移,旋轉,偏移,縮放分別使用translate/rotate/skew/scale的方式來控制元素變換,也可以使用matrix。
使用translate/rotate/skew/scale
.demo{
transform:translate(10px, 20px) rotate(30deg) scale(1.5, 2);
}
matrix
.demo{
transform:matrix(0.75, 0.8, -0.8, 1.2, 10, 20)
}
Matrix的中文是矩陣,在計算機科學中,會用矩陣來對向量進行變換,在css3的transform屬性中,可以使用矩陣對圖像進行變換。
matrix與矩陣對應
css3里面可以用矩陣表示2D和3D轉換
.demo{
transform:matrix(a,b,c,d,e,f)
}
2D的轉換是由一個3*3的矩陣表示的,前兩行代表轉換的值,分別是 a b c d e f ,要注意是豎著排的,第一行代表的是X軸變化,第二行代表的是Y軸的變化,第三行代表的是Z軸的變化,2D不涉及到Z軸,這里使用 0 0 1
假設一個問題
創建一個寬高為200px的div ,div 里面有一個紅色的點,位置是{x:181px y:50px}
倘若將這個div向右平移20px,旋轉37°,x軸縮放1.5倍,y軸縮放2倍
transform:tranlate(10px,20px) rotate(37deg) scale(1.5, 2)
縮放scale(x,y)
縮放對應的是矩陣中的a
和d
,x
軸的縮放比例對應a
,y
軸的縮放比例對應d
。
transform:scale(x,y)
a = x
d = y
所以scale(1.5, 2)
對應的矩陣是
matrix:(1.5,0,0,0,2,0)
如果元素沒有被縮放,默認a = 1 d =1
平移 translate(10, 20)
平移對應的是矩陣中 e
和 f
,平移的x
和 f
分別對應 e
和 f
transform:translate(10, 20)
e = 10
f = 20
對應:transform: matrix(a, b, c, d ,10, 20);
結合縮放:transform: matrix(1.5 0, 0, 2, 10, 20)
旋轉 rotate(0deg)
旋轉影響的是a/b/c/d四個值,分別是什么呢?
transform: rotate(θdeg)
a=cosθ
b=sinθ
c=-sinθ
d=cosθ
如果要計算 30° 的sin值:
首先我們要將 30° 轉換為弧度,傳遞給三角函數計算。用 JS 計算就是下面的樣子了。
// 弧度和角度的轉換公式:弧度=π/180×角度
const radian = Math.PI / 180 * 30 // 算出弧度
const sin = Math.sin(radian) // 計算 sinθ
const cos = Math.cos(radian) // 計算 cosθ
console.log(sin, cos) // 輸出 ≈ 0.5, 0.866
transform: rotate(30deg)
a=0.866
b=0.5
c=-0.5
d=0.866
transform: matrix(0.866, 0.5, -0.5, 0.866, 0, 0);
偏移 skew(20deg, 30deg)
上面的題目中沒有出現出現偏移值,偏移值也是由兩個參數組成,x 軸和 y 軸,分別對應矩陣中的 c 和 b。是 x 對應 c,y 對應 b, 這個對應并不是相等,需要對 skew 的 x 值 和 y 值進行 tan 運算。
transform: skew(20deg, 30deg);
b=tan30°
c=tan20°
注意 y 對應的是 c,x 對應的是 b。
transform: matrix(a, tan(30deg), tan(20deg), d, e, f)
使用 JS 來算出 tan20 和 tan30
// 先創建一個方法,直接返回角度的tan值
function tan (deg) {
const radian = Math.PI / 180 * deg
return Math.tan(radian)
}
const b = tan(30)
const c = tan(20)
console.log(b, c) // 輸出 ≈ 0.577, 0.364
b=0.577 c=0.364
transform: matrix(1, 0.577, 0.364, 1, 0, 0)
旋轉+縮放+偏移+位移怎么辦?
如果我們既要旋轉又要縮放又要偏移,我們需要將旋轉和縮放和偏移和位移多個矩陣相乘,要按照transform里面rotate/scale/skew/translate所寫的順序相乘。
這里我們先考慮旋轉和縮放,需要將旋轉的矩陣和縮放的矩陣相乘
實在是用語言解釋不清楚如何去乘,用一張圖解釋吧:
這里我用小寫字母代表第一個矩陣中的值,大寫字母代表第二個矩陣里的值
將我們的已經得到的矩陣帶入到公式
得出:
transform: rotate(30) scale(1.5 2);
轉換為 matrix 表示為:
transform: matrix(1.299, 0.75, -1, 1.732, 0, 0);
找到這次轉換的矩陣
div 的 transform 值如下
transform: translate(10px, 20px) rotate(37deg) scale(1.5, 2);
#### translate(10px, 20px)
x 平移 10px,y 平移 20px,所以 e=10,f=20。
rotate(37deg)
sin37° ≈ 0.6
cos37° ≈ 0.8
根據 a 對應 cos b,對應 sin,c 對應 -sin,d 對應 cos 的值
得到:
a=0.8,b=0.6,c=-0.6,d=0.8
scale(1.5, 2)
x 軸縮放 1.5,y 軸縮放 2,所以 a=1.5,d=2
結合
transform: translate(10px, 20px) rotate(37deg) scale(1.5, 2);
我們使用 位移矩陣 旋轉矩陣 縮放矩陣(根據transform中的變換類型書寫的順序)
可以使用矩陣計算器進行計算
從左往右依次計算
所以最終得到矩陣
matrix(1.2, 0.9, -1.2 1.6, 10, 20)
驗證一下
transform: matrix(1.2, 0.9, -1.2 1.6, 10, 20)
和
transform: translate(10px, 20px) rotate(37deg) scale(1.5, 2);
效果是一樣的
如何對一個坐標進行矩陣變換
我們已經知道了這個矩陣,如何通過矩陣對一個坐標進行變化,找到這個坐標變化后的位置呢?
我們用之前得出的變換矩陣去乘以這一個坐標組成的3*1(三排一列)矩陣。
上面已經介紹過如何進行矩陣乘法了,這里在介紹一遍
上圖中左右兩個矩陣顏色相同的位置相乘后相加,每一行都進行這樣的計算:
得到一個3*1的矩陣,第一行是轉換后的 x 值,第二行是轉換后的 y 值,第三行是轉換后的 z 值(2d不考慮z值)。
前面講到,矩陣的第一行影響 x,第二行影響 y,也體現在這個地方。
假設我們的坐標是(50, 80),這里還沒有針對我們提出的問題上面的點進行計算。
我們把坐標寫成矩陣的形式,設置 z 軸是1:
然后進行乘法計算:
通過我們計算出來的矩陣變換得到新的位置(46, 172)
繼續剛剛問題
坐標是需要基于一個坐標系存在的,我們需要找到正確的坐標系才能算出準確的坐標。 在 CSS transform 中,有個屬性是 transform-origin,來設置變換所基于的點,默認是transform-origin: 50% 50%,基于中間元素的中心點。我們需要以這個點建立坐標系。
在網頁中,坐標系是 x 軸向右,y 軸向下。
轉換前:
轉換后:
根據題目我們知道,這個點相對于綠色div左上角的坐標是(181, 50) 綠色div的寬高為200 基于綠色div中心點建立的坐標系,這個點的坐標是(81, -50)
將坐標代入公式進行計算:
得到坐標約為(167, 13)
再將這個坐標轉換成頁面坐標系(267,113)
最終我們得到了這個點在經過轉換后的坐標
參考文章: https://fanmingfei.com/post/CSS3_Transform_Matrix_Intro.html