受け入れられたフロントエンドチャレンジ:CSS 3D Cube

公開: 2022-03-10
クイックサマリー↬チャレンジは好きですか? 今まで出会ったことのない仕事を引き受けて、締め切りを守ってくれませんか? タスクの実行中に、解決できないと思われる問題が発生した場合はどうなりますか? 実際のプロジェクトで初めてCSS3D効果を使用した経験を共有し、挑戦するように促したいと思います。 CreativePeopleのマネージャーであるEugeneが私に手紙を書いたのは普通の日でした。 彼は私にビデオを送って、彼が新しいプロジェクトのコンセプトを開発していると説明し、私がビデオにあるようなものを開発することが可能かどうか疑問に思いました。

あなたは挑戦が好きですか? 今まで出会ったことのない仕事を引き受けて、締め切りを守ってくれませんか? タスクの実行中に、解決できないと思われる問題が発生した場合はどうなりますか? 実際のプロジェクトで初めてCSS3D効果を使用した経験を共有し、挑戦するように促したいと思います。

CreativePeopleのマネージャーであるEugeneが私に手紙を書いたのは普通の日でした。 彼は私にビデオを送って、彼が新しいプロジェクトのコンセプトを開発していると説明し、私がビデオにあるようなものを開発することが可能かどうか疑問に思いました。

SmashingMagの詳細

  • Beercamp:CSS3Dを使った実験
  • クリップパスを使用してレスポンシブシェイプを作成し、箱から出して
  • ハードウェアアクセラレーションされたCSSで遊んでみましょう

これは、軸の1つを中心に回転する3Dオブジェクト(正確には直方体)でした。 私はすでにCSS3Dでの作業経験があり、解決策が頭に浮かび始めました。 「CSS3Dcube」などのキーワードをグーグルで検索してアイデアを確認し、Eugeneに可能だと答えました。

ジャンプした後もっと! 以下を読み続けてください↓

ユージーンの次の質問は、私がプロジェクトを引き受けるかどうかでした。 トリッキーな仕事が好きなので、断れませんでした。 当時、自分が何をしているのかわからなかったのですが、決心がつきませんでした。

斧を研ぐ

軸について思い出してみましょう。戦争軸ではなく、数直線です。これは、学校で勉強した3次元デカルト座標系と同じ軸です。 ウィキペディアが私たちに言うように:

3次元空間のデカルト座標系は、ペアごとに垂直で、3つの軸すべてに単一の長さの単位があり、各軸に方向がある、順序付けられた線(軸)のトリプレットです。

次の図は、Webブラウザで軸がどのように方向付けられているかを示しています。

Z軸が視聴者の方を向いている右手系の3次元デカルト座標系。
z軸が視聴者の方を向いている右手系の3次元デカルト座標系。 (画像:ウィキメディアコモンズ)(拡大版を表示)

x軸は水平、y軸は垂直、z軸は画面から手前に出ているように見えます。 z軸のゼロ値は画面の平面です。 これを覚えて。

視点を片付ける

3Dオブジェクトを作成するには、遠近感のある要素(「シーン」と呼びましょう)が必要でした。 パースペクティブはシーンの深さであり、含まれるオブジェクトのサイズによって異なります。

 .scene { perspective: 800px; }

遠近法が小さすぎると、オブジェクトが歪む可能性があります。 大きすぎると、3D効果がゼロになります。

CodePenのAnnaSelezniova(@askd)によるPenjqgMvLを参照してください。

さらに、シーン内のすべてのオブジェクトに対して1つの画角しかありません。 また、3D効果は視点の位置によって異なります。

CodePenのAnnaSelezniova(@askd)によるPenoxKzKvを参照してください。

では、どのように視点を計算するのでしょうか? 私はそれが回転軸に依存することを発見しました。 x軸の場合、高さの値に4を掛けた値が適合します。 y軸の場合、幅の値に4を掛けたものになります。これが私の魔法の公式です。

 const perspective = dimension * 4;

あらゆる面から考える

遠近法を決定した後、3Dオブジェクトの作成を開始しました。 キューブを選んだのは、それが単純で予測可能だからです。 立方体要素は、幅と高さが定義された(たとえば、 200px )、比較的配置された通常のdivとして作成されます。 これは、 preserve-3dの値を持つtransform-styleプロパティを介して3Dオブジェクトに変換されます。 3Dワールドのルールに従って、ネストされたすべての要素をレンダリングするようにブラウザに指示します。

私の場合、立方体には6つのdiv(または「サイド」)があり、絶対的に配置されています。 クラス名は、側面の初期位置( backleftrighttopbottomfront )に対応しています。 マークアップは次のとおりです。

 <div class="scene"> <div class="cube"> <div class="side back"></div> <div class="side left"></div> <div class="side right"></div> <div class="side top"></div> <div class="side bottom"></div> <div class="side front"></div> </div> </div>

デフォルトでは、すべての辺が1つの平面上にあります。 だから、私はそれらを再配置する必要がありました。 これがどのように見えるかです:

CodePenのAnnaSelezniova(@askd)によるペンmPNwPxを参照してください。

そして、これが結果のCSSです:

 .cube { position:relative; width: 200px; height: 200px; transform-style: preserve-3d; } .side { position: absolute; width: 200px; height: 200px; } .back { transform: translateZ(-100px); } .left { transform: translateX(-100px) rotateY(90deg); } .right { transform: translateX(100px) rotateY(90deg); } .top { transform: translateY(-100px) rotateX(90deg); } .bottom { transform: translateY(100px) rotateX(90deg); } .front { transform: translateZ(100px); }

立方体を回転させるには、立方体要素のtransformプロパティをx軸に沿った任意の回転角度に設定します。

 .cube { transform: rotateX(42deg); }

欠点を克服する

割り当てによると、立方体をx軸に沿ってのみ回転させることになっていたので、左側または右側は必要ありませんでした。 残りの辺の初期位置に合わせるためにキャプションを追加しました。

立方体を回転させ始めたところ、底面と背面のキャプションが上下逆に表示されていることがわかりました。

CodePenのAnnaSelezniova(@askd)によるPenGZVvMRを参照してください。

この問題を解決するために、これらの各辺をx軸に沿って180度回転させました。

 .back { transform: translateZ(-100px) rotateX(180deg); } .bottom { transform: translateY(100px) rotateX(270deg); }

画面を超えて

私は実際のコンテンツで側面を埋め始め、すぐに別の問題に遭遇しました。 1ピクセルの点線を表示する必要がありましたが、ぼやけて見栄えが悪くなりました。

CodePenのAnnaSelezniova(@askd)によるPenVjeBPgを参照してください。

私はすぐに問題が何であるかを理解しました。 画像が画面を超えて広がる3Dテレビ広告を覚えていますか? それは私のキューブではそのようなものでした。

立方体を左側または右側から見ると、その中心が画面の平面上にあり(z軸上でゼロ)、前面が画面の向こう側にあることがわかります。 したがって、それは視覚的に増加し、ぼやけた。

CodePenのAnnaSelezniova(@askd)によるPenWwVEMRを参照してください。

この問題を解決するために、立方体をz軸に沿って移動し、前面を画面の平面に揃えました。

 .cube { transform:translateZ(-100px); }

これがキューブです。ほぼ準備ができています。

CodePenのAnnaSelezniova(@askd)によるPenXdveryを参照してください。

マジックナンバーズの使用

魔法の数100を使用して、軸に沿って辺をシフトしていることに気付いたと思います。 値100は、テストキューブの高さのちょうど半分です。 なぜ高さの半分? それは、立方体の側面に内接する円の半径であるためです(これは明らかに正方形です)。

 const offset = dimension / 2;

三角柱を回転させる必要がある場合、円は三角形に内接します。 この場合、オフセットの式は次のようになります。

 const offset = dimension / (2 * Math.sqrt(3));

キューブを吹き飛ばす

タスクが完了したと見なすには、さまざまなブラウザーで結果をテストする必要がありました。

Internet Explorerで見た写真は、私をうつ病に陥らせました。 私が話していることを理解するには、お気に入りのブラウザで以下のデモをご覧ください。 1つのプロパティを変更したため、InternetExplorerでキューブが正しく表示されませんでした。 ただし、以下のデモの下の段落を読むまで、ソースコードを覗き見しないでください。

CodePenのAnnaSelezniova(@askd)によるPenXKWMwVを参照してください。

実際のところ、Internet Explorerは、 preserve-3dの値を持つtransform-styleプロパティをサポートしていません。 これについては、信頼できるリソースであるCan I Use(注1を参照)を見て学びました。 上記のデモでは、 preserve-3dflatに置き換えました。 あなたはすでにそれを知っていましたか? ねえ、私はあなたに覗かないように言った!

私は動揺しましたが、あきらめるつもりはありませんでした。 問題は、何か新しいことを学ぶ機会です。 その上、私は挑戦を受け入れました。

支点を探す

transform-style: preserve-3dを使用せずに3Dオブジェクトを作成する方法を探していましたが、最終的には便利なプロパティであるtransform-originを発見しました。 要素の変換の中心点を決定します。 以下にインタラクティブなデモを作成しました。これは、その仕組みを理解するのに役立ちます。

CodePenのAnnaSelezniova(@askd)によるPenrLNmBpを参照してください。

デモの要素の3D回転は、立方体の前面と非常によく似ていますね。 それが私が使ったものです。

(ちなみに、 backface-visibility: hiddenのチェックボックスを選択しようとしましたか?このプロパティは、3D変換中に要素の背面を非表示にするために使用されます。)

最初からやり直す

キューブをやり直し始めました。 シーン全体を操作する必要がなかったので、 scene要素のperspectiveプロパティを削除し、それを各3D変換に追加して、すべての要素が独立して変換されるようにしました。 また、各辺に新しいプロパティを設定しました。立方体の中心の位置に等しい値を持つtransform-originと、 backface-visibility: hiddenです。 スタイルがどのように変更されたかは次のとおりです。

 .scene { } .cube { position: relative; width: 200px; height: 200px; transform: perspective(800px) translateZ(-100px); } .side { position: absolute; transform-origin: 50% 50% -100px; backface-visibility: hidden; }

私は適切な場所に側面を配置する必要がありました。 transform-originプロパティがあるため、シフトする必要はなく、軸を中心に回転させるだけです。 まるで魔法のようです! それがどのように見えるか見てみましょう:

CodePenのAnnaSelezniova(@askd)によるPenzBYwEmを参照してください。

側面を配置するためのCSSは次のとおりです。

 .back { transform: perspective(800px) rotateY(180deg); } .top { transform: perspective(800px) rotateX(90deg); } .bottom { transform: perspective(800px) rotateX(-90deg); } .front { transform: perspective(800px); }

そして、ここで新しいキューブの動作を確認できます。

CodePenのAnnaSelezniova(@askd)によるペンwWvdXdを参照してください。

シーザーに恩返しシーザーとは

2番目の立方体は、最初の立方体と同じように見え、回転します。 ただし、この場合、それぞれの側を個別に変換する必要があります。 これは、特に中間の回転角を制御したい場合は、それほど簡単ではないかもしれません。

さらに、Chromeでデモを開くと、回転中に側面が点滅することがわかります。これは非常に苛立たしいことです。

最後に、 transform-style: preserve-3dを使用して、両方のアプローチを適用しました。 最初のキューブがデフォルトです。 2番目のキューブは、 preserve-3dをサポートしていないInternetExplorerおよびブラウザー用です。

数学の力を使う

最後に、視差効果を実装する必要がありました。 通常、この効果は、マウスカーソルの位置またはスクロールバーの位置に関係なく、ユーザーのアクションに応答します。 この場合、効果は回転角によって異なります。

CodePenのAnnaSelezniova(@askd)によるPenQENyqmを参照してください。

それで、私はどのようなデータを持っていますか? まず、キャプションの位置の始点と終点、または簡単に言えば、側面の中心から上下にoffsetしました。 第二に、私は立方体の回転angleを持っていました。

私は数式を開発するのに何時間も費やしました。 それから、それは私に夜明けしました。 頭に浮かんだのは次のとおりです。

サイン関数とコサイン関数のグラフ
サイン関数とコサイン関数のグラフ(画像:ウィキメディアコモンズ)(拡大版を表示)

サインとコサインの助けを借りて、角度に応じて各キャプションのオフセットを簡単に計算しました。 これが私が思いついた式です:

 const front_offset = offset * sin(angle) * -1; const bottom_offset = offset * cos(angle); const back_offset = offset * sin(angle); const top_offset = offset * cos(angle) * -1;

まとめ

これで課題は完了です。結果を楽しんで共有することができます。 それがどのように機能するかを自分で確かめてください。 スクロールキーまたは矢印キーを使用して、プロモーションブロックを回転させます。 また、右の黒い三角形を上下に引いて回転角を手動で制御してみてください(残念ながら、この機能はInternet Explorerでは機能しません)。 かなり良さそうですね。 そして、パフォーマンスはかなり高いです(毎秒約60フレーム)。

このウェブサイトの開発に参加できてとてもうれしく思います。 私はCSS3Dでの作業で有益な経験を積み、多くの興味深いプロパティを発見しました。 さらに重要なことに、私は人が決してあきらめるべきではないことを学びました。 ほとんどの場合、タスクを実行する方法が見つかります。

あなたが私の話を楽しんで、新しい挑戦に挑戦する準備ができていることを願っています。