基本
CSS 3D(Transform)は平面に奥行きをつけて変形させます
光源をもとにして陰影をつけることはできません
perspective
の値は平面(z=0)とユーザー(視線)との距離です
- 親要素に対して設定する場合
perspective: 数値px; - 対象要素に設定する場合
「transform関数のperspective(数値px)」を対象要素に設定することもできます
*例:transform: perspective(500px);
<div class="box-parent">
<div class="box" style="width:100px; height:100px; background:#ccc; margin: 0 auto"></div>
</div>
.box-parent{
perspective: 200px;
}
.box{
transform:rotateX(45deg)
}
.box{
transform:perspective(200px) rotateX(45deg)
}
transform-style: preserve-3d;
要素の子要素を3D空間に配置することを示します
perspective-originについて
親要素にtransform-style: preserve-3d;
を設定するとperspective-origin
でユーザーの目線を変更できます
斜めから画面を見た場合など
*初期値は50% 50%(center center)
- キーワード値
Xではleft(0)・center(50%)・right(100%)
Yではtop(0)・center(50%)・bottom(100%) - 値が1つ:x-position
- 値が2つ:x-position y-position
transform-style: preserve-3d;
で宣言した時
同じ空間の要素はtransform:translateZ
で重なりの順番を指定
*translateZは%指定はできません
<div class="base">
<div class="first">1</div>
<div class="second">2</div>
<div class="third">3</div>
</div>
<style>
/*boxのポジションや外観のcssは省略*/
.base{
transform-style: preserve-3d;
perspective: 15px;
perspective-origin: -100% 50%;/*左横方向から見るため*/
}
.first{
transform: translateZ(1px);
}
.second{
transform: translateZ(2px);
}
.third{
transform: translateZ(3px);
}
</style>
右上部のControlsを開きNO1(奥行き)で
奥行き(translateZ)と画面と視線の距離(perspective)と目線(perspective-origin)を変更して見え方を確認
*正方形を2枚重ねているので奥行き(translateZ)をつけて、目線(perspective-origin)を変更すると下になっている正方形(黒)が見えます
*z軸座標がperspectiveの値より大きい要素は描画されません(ユーザーを通りこしている)
<style>
.parent{
width:200px;
height:200px;
margin: 0 auto;
position: relative;
transform-style: preserve-3d;
perspective: 200px;
perspective-origin:50% 50%;
}
.box{position: absolute;top:0;left:0;width:100%;height:100%;background:#222;font-size: 80px;line-height: 200px;text-align: center;}
.box1.target{
box-sizing: border-box;
background:white;
border:solid 3px #ccc;
transform: translateZ(0);
}
</style>
<div class="parent">
<div class="box"></div>
<div class="box target">平面</div>
</div>
回転
rotateX, rotateY, rotateZ(それぞれXYZの軸に対する回転)とrotate3dがあります
rotate・rotateX・rotateY・rotateZ
ちなみにrotateZは3D空間でも2Dのrotateと同じ動きです
.box-parent{
transform-style: preserve-3d;
perspective: 200px;
}
.box{
transform:rotateZ(45deg)
}
transform-origin
でrotate(回転)の回転軸の位置を変更できます(scaleの原点にもなります)
transform-origin:値
*transform-originを設定しない場合はデフォルト値(50% 50%)で要素の中央を中心に回転
値は2Dの回転では要素の左上を起点(0 0)として値を設定
マイナスや%
Xではleft(0)・center(50%)・right(100%)
Yではtop(0)・center(50%)・bottom(100%)
といったキーワードもつかえます
*値が1つのときは、Y方向は「center」とみなされます
transform-originの値が3つある時
3つ目はZオフセットです
*値はpxなどのlengthデータ型で%は不可
右上部のControlsを開きNO2(回転)で
回転軸と角度(rotate)と回転軸の位置(transform-origin)を変更して動きを確認
*特にoriginZの動きを確認するため実際のコードは視線をズラし(perspective-origin:-10% 50%;
)後ろの正方形はtransform: translateZ(-5px);
をつけています
.parent{
perspective: 500px;
}
.rotate{
background:white;
border:solid 3px #ccc;
transform-origin: center center 0;
transform:rotateX(0) rotateY(0) rotateZ(0);
}
右上部のControlsを開きNO3(立方体)で
距離(perspective)と視点(perspective-origin)を変更して見え方を確認
*translateZはあえて若干遠くしている(105px)
立方体
6個の同じ位置に重ねた正方形を作り
正方形の中心を軸にそれぞれX軸とY軸に回転して配置
*回転の起点を設定するtransform-originのデフォルト値が中心(center center)のため設定の必要はなし
<style>
.base{
margin: 0 auto;
position:relative;
width:200px;
height:200px;
transform-style: preserve-3d;
perspective: 500px;
perspective-origin: 50% 50%;
}
.cube{position: absolute; top:0; left:0; width:100%;height:100%;opacity:0.7;font-size: 60px;line-height: 200px; text-align: center;}
.front {
background: rgba(0, 0, 0, 0.3);
transform: translateZ(100px);
}
.back {
background: green;
color: white;
transform: rotateY(180deg) translateZ(100px);
}
.right {
background: yellow;
transform: rotateY(90deg) translateZ(100px);
}
.left {
background: pink;
transform: rotateY(-90deg) translateZ(100px);
}
.top {
background: orange;
transform: rotateX(90deg) translateZ(100px);
}
.bottom {
background: blue;
transform: rotateX(-90deg) translateZ(100px);
}
</style>
<div class="base">
<div class="cube front">0</div>
<div class="cube back">Y(180)</div>
<div class="cube right">Y(90)</div>
<div class="cube left">Y(-90)</div>
<div class="cube top">X(90)</div>
<div class="cube bottom">X(-90)</div>
</div>
rotate3d(x, y, z, a)
要素を三次元空間内の固定した軸を中心に回転させる変形を定義します
x, y, zの値は0から1でaは回転する角度です
*firefoxとsafariではrotate3dのアニメーションで一気に一回転させるコードは動かない😂
右上部のControlsを開きNO4(回転)で
立方体の回転(rotate3d)と回転の中心点(transform-origin)を変更して見え方を確認
<style>
.grand-parent{
perspective:500px; /*祖父母の要素にperspectiveをつける(親につけると変形したまま回転する)*/
}
.parent{
width:100px;
height:100px;
position:relative;
transform-style: preserve-3d;
transform-origin: center center 0px;/*初期値*/
animation: rotate 10s linear infinite;
}
@keyframes rotate {
to{
transform: rotate3d(1,0,0, -360deg);/* firefoxとsafariでは動きません */
}
}
.cube{position: absolute;top:0;left:0;width:100%;height:100%;font-size: 30px;line-height: 100px;text-align: center;}
.front {background: silver;transform: translateZ(50px); }
.top {background: orange;transform: rotateX(90deg) translateZ(50px);}
.back {background: tomato;transform: rotateY(180deg) translateZ(50px);}
.bottom {background: skyblue;transform: rotateX(-90deg) translateZ(50px);}
.right {background: yellow;transform: rotateY(90deg) translateZ(50px);}
.left {background: pink;transform: rotateY(-90deg) translateZ(50px);}
</style>
<div class="grand-parent" style="overflow:hidden;">
<div class="parent">
<div class="cube front">1</div>
<div class="cube top">2</div>
<div class="cube back">3</div>
<div class="cube bottom">4</div>
<div class="cube right">5</div>
<div class="cube left">6</div>
</div>
</div>
三次元空間で要素が回転した時は背面を見ることができますbackface-visibility:visible
(初期値:背面を表示)backface-visibility: hidden
(背面を非表示)
translateZが優先
画像は円の上に位置するので、裏面になった時はbackface-visibility: hidden
がなくても円で隠れます
HELLO
<style>
.card2 {
position: relative;
margin: 0 auto;
text-align:center;
width: 150px;
border-radius: 20px;
padding: 2rem 50px;
box-shadow: 0 20px 20px rgba(0, 0, 0, 0.2);
transform-style: preserve-3d;
perspective: 500px;
animation: rotate 10s linear infinite
}
.card-img{
transform: translateZ(50px);
}
.circle{
width: 150px;
height: 150px;
background: linear-gradient(120deg, #e0c3fc 0%, #8ec5fc 100%);
position: absolute;
border-radius: 50%;
transform: translateZ(25px);
}
.card-text{
font-size:30px;
font-weight: bold;
}
@keyframes rotate{
100%{ transform: rotateY(360deg); }
}
</style>
<div class="card-container">
<div class="card">
<img class="card-img" src="https://koro-koro.com/wp-content/uploads/2022/05/03.png">
<div class="circle"></div>
<p class="card-text">HELLO</p>
</div>
</div>
カードをクリックすると回転する
同じ大きさのカードを2枚を重ねて
裏側のカードはtransform: rotateY(180deg);
で回転しておく
2枚のカードはbackface-visibility: hidden
でユーザーに対して裏側を向いたときに見えなくします
<style>
.card-inner {
cursor: pointer;
position: relative;
width: 200px;
height: 200px;
margin: 0 auto;
text-align: center;
font-size:30px;
line-height:200px;
transition: transform 0.5s;
transform-style: preserve-3d;
}
.card-front,
.card-back {
position: absolute;
top:0;
left:0;
width: 100%;
height: 100%;
background: #ddd;
border-radius: 10px;
box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.2);
backface-visibility: hidden;
}
.card-back{
transform: rotateY(180deg);
}
.card-inner.rotated {
transform: rotateY(-180deg);
}
</style>
<div class="card-inner">
<div class="card-front">表</div>
<div class="card-back">裏</div>
</div>
<script>
const card = document.querySelector('.card-inner')
card.addEventListener('click',()=>{
card.classList.toggle('rotated');
})
</script>
移動と拡大縮小
translate3d(X,Y,Z)
:X,Y,Zをまとめて移動する
*Zは%指定できません
<style>
.square{
width:100px;
height:100px;
font-size:24px;
text-align:center;
line-height:100px;
background: #ccc;
margin:0 auto;
}
.square.moved{
background:green;
transform:perspective(1000px) translate3d(0px, 20px, 200px) rotateX(-55deg);
}
</style>
<div class="square">Static</div>
<div class="square moved">Moved</div>
スターウォーズ風のアニメーション
HELLO WORD
HELLO WORD
HELLO WORD
HELLO WORD
HELLO WORD
<style>
.wrap-text{
overflow:hidden;
perspective: 500px;
display: grid;
place-items: center;
background:black;
}
.scroll-text{
height:180px;
color:white;
font-size: clamp(2.5rem, 2.045rem + 2.27vw, 3.75rem);
line-height: 0.5em;
font-weight: bold;
animation: scroll 10s linear infinite alternate;
}
@keyframes scroll {
0% { transform: translate3d(0px, 100px, 200px) rotateX(45deg); }
100%{ transform: translate3d(0px, -300px, -400px) rotateX(60deg); }
}
</style>
<div class="wrap-text">
<div class="scroll-text">
<p>HELLO WORD</p>
<p>HELLO WORD</p>
<p>HELLO WORD</p>
<p>HELLO WORD</p>
<p>HELLO WORD</p>
</div>
</div>
scale3d(X,Y,Z)
scaleX, scaleY, scaleZの拡大縮小をまとめて操作
.square.scaled{
background:green;
transform: perspective(1000px) scale3d(1.5, 0.5, 2) rotateX(-55deg);
}
*SafariのCSS 3D(translateZ)とz-indexの制御順にバグがありtranslateZが優先されるようです
対策:translateZで上にきている要素の親にtransform: translateZ(0)
をつける
z-indexの制御順
親要素がローカルの重ね合わせコンテキストを形成していた場合(条件は下記リンク参照)
子要素のz-indexはローカル内でのみ有効になります