recherche

Maison  >  Questions et réponses  >  le corps du texte

css3 d'une image carrée à un trapèze sans rotation x

J'essaie de convertir un div carré avec une image d'arrière-plan en trapèze.

Je voulais le réaliser en 2D, de la même manière que l'outil "déformation" de Photoshop.

En gros, tout ce que je veux, c'est réduire le bord supérieur du carré et déformer l'image en conséquence.

La conversion 3D "semble" faire l'affaire :

transform: rotateX(30deg);

Cela fonctionne pour la plupart des cas d'utilisation, mais pas pour tous. En fait, il s'agit d'un carré pivoté de 30 degrés qui "ressemble" à un trapèze vu de face/arrière, mais qui reste un carré pivoté de 30 degrés vu de n'importe quel autre côté.

Ce que je veux, c'est obtenir un vrai trapèze. Je souhaite que l'image carrée soit déformée en 2D afin que la forme et l'image changent réellement sans impliquer de rotation.

J'ai essayé ça et ça marche en terme de forme (trapèze) :

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

Mais je ne peux pas remplacer la zone rouge par l'image d'arrière-plan déformée. Cela va à l’encontre de mon objectif. Tout ce que j'essaie garde l'image intacte.

Existe-t-il des astuces CSS/html5/javascript pour obtenir ce que je veux ?

Merci.

P粉604669414P粉604669414240 Il y a quelques jours343

répondre à tous(1)je répondrai

  • P粉131455722

    P粉1314557222024-03-29 14:57:26

    Vous pouvez obtenir l'effet en appliquant une transformation 3D au pseudo-élément (vous pouvez également définir background-image dessus) et en vous assurant qu'il est aplati sur son plan d'origine (le plan de son élément parent). Cela signifie que si vous souhaitez faire pivoter quelque chose en 3D, vous devez faire pivoter l'objet parent.

    Étape n°1 : Créez un carré div, ajoutez une variable factice (ou sous-variable) avec exactement les mêmes dimensions et définissez div,添加一个具有完全相同尺寸的伪变量(或子变量),并在该伪变量上设置 background-image sur cette variable factice.

    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: ''
        }
    }

    Étape n°2 : Placez la valeur factice sur le transform-origin 设置为底部边缘的中间 (100% 50%) - cela garantit que le bord inférieur reste en place après l'application de la transformation 3D.

    Étape n°3 : Étendez le bord le long de l'axe z 轴应用 3D 倾斜,沿 y.

    Oui, nous n'avons pas de fonction d'inclinaison 3D en CSS. Mais nous avons matrix3d(), qui peut être utilisé pour exprimer n'importe quelle rotation, mise à l'échelle, inclinaison et translation !

    Commençons donc par comprendre comment fonctionne l’inclinaison.

    L'inclinaison se produit le long de l'axe.

    Il s'agit d'une démo interactive qui illustre le fonctionnement de la fonction d'inclinaison 2D.

    Considérez cet exemple où nous inclinons le long de l'axe x, lorsque l'axe y s'éloigne de sa position initiale, les bords le long de l'axe y sont allongés - cet angle est l'angle d'inclinaison. L'axe z est perpendiculaire au plan que nous inclinons (dans ce cas xOy) et n'est pas affecté :

    Eh bien, dans notre cas, nous avons fait quelque chose de similaire, mais l'inclinaison s'est produite dans le plan yOz, pas dans le plan xOy, car nous avons plutôt incliné le long du plan yOz > z le long de l'axe x.

    Puisque nous avons déjà utilisé transform-origin pour ancrer le milieu du bord inférieur de la pseudo-valeur en place, et que cette inclinaison se produit le long de l'axe z (perpendiculaire à l'écran), nous tirons essentiellement notre pseudo-arrière vers l'arrière de l'écran, en conservant toutes les coordonnées x et y d'un point, mais en modifiant les coordonnées z.

    En gros, si nous le visualisons en 3D sans l'aplatir sur le plan parent (le parent est limité par le contour), il ressemblera à ceci.

    Vous pouvez voir comment la ligne de guidage horizontale en haut montre comment le haut de la pseudo-valeur inclinée conserve ses coordonnées x et y, c'est juste le long de l'axe z.

    D'accord, comment pouvons-nous faire cela en utilisant CSS ?

    Comme mentionné ci-dessus, il n'y a pas d'inclinaison 3D, mais nous pouvons construire nous-mêmes la matrice de transformation. Puisqu'il s'agit d'une inclinaison le long de l'axe z (le troisième axe) et que le bord est étiré le long de l'axe y (le deuxième axe), la seule chose dans la matrice qui ressemble à la matrice d'identité ( le 1,其他地方的 0)将位于第 3 行第 2 行柱子。我们将在那里得到倾斜角的正切。在 MDN 上,您也可以在 skewX()skewY() le long de la diagonale principale) jusqu'à ce point

    En effet, chaque point le long de l'axe d'inclinaison est déplacé de sa coordonnée le long de l'axe allongé multipliée par la tangente de l'angle d'inclinaison - vous pouvez le voir dans la première illustration si vous tracez une ligne parallèle à l'axe (l'axe x< /em> , l'axe y (incliné vers l'avant et vers l'arrière) passe par la position d'origine (gris) et la position finale (noire) du point d'exemple. Dessiner ces lignes parallèles crée un triangle rectangle avec la coordonnée y sur le déplacement x . est la tangente de l'angle d'inclinaison

    .

    D'accord, revenons à la matrice, ça ressemble à ça.

    1   0    0
    0   1    0
    0 tan(a) 1

    Pour obtenir matrix3d() 值,我们再添加一行和一列,与 4x4 les mêmes valeurs dans la matrice identité, puis lister les valeurs colonne par colonne ( pas ligne par ligne !). Jusqu'à présent, nous avons :

    @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: ''
        }
    }

    Notez que nous avons également ajouté perspective pour obtenir une vue déformée (plus petite en haut/plus en arrière).

    Le code jusqu'à présent nous donne la version aplatie vue dans le gif ci-dessus. Je dis version aplatie car, pour autant que nous en soyons ici, les pseudo-objets sont toujours aplatis sur le plan de leur parent.

    Lorsque le parent divn'a pas de transformation 3D, et qu'on le regarde de face, l'aspect pseudo-évident est plat.

    Lorsqu'un parent div 确实具有 3D 变换时,其 3D 变换伪值会展平到其平面中,因为默认 transform-style 值为 flat。这意味着 3D 变换父级的任何 3D 变换子级/伪对象都会在父级平面中展平。如果我们将div的transform-style设置为preserve-3d a une transformation 3D, sa pseudo-valeur de transformation 3D est aplatie dans son plan, car la valeur par défaut de transform-style est flat. Cela signifie que tous les enfants/pseudo-objets de transformation 3D d'un parent de transformation 3D seront aplatis dans le plan parent. Ce paramètre peut être modifié si nous définissons le transform-style du div sur preserve-3d. Mais nous ne voulons pas de cela.

    Étape 4 : Sécurisez le bord supérieur !

    Encore une chose qui ne semble toujours pas correcte : transformLe bord supérieur est maintenant en dessous du bord d'origine.

    C'est à cause de la façon dont nous l'avons configuré perspective 以及它的工作原理。默认情况下,perspective-origin 死在我们设置它的元素的中间(在本例中是我们的 div),水平方向为 50%,垂直方向为 50% et de son fonctionnement. Par défaut, perspective-origin meurt au milieu de l'élément sur lequel nous l'avons placé (dans ce cas notre

    ), à 50% horizontalement et verticalement 50% .

    Considérons simplement les points situés derrière le plan de l'écran, car c'est là que se trouve l'intégralité de notre pseudo-valeur d'inclinaison 3D.

    perspective-origin (50% 50%),只有 div 正中间垂直于屏幕平面的线上的点才会被投影到屏幕平面上的某个点:考虑视角后,与自己的 x,y 坐标相同的 x,y 坐标。考虑透视后,只有垂直于屏幕并沿 divEn utilisant la perspective-origin par défaut (50% 50%), seuls les

    points sur la ligne perpendiculaire au plan de l'écran seront projetés sur le plan de l'écran. Un certain point : les coordonnées x, y qui sont les mêmes que vos propres coordonnées x, y après prise en compte de la perspective. En tenant compte de la perspective, seuls les points du plan perpendiculaires à l'écran et coupant l'écran le long de la ligne médiane horizontale de

    seront projetés sur cette ligne médiane horizontale. perspective-origin 使其位于 div 顶部边缘的中间 (50% 0

    Savez-vous ce qui se passe ? Si nous bougeons

    ), alors les points dans un plan perpendiculaire à l'écran le long de ce bord supérieur seront projetés le long de ce bord supérieur - c'est-à-dire que le bord supérieur du pseudo-objet incliné 3D sera dans la même ligne que le bord supérieur. de son parent.

    🎜Notre code final est donc : 🎜
    @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: ''
        }
    }

    Voici une vue comparative en direct entre nos résultats et leur version pré-conversion car les deux divs sont pivotés en 3D pour montrer qu'ils sont à plat sur le plan xOy.


    Vous ne souhaitez pas utiliser de préprocesseur pour gérer les valeurs tangentes ? Firefox et Safari prennent déjà en charge les fonctions trigonométriques par défaut, et Chrome 111+ prend en charge les fonctions trigonométriques en activant le drapeau chrome://flagsFonctionnalités expérimentales de la plateforme Web dans le .

    Vous ne voulez pas attendre le support de Chromium ? Vous n'avez même pas besoin d'utiliser le calcul de la tangente, vous pouvez utiliser n'importe quel nombre positif - plus le nombre est grand, plus le bord supérieur sera petit. J'utilise la valeur tangente pour illustrer d'où elle vient, mais ce n'est pas obligatoire. Notre tangente est pour la tangente de 90° 的角度计算的。这为我们提供了从 0+Infinity. Alors oui, n’importe quel nombre positif peut apparaître dans une matrice.

    répondre
    0
  • Annulerrépondre