CSS レイヤー構成図を3D作成 テキストは面に対して直立し鏡面反射

WEBサイト等でよく見かけるレイヤーを説明するための図、イラストレーター等の図形描画ソフトで作成した画像を読み込んでいることも多いです。
今回は、これをCSSの3D機能を使って作成してみましたので紹介いたします。
レイヤーを水平方向に上から並べたパターンと、垂直方向に少し傾きをつけて並べたパターンの2つあります。

レイヤー面には透明感を出していますので、背面に位置するレイヤーのテキストも視認可能です。
水平方向に並べたパターンではテキストは起き上がらせて、ついでにテキストの下にはうすい影を付け、かつレイヤー面に鏡面反射させてみました。

水平方向に上から並べたパターン

CODEPEN

「Run Pen」をクリックしてください。

See the Pen layer_horizon by blue moon (@blue-moon) on CodePen.

HTMLファイル

<body>
  <div class="container">
    <div class="layer top">
      <p>top</p>
    </div>
    <div class="layer middle">
      <p>middle</p>
    </div>
    <div class="layer bottom">
      <p>bottom</p>
    </div>
  </div>
</body>

CSSファイル

.container {
  margin:100px;
  display: flex;
  flex-direction: column;
    /*transform-style: preserve-3d; 直接の子要素であるレイヤーに対しては、3D空間配置には設定していない。*/
}

.layer {
  width: 180px;
  height: 180px;
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  color: #fff;
  font-weight: 700;
  border-radius: 10px;
  border: 5px rgba(255,255,255,0.4) solid;  /* 白に透明度を追加 */
  box-shadow: rgba(0,0,0,0.2) 0px 4px 10px,  /* より自然な影にしたい場合は、影を複数指定することが可能 */
              rgba(0,0,0,0.3) 0px 5px 25px;  
  transform: rotateX(75deg) skew(30deg,0deg);  /* X軸に対して75度回転、90度で完全にボックスが倒れた状態で見えなくなる。そして歪ませる。 */
  transform-style: preserve-3d;  /* 子要素(pタグ)を3D空間に配置 */
}

.top {
  top: -45px;
  background: rgba(0,17,255,0.3);
  border-top: 4px rgba(0,17,255,0.1) solid;  /* 四方の枠は白に透明度を追加した色だが、奥側部分のみ背景色に透明度を調整した色に変更 */
  border-right: 2px rgba(0,17,255,0.2) solid;  /* 上記(top)のように、色を濃くするborderは、必ずしもbottomとrightの組み合わせとはならない。 */
  /* z-index: 10; レイヤーは透明度があるので不要だが、テキスト等と重なり調整したい場合には適宜、但し重なる箇所のレイヤーの色が多少場合あり。 */
}

.middle {
  top: 0%;
  background-color: rgba(0,255,238,0.3);
  border-top: 4px rgba(0,255,238,0.1) solid;
  border-right: 2px rgba(0,255,238,0.2) solid;
  /* z-index: 5; */
}

.bottom {
  top: 45px;
  background-color: rgba(238,0,255,0.3);
  border-top: 4px rgba(238,0,255,0.1) solid;
  border-right: 2px rgba(238,0,255,0.2) solid;
}

p {
  margin: 0;
  position: relative;
  text-shadow: 1px 2px 2px #999;
  transform: perspective(130px) translateZ(10px) rotateX(-90deg) rotateY(-15deg);  /* perspectiveで奥行き(視点)を変更 */
  -webkit-box-reflect: below -6px  /* 鏡面反射 */
                      -webkit-gradient(linear, left bottom, left top,  /* topからbottomにかけて */
                      from(#fff),  /* 白から始まり */
                      color-stop(0.2, rgba(255,255,255,0.4)),  /* グラデーションの停止点20% */
                      color-stop(0.4, rgba(255,255,255,0.2)),  /* グラデーションの停止点40% */
                      to(rgba(255, 255, 255, 0)));  /* 透明で終わる */
}

p::before { /* レイヤー面にテキストの影を落とすための疑似要素 */
  position: absolute;
  top: 0%;
  left: -10%;
  width: 120%;
  height: 200%;  /* X軸に回転させる(水平に近い状態にする)ため、大きめに */
  content: "";
  border-radius: 50%;
  background: rgba(255,255,255,0.8); /* 白に若干透明度を */
  filter: blur(25px);  /* 透明度があるため広い範囲にぼかしているが、お好みで */
  transform: rotateX(85deg) rotateY(0deg) translateZ(5px);  /* 位置調整、悩み所 */
}

3D空間

厳密に言うと3D空間となっているのは、テキストの方のみです。
レイヤー(面)は、transformプロパティで回転と歪みを持たせ、上下の間隔を均等にずらしているだけです。

しかし、こうするとなるとテキストも面に貼りつくことになるので、当然読みづらくなります。
よって、テキストを起き上がらせるために、テキストを3D空間としています。
それが、transform-style: preserve-3d; です。
この値にはもう一つ flat (初期値)というものがあり、文字通りこれを指定すると平面になります。

3D空間を作成ということなので、3D配置したい要素そのものに設定するものではありません。

3D表示にするためのプロパティ transform-style は、3D配置させたい要素の親要素に設定します。
また、このプロパティは継承されないため、直接の親要素に設定します。

MDN > CSS: カスケードスタイルシート > transform-style

3D空間の視点

Pタグに、transform: perspective(130px) ~途中省略~; で3Dの奥行き(視点)を設定しています。
テキストが下から上にかけて少し大きくなっているのが分かるでしょうか。
この奥行きの変更は、親要素にperspectiveプロパティを設定することでも可能です(例えば、perspective: 130px;)。
つまりこの違いは、transformで指定した場合は、その要素自身のみが対象となるということです。

尚、この値は数値が小さい程奥行が出ます。つまり、ユーザーとの視点が近くなるということだそうです。

MDN > CSS: カスケードスタイルシート > perspective

鏡面反射

この -webkit-box-reflect プロパティの詳細については、下記ページ(英語)にあるとおり標準化されたものではなく、ブラウザーによっては表示されない場合もあり、将来動作が変更される場合もありますので、ご注意ください。
但し、あくまでテキストの装飾として使用されるため、もしサポートされていなくても大きなトラブルにはならないと思いますが、念のためご注意ください。

MDN > CSS: カスケードスタイルシート > -webkit-box-reflect

因みに、この値は、左右上下の選択と元の要素の距離の指定が可能です。

このプロパティが使用できずにどうしても鏡面反射させたい場合は、X軸回転して…等いろいろ工夫すれば実現できるかもしれません。
ただ今回の場合は、もともとの要素自体を回転したりしているので、とてもややこしくなります。
やはり1つのプロパティで実現できる方が断然楽なので、ずーとサポートしてもらいたいものです。

グラデーションの記述については、下記の記事でも紹介しています。ご参考までに。

垂直方向(縦)に少し傾きをつけて並べたパターン

CODEPEN

「Run Pen」をクリックしてください。

See the Pen layer_vertical by blue moon (@blue-moon) on CodePen.

HTMLファイル

前述のパターンと同じです。

CSSファイル

.container {
  margin: 50px;
  display: flex;
  flex-direction: column;
  transform-style: preserve-3d;  /* レイヤー構成図を3D空間に配置 */
  perspective: 1000px;  /* 奥行き(ユーザーとの視点距離)、今回は親要素に設定、直接の子要素レイヤーを3D空間に配置 */
}

.layer {
  /* 前述パターンと同じため省略 */
  border: 3px rgba(255,255,255,0.4) solid;
  box-shadow: rgba(0,0,0,0.3) 2px 4px 10px,
              rgba(0,0,0,0.3) 1px 2px 15px;
  transform: rotateY(-30deg)  rotateZ(10deg);  /* Y軸を基準に-30度回転、Z軸を基準に10度回転 */
  transform-origin: 50% 50% 0;  /* 初期値 */
}

.top {
  top:0;
  left: 0;
  background: rgba(0,17,255,0.3);
  border-bottom: 2px rgba(0,17,255,0.2) solid;  /* 前述のパターンと異なり、奥と下になる枠の色を変更 */
  border-left: 4px rgba(0,17,255,0.2) solid;
}

.middle {
  left: 50px;
  background-color: rgba(0,255,238,0.3);
  border-bottom: 2px rgba(0,255,238,0.2) solid;
  border-left: 4px rgba(0,255,238,0.2) solid;
  transform: rotateY(-30deg)  rotateZ(10deg) scale(0.975);  /* 見た目はほとんど変わらないが、背面にいくにつれて若干小さ目に、お好みで */
}

.bottom {
  left: 100px;
  background-color: rgba(238,0,255,0.3);
  border-bottom: 2px rgba(238,0,255,0.2) solid;
  border-left: 4px rgba(238,0,255,0.2) solid;
  transform: rotateY(-30deg)  rotateZ(10deg) scale(0.95);  /* middleより更に小さ目に、お好みで */
}

/* このpタグは3D表示していません。テキストは普通にレイヤー面に貼りついている状態 */
p {  
  font-size: 25px;
  text-shadow: 1px 2px 2px #999;
}

こちらの縦のレイアウトの場合は、レイヤー構成図に限らず他の用途でも使用できそうです。
例えば、マウスオーバーしたボックスが上や横に飛び出す、背景色や枠の透明度を調整し強調させる等… 思い浮かんだアイデアです。

タイトルとURLをコピーしました