CSS3 vom quadratischen Bild zum Trapez ohne x-Rotation
P粉604669414
P粉604669414 2024-03-28 15:26:58
0
1
337

Ich versuche, ein quadratisches Div mit einem Hintergrundbild in ein Trapez umzuwandeln.

Ich wollte es in 2D erstellen, ähnlich wie das Photoshop-Werkzeug „Verzerren“.

Im Grunde möchte ich nur die Oberkante des Quadrats verkleinern und das Bild entsprechend verformen.

3D-Konvertierung „scheint“ den Zweck zu erfüllen:

transform: rotateX(30deg);

Es funktioniert für die meisten Anwendungsfälle, aber nicht für alle. Tatsächlich handelt es sich um ein um 30 Grad gedrehtes Quadrat, das von vorne/hinten wie ein Trapez „sieht“, von jeder anderen Seite jedoch immer noch ein um 30 Grad gedrehtes Quadrat ist.

Was ich möchte, ist ein echtes Trapez. Ich möchte, dass das quadratische Bild zweidimensional verzerrt wird, sodass sich Form und Bild tatsächlich ändern, ohne dass eine Drehung erforderlich ist.

Ich habe es versucht und es funktioniert in Bezug auf die Form (Trapez):

border-style: solid;
height: 0;
border-color: transparent transparent red transparent;
border-width: 0 100px 100px 100px;

Aber ich kann den roten Bereich nicht durch das verzerrte Hintergrundbild ersetzen. Das macht meinen Zweck zunichte. Bei allem, was ich versuche, bleibt das Bild unverzerrt.

Gibt es CSS/HTML5/Javascript-Tricks, um das zu erreichen, was ich will?

Vielen Dank.

P粉604669414
P粉604669414

Antworte allen(1)
P粉131455722

您可以通过对伪元素应用 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 轴(垂直于屏幕)发生,因此我们基本上将我们的伪背部拉向屏幕背面,保留每个点的 xy 坐标,但更改 z坐标。

基本上,如果我们以 3D 方式查看它而不展平到父级平面(父级受轮廓限制),它会如下所示。

您可以看到顶部的水平指导线如何显示倾斜伪值的顶部如何保留其 xy 坐标,它只是沿着z 轴。

好吧,我们如何使用 CSS 来实现它?

如上所述,没有 3D 倾斜,但我们可以自己构建变换矩阵。由于这是沿 z 轴(第三轴)的倾斜,沿 y 轴(第二轴)拉伸边缘,因此矩阵中唯一与 单位矩阵(沿着主对角线的 1,其他地方的 0)将位于第 3 行第 2 行柱子。我们将在那里得到倾斜角的正切。在 MDN 上,您也可以在 skewX()skewY() 中看到这一点。

这是因为沿倾斜轴的每个点都会被其沿延长轴的坐标乘以倾斜角的正切值所位移 - 如果您绘制与轴平行的线,您可以在第一个插图中看到这一点(x 轴,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 支持吗?您甚至不需要在那里使用正切计算,您可以使用任何正数 - 该数字越大,顶部边缘就越小。我使用正切值来说明它的来源,但您不必这样做。我们的正切值是针对从 90° 的角度计算的。这为我们提供了从 0+Infinity 的切线值。所以是的,任何正数都可以在矩阵中出现。

Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage