枠線がぐるっと描かれるカードを、CSS だけで作る
要点
- @property で変数に「角度」の型を教え、0deg から 360deg へなめらかに動かす
- conic-gradient の扇形を、mask で 1px の枠だけ残す
- JavaScript は使わず、CSS だけで作る
使っている CSS
- @property:型(角度)があるので、アニメーションで、角度をなめらかに変えられます。
- conic-gradient:「白はこの角度まで、その先は透明」と指定して、扇形に塗ります。
- mask:中身をくり抜いて、枠の 1px だけを残します。扇形が「枠線」になります。
コード
@property --line {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}
.card {
position: relative;
border: 1px solid rgb(255 255 255 / 0.14);
border-radius: 16px;
}
.card::before {
--line: 0deg;
content: "";
position: absolute;
inset: -1px;
padding: 1px;
border-radius: inherit;
background: conic-gradient(from 0deg, #fff 0deg, #fff var(--line), transparent calc(var(--line) + 0.4deg));
mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
mask-composite: exclude;
pointer-events: none;
}
.is-active .card::before {
animation: line 1.6s cubic-bezier(0.65, 0, 0.35, 1) forwards;
}
@keyframes line {
to {
--line: 360deg;
}
}
仕組み
- 重ねる:
::beforeをカードと同じ大きさで重ね、padding: 1pxを付けます。この 1px が枠線の太さです。 - 塗る:
conic-gradientの白の範囲を、var(--line)にします。 - くり抜く:
maskを 2 枚重ねてmask-composite: exclude。内側が抜けて、padding の 1px だけが残ります。 - 描く:
--lineを 0deg から 360deg へアニメーションさせます。
気をつけたこと
- 開始は、クラスで切り替えます。カードが画面に入ったときに
is-activeを付けます。 - 3 枚は、
animation-delayを 0.2 秒ずつずらします。順番に描かれて見えます。 - 動きを減らす設定には、最初から 360deg にします。描き終わった状態を、そのまま見せます。
- 土台に、普通の細い枠線を付けておきます。@property に対応していない環境では、角度が変わらず、描かれないためです。最近の Chrome・Safari・Firefox で動きます。