我正在嘗試將帶有背景圖像的方形 div 轉換為梯形。
我想以 2D 形式製作它,與 Photoshop 的「扭曲」工具的方式幾乎相同。
基本上,我想要的只是縮小正方形的頂邊並使圖像相應變形。
3D 轉換「似乎」能夠解決問題:
transform: rotateX(30deg);
它適用於大多數用例,但並非全部。 事實上,它是一個 30 度旋轉的正方形,從正面/背面看時「看起來」像梯形,但從任何其他側面看時仍然是 30 度旋轉的正方形。
我想要的是得到一個真正的梯形。我希望方形圖像以 2D 方式扭曲,以便形狀和圖像實際上發生變化,而不涉及旋轉。
我嘗試了這個,它在形狀(梯形)方面有效:
border-style: solid; height: 0; border-color: transparent transparent red transparent; border-width: 0 100px 100px 100px;
但是我無法用失真後的背景圖像替換紅色區域。這違背了我的目的。 我嘗試的任何嘗試都會使圖片保持不變形。
是否有任何 css/html5/javascript 技巧可以實現我想要的?
謝謝。
P粉1314557222024-03-29 14:57:26
您可以透過對偽元素套用3D 變換(您也可以在其上設定background-image
)並確保它在其原始平面(其父元素的平面)上展平來獲得效果。這表示如果您想要以 3D 方式旋轉某些物體,則必須旋轉父物體。
步驟#1:建立一個方塊div
,新增一個具有完全相同尺寸的偽變數(或子變數),並在該偽變數上設定background -image
。
div { display: grid; /* makes pseudo stretch all across */ width: 28em; /* whatever edge value we want */ aspect-ratio: 1; /* make it square */ /* just to highlight div boundaries */ box-shadow: 0 0 0 3px; &::after { background: url(image.jpg) 50%/ cover; content: '' } }
步驟#2:將偽值上的transform-origin
設定為底部邊緣的中間(100% 50%
) - 這可確保應用3D 後底部邊緣保持在原位變換。
步驟 #3:沿著 z
軸應用 3D 傾斜,沿著 y
軸延長邊緣。
是的,我們在 CSS 中沒有 3D 傾斜函數。但我們有matrix3d()
,可以用來表達任何旋轉、縮放、傾斜、平移!
所以讓我們先了解傾斜是如何運作的。
沿軸發生傾斜。
這是一個互動式示範,說明了 2D 傾斜函數的工作原理。
考慮這個例子,我們沿著x軸傾斜,當y軸旋轉遠離其初始位置時,沿著y軸的邊緣被拉長- 這個角度是傾斜角度。 z 軸垂直於我們傾斜的平面(本例為xOy)且不受影響:
好吧,在我們的例子中,我們做了類似的事情,但是傾斜發生在yOz 平面中,而不是xOy 平面中,因為我們沿著yOz 平面傾斜>z 軸而不是沿著x 軸。
由於我們已經使用transform-origin
將偽值底部邊緣的中間錨定到位,並且這種傾斜沿著z 軸(垂直於螢幕)發生,因此我們基本上將我們的偽背部拉向螢幕背面,保留每個點的x 和y 座標,但更改z座標。
基本上,如果我們以 3D 方式查看它而不展平到父級平面(父級受輪廓限制),它會如下所示。
您可以看到頂部的水平指導線如何顯示傾斜偽值的頂部如何保留其x 和y 座標,它只是沿著z 軸。
好吧,我們要如何使用 CSS 來實現它?
如上所述,沒有 3D 傾斜,但我們可以自己建立變換矩陣。由於這是沿著z 軸(第三軸)的傾斜,沿著y 軸(第二軸)拉伸邊緣,因此矩陣中唯一與單位矩陣(沿著主對角線的1
,其他地方的0
)將位於第3 行第2 行柱子。我們將在那裡得到傾斜角的正切。在 MDN 上,您也可以在 skewX()
和 skewY()
中看到這一點。
這是因為沿著傾斜軸的每個點都會被其沿延長軸的座標乘以傾斜角的正切值所位移- 如果您繪製與軸平行的線,您可以在第一個插圖中看到這一點(x< /em> 軸,y 軸(前後傾斜)穿過範例點的原始位置(灰色)和最終位置(黑色)。繪製這些平行線會建立一個直角三角形,其中y 座標上的x 位移是傾斜角的正切。
好吧,回到矩陣,它看起來像這樣。
1 0 0 0 1 0 0 tan(a) 1
要取得matrix3d()
值,我們再增加一行和一列,與4x4
單位矩陣中的值相同,然後逐列列出值(不是 一行一行!)。到目前為止,我們已經:
@use 'sass:math'; // allows us to use trigonometric functions $a: 60deg; // the skew angle div { display: grid; width: 28em; aspect-ratio: 1; perspective: 25em; box-shadow: 0 0 0 3px; &::after { transform-origin: 50% 100%; transform: matrix3d(1, 0, 0, 0, /* 1st column */ 0, 1, math.tan($a), 0, /* 2nd column */ 0, 0, 1, 0, /* 3rd column */ 0, 0, 0, 1); background: url(image.jpg) 50%/ cover; content: '' } }
請注意,我們也加入了 perspective
來取得扭曲的視圖(頂部較小/較後)。
到目前為止的程式碼為我們提供了上面 gif 中所看到的扁平化版本。我說扁平版本是因為,就我們在這裡所擁有的而言,偽物件總是在其父級的平面上被扁平化。
當父級div
沒有3D變換時,我們從正面看,偽明顯看起來是平的。
當父級div
確實具有3D 變換時,其3D 變換偽值會展平到其平面中,因為預設transform-style
值為flat
。這意味著 3D 變換父級的任何 3D 變換子級/偽物件都會在父級平面中展平。如果我們將div的transform-style
設定為preserve-3d
,則可以更改此設定。但我們不希望這樣。
第 4 步:固定頂部邊緣!
還有一件事看起來仍然不正確:transform
頂部邊緣現在位於原始邊緣下方。
這是因為我們設定了 perspective
以及它的工作原理。預設情況下,perspective-origin
死在我們設定它的元素的中間(在本例中是我們的div
),水平方向為50%
,垂直方向為50%
。
讓我們只考慮螢幕平面後面的點,因為那是我們整個 3D 傾斜偽值所在的位置。
使用預設的perspective-origin
(50% 50%
),只有div
正中間垂直於螢幕平面的線上的點才會被投影到螢幕平面上的某一點:考慮視角後,與自己的x,y 座標相同的x,y 座標。考慮透視後,只有垂直於螢幕並沿著 div
的水平中線與螢幕相交的平面中的點才會投影到該水平中線上。
你知道這是怎麼回事嗎?如果我們移動perspective-origin
使其位於div 頂部邊緣的中間(50% 0
),那麼沿著該頂部邊緣垂直於螢幕的平面中的點將沿著該頂部邊緣投影- 即,3D 傾斜偽物件的頂邊將與其父項的頂邊沿同一直線。
所以我們最終的程式碼是:
@use 'sass:math'; // allows us to use trigonometric functions $a: 60deg; // the skew angle div { display: grid; width: 28em; aspect-ratio: 1; perspective-origin: 50% 0; perspective: 25em; box-shadow: 0 0 0 3px; &::after { transform-origin: 50% 100%; transform: matrix3d(1, 0, 0, 0, /* 1st column */ 0, 1, math.tan($a), 0, /* 2nd column */ 0, 0, 1, 0, /* 3rd column */ 0, 0, 0, 1); background: url(image.jpg) 50%/ cover; content: '' } }
這是我們的結果與其轉換前版本之間的即時比較視圖因為兩個div 都以3D 方式旋轉,以顯示它們在xOy 平面上是平坦的。
不想使用預處理器來處理正切值? Firefox 和 Safari 預設情況下已經支援三角函數,Chrome 111 透過在 chrome://flags
中啟用實驗性 Web 平台功能標誌來支援三角函數。
也不想等待 Chromium 支援嗎?您甚至不需要在那裡使用正切計算,您可以使用任何正數 - 該數字越大,頂部邊緣就越小。我使用正切值來說明它的來源,但您不必這樣做。我們的正切值是針對從 0°
到 90°
的角度計算的。這為我們提供了從 0
到 Infinity
的切線值。所以是的,任何正數都可以在矩陣中出現。