Nehmen wir an, wir wollten so etwas haben

Zuerst scheint das nicht allzu kompliziert. Wir beginnen mit `12` nummerierten Elementen.
- 12.times do |i|
.item #{i}
Wir geben diesen Elementen Abmessungen, positionieren sie absolut in der Mitte ihres Containers, geben ihnen einen `background`, einen `box-shadow` (oder einen `border`) und passen die textbezogenen Eigenschaften ein wenig an, damit alles gut aussieht.
$d: 2em;
.item {
position: absolute;
margin: calc(50vh - #{.5*$d}) 0 0 calc(50vw - #{.5*$d});
width: $d; height: $d;
box-shadow: inset 0 0 0 4px;
background: gainsboro;
font: 900 2em/ #{$d} trebuchet ms, tahoma, verdana, sans-serif;
text-align: center;
}
Bisher alles gut
Siehe den Pen von thebabydino (@thebabydino) auf CodePen.
Nun müssen wir sie nur noch auf einem Kreis verteilen, oder? Wir erhalten einen Basiswinkel `$ba` für unsere Verteilung, drehen jedes Element um seinen Index mal diesen `$ba`-Winkel und verschieben es dann entlang seiner `x`-Achse.
$n: 12;
$ba: 360deg/$n;
.item {
transform: rotate(var(--a, 0deg)) translate(1.5*$d);
@for $i from 1 to $n { &:nth-child(#{$i + 1}) { --a: $i*$ba } }
}
Das Ergebnis scheint zunächst in Ordnung zu sein.
Siehe den Pen von thebabydino (@thebabydino) auf CodePen.
Bei näherer Betrachtung stellen wir jedoch fest, dass wir ein Problem haben: Element `11` liegt sowohl über Element `0` als auch über Element `10`, während Element `0` unter Element `1` und `11` liegt.

Es gibt eine Reihe von Möglichkeiten, dies zu umgehen, aber sie fühlen sich eher wie Hacks an und sind mühsam, da sie entweder das Duplizieren von Elementen, das Umgehen von Einschränkungen mit `clip-path`, das Hinzufügen von Pseudo-Elementen zum Abdecken von Ecken oder deren Ausblenden über `overflow` beinhalten. Einige davon sind besonders ineffizient, wenn wir auch die Position der Elemente animieren oder die Elemente halbtransparent machen wollen.
Was ist also die beste Lösung?
3D zur Rettung! Eine wirklich nette Sache, die wir in diesem Fall tun können, ist, diese Elemente in 3D zu drehen, sodass ihr oberer Teil nach hinten (hinter die Bildschirmebene) und ihr unterer Teil nach vorne (vor die Bildschirmebene) geht. Dies tun wir, indem wir eine dritte `transform`-Funktion – ein `rotateX()` – verketteln.
transform: rotate(var(--a, 0deg)) translate(1.5*$d) rotateX(40deg)
Zu diesem Zeitpunkt scheint sich nichts zum Besseren verändert zu haben – wir haben immer noch dasselbe Problem wie zuvor und zusätzlich scheinen unsere Elemente entlang ihrer `y`-Achsen geschrumpft zu sein, was nicht das war, was wir wollten.
Siehe den Pen von thebabydino (@thebabydino) auf CodePen.
Lassen Sie uns diese Probleme nacheinander angehen. Zuerst müssen wir dafür sorgen, dass alle unsere Elemente zum selben 3D-Rendering-Kontext gehören, und das tun wir, indem wir `transform-style: preserve-3d` auf ihr Elternelement (in diesem Fall das `body`-Element) anwenden.

Wer aktuelle Firefox-Versionen nutzt, hat vielleicht ein anderes Problem bemerkt. Element `8` erscheint sowohl über dem vorherigen (7) als auch über dem nächsten (9), während Element `7 sowohl unter dem vorherigen (6) als auch unter dem nächsten (8) erscheint.

Das passiert in Chrome oder Edge nicht und liegt an einem bekannten Firefox-Bug, bei dem 3D-transformierte Elemente nicht immer in der richtigen 3D-Reihenfolge gerendert werden. Glücklicherweise ist dies jetzt in der Nightly-Version (55) behoben.
Kommen wir nun zum Problem der schrumpfenden Höhe. Wenn wir das erste Element nach der letzten Drehung von der Seite betrachten, sehen wir Folgendes:
Die Linie `AB`, die um `40°` von der Vertikalen abweicht, ist die tatsächliche `height` unseres Elements (h). Die Linie `CD` ist die Projektion dieser Linie `AB` auf die Bildschirmebene. Das ist die Größe, die wir als Höhe unseres Elements nach der Drehung *wahrnehmen*. Wir wollen, dass diese gleich `d` ist, was auch gleich der anderen Dimension unseres Elements (seiner `width`) ist.
Wir zeichnen ein Rechteck, dessen linke Kante diese Projektion (`CD`) ist und dessen rechte obere Ecke der Punkt `A` ist. Da gegenüberliegende Kanten in einem Rechteck gleich sind, ist die rechte Kante `AF` dieses Rechtecks gleich der Projektion `d`. Da die gegenüberliegenden Kanten eines Rechtecks auch parallel sind, erhalten wir auch, dass der Winkel `∠OAF` (oder `∠BAF`, dasselbe) dem Winkel `∠AOC` entspricht (es sind wechselseitige Innenwinkel).
Entfernen wir nun alles außer dem rechtwinkligen Dreieck `AFB`. In diesem Dreieck hat die Hypotenuse `AB` eine Länge von `h`, der Winkel `∠BAF` ist ein `40°`-Winkel und die Kathete `AF` ist `d`.
Von hier aus haben wir, dass der Kosinus des Winkels `∠BAF` gleich `d/h` ist.
cos(40°) = d/h → h = d/cos(40°)
Das Erste, was uns in den Sinn kommt, ist, dass wir, wenn wir wollen, dass die Projektion unserer Elemente so hoch aussieht, wie sie breit ist, ihr eine Höhe von `$d/cos(40deg)` geben müssen. Dies behebt jedoch nicht den gequetschten Text oder gequetschte Hintergründe, daher ist es besser, sie bei ihrer ursprünglichen `height: $d` zu belassen und eine weitere `transform`-Funktion zu verketteln – ein `scaleY()` mit einem Faktor von `1/cos(40deg)`. Noch besser, wir können den Rotationswinkel in einer Variablen `$ax` speichern und dann haben wir:
$d: 2em;
$ax: 40deg;
.item {
transform: rotate(var(--a, 0deg)) translate(1.5*$d) rotateX($ax) scaleY(1/cos($ax));
}
Die obigen Änderungen ergeben das gewünschte Ergebnis (nun ja, in Browsern, die CSS-Variablen unterstützen und keine Probleme mit der 3D-Reihenfolge haben).

Diese Methode ist sehr praktisch, da sie nicht erfordert, dass wir für ein einzelnes Element etwas anderes tun, und sie funktioniert gut, ohne weitere Anpassungen, bei halbtransparenten Elementen. Die obige Demo ist jedoch nicht besonders spannend, schauen wir uns also ein paar etwas interessantere Anwendungsfälle an.
Beachten Sie, dass die folgenden Demos nur in WebKit-Browsern funktionieren, dies hat jedoch nichts mit der im Artikel vorgestellten Methode zu tun, sondern ist lediglich das Ergebnis der derzeit schlechten Unterstützung von `calc()` für andere Werte als Längenangaben.
Das erste ist ein Tic-Toc-Loader, eine reine CSS-Nachbildung von einem GIF von Geometric Animations Tumblr. Die Animation ist in diesem Fall ziemlich schnell, daher ist es möglicherweise schwer, den Effekt hier zu bemerken. Sie funktioniert nur in WebKit-Browsern, da Firefox und Edge `calc()` nicht als `animation-delay`-Wert unterstützen und Firefox `calc()` auch nicht in `rgb()` unterstützt.

Der zweite ist ein Seemuschel-Loader, ebenfalls eine reine CSS-Nachbildung von einem GIF vom selben Tumblr und aus denselben Gründen wie der vorherige nur für WebKit.

Die dritte Demo ist ein Diagramm. Sie funktioniert nur in WebKit-Browsern, da Firefox und Edge `calc()`-Werte innerhalb von `rotate()`-Funktionen nicht unterstützen und Firefox `calc()` auch nicht innerhalb von `hsl()` unterstützt.

Die vierte ist eine kreisförmige Bildergalerie, nur WebKit aus demselben Grund wie das obige Diagramm.

Die fünfte und letzte ist eine weitere Ladeanimation, diesmal inspiriert von den Disc Buddies.gif von Dave Whyte.

Warum das Problem der schrumpfenden Höhe nicht dadurch lösen, indem man es nur sehr wenig dreht (ich habe 0,1 Grad versucht und es funktioniert in Firefox), anstatt 40 Grad?
Weil ich zeigen wollte, wie man dieses Problem logisch löst (nicht durch Versuch und Irrtum/Annäherungen), wenn man sich in einer Situation befindet, die einen größeren Rotationswinkel erfordert und daher den Höhenunterschied stärker hervorhebt.
Ich habe den Ordnungsfehler in Firefox 53.0.3 (64-Bit) für Mac nicht. Es ist perfekt!
das ist wirklich seltsam, unter Windows funktioniert es.
aber auf meinem Mac funktioniert es immer noch nicht, egal welcher Browser.
Habe das vor einem Jahr gemacht, musste aber schummeln :)
http://codepen.io/wintercounter/pen/LZRBLj
Das Logische ist großartig.
Aber es gibt eine Verwirrung für mich,
warum hat die Reihenfolge der Schlüsselwörter `rotate` und `translate` unterschiedliche Auswirkungen?
wie dieser Pen
Und das Endergebnis funktioniert nicht.
http://codepen.io/thebabydino/pen/3d16c309036a90ff2bbb96fbb2be1081/
Ich habe Opera, Firefox, Safari und Chrome ausprobiert, das Element 0 liegt immer noch unter 1 und 11.
Im Allgemeinen sind Transform-Funktionen nicht kommutativ, da die Matrixmultiplikation im Allgemeinen nicht kommutativ ist.
Wenn Sie eine uniforme (isotrope) Skalierungstransformation mit einer Drehung verketten, dann ja, erhalten Sie unabhängig von der Reihenfolge dasselbe Ergebnis, aber das ist nur ein Sonderfall.
Im Fall einer Drehung, gefolgt von einer Verschiebung, führen Sie zuerst die Drehung durch. Wenn der Wert für die Drehung zum Beispiel `90deg` ist, dann geht die `x`-Achse des Elements nach der Drehung von der Rechtsrichtung in die Richtung nach unten. Wenn Sie das Element nach dieser Drehung entlang seiner `x`-Achse in positive Richtung verschieben möchten, bedeutet dies, dass Sie es nach unten verschieben.
Im Gegensatz dazu, wenn Sie das Element vor jeder Drehung entlang seiner `x`-Achse verschieben möchten, verschieben Sie es nach rechts.
Und das Endergebnis funktioniert bei mir in Chrome/Opera, Edge und Firefox 55+. Es mag einige Probleme auf OSX/iOS geben, aber ich habe keine Ahnung, warum...
Die letzte Demo in Firefox (50.0.2) zeigt immer noch, dass Feld 11 über Feld 0 liegt.
http://codepen.io/thebabydino/pen/LyQBrR
richtig. vielleicht ist das mein Mac-Problem.
es funktioniert unter Windows. und auf allen Browsern auf dem Mac funktioniert es nicht.
Ich habe einen Screenshot gemacht.
https://singlexyz.github.io/screenshot.png
Sieht gut aus in Firefox 53.0.3.
Ich habe auf die neueste Firefox-Version 53 aktualisiert und immer noch dasselbe Problem, aber diesmal liegt 6 unter 7 und 8.
7 unter 6 und 8 ist das, was ich auch in Firefox 53 sehe, wie im Screenshot im Artikel gezeigt. Dieses Problem ist jedoch in Firefox 55+ behoben.
Toller Artikel, habe viel gelernt!! Danke Ana