はじめまして、DXOでUI/UXやフロントエンドを担当しているkoyaです。
フロントエンド開発をそこそこ経験してきたつもりでしたが、最近までborder
にグラデーションやアニメーションは適用できないということを知りませんでした…
この記事では、私が実際にハマった失敗談と、その解決方法を整理しています。同じような問題に直面している方の参考になれば嬉しいです。
1. ハマったポイント:border
はグラデーション非対応
最初に以下のように書きました。
.box {
border: 4px solid linear-gradient(to right, #82BEF0, #D2A5EB);
}
結果、何もエラーが出ずにborderも表示されませんでした。CSSの仕様では、border
はレイアウト領域であり、装飾は background
プロパティに任されています。
2. 試したけど微妙だった方法:border-image
次に、画像として扱える border-image
を試しました。
.box {
border: 2px solid transparent;
border-image: linear-gradient(to right, #82BEF0, #D2A5EB) 1;
}
しかし、以下の問題がありました。
- 点線や破線(
dashed
/dotted
)が使えない - 角丸がきれいに表示されない
- アニメーションができない
静的なデザインであれば使えますが、動的なデザインには向きませんでした。
3. 最終的に辿り着いた方法:擬似要素 + mask
擬似要素を使い、グラデーション背景を設定してマスクで枠線だけを残す方法です。
これにより、
- 点線や破線を自由に作れる
- アニメーションも可能
- 角丸にも対応できる
といった柔軟なデザインが実現できました。
4. 実際の実装例
グラデーション下線付きリンク
リンクの下線をグラデーション+アニメーションにするのも意外と苦労しました。当初は 疑似要素で簡単に設定できると思っていましたが、結局うまくいかず、試行錯誤の末にたどり着いたのがこの方法です。
background-image
を使ってグラデーション下線を作成し、色をアニメーションさせるために、@keyframes
を使う必要があります。
HTML
<div class="gradient">
<a href="#">これはダミーテキストです。</a>
</div>
CSS
.gradient a {
color: #82BEF0;
position: relative;
text-decoration: none;
background-image: linear-gradient(90deg, #82BEF0, #82BEF0);
background-repeat: no-repeat;
background-position: left bottom;
background-size: 0 1px;
transition: background-size 0.3s;
animation: randomColor 10s infinite ease-in-out;
}
.gradient a:hover {
background-size: 100% 1px;
}
@keyframes randomColor {
0% { color: #82BEF0; background-image: linear-gradient(90deg, #82BEF0, #82BEF0); }
50% { color: #AADCB9; background-image: linear-gradient(90deg, #AADCB9, #AADCB9); }
100% { color: #D2A5EB; background-image: linear-gradient(90deg, #D2A5EB, #D2A5EB); }
}
グラデーション × 点線
擬似要素を縦横それぞれに用意し、縞模様のグラデーションを作成。マスクを使用して枠線のみ表示しました。
SVGの方が無難に対応出来そうな気もしますが、CSSのみで柔軟に対応できたのはこの方法だけでした。
HTML
<div class="dotted-box">
<p>これはダミーテキストです。</p>
</div>
CSS
.dotted-box {
margin: 30px 0;
width: 100%;
height: auto;
border-radius: 16px;
position: relative;
border: 2px solid transparent;
}
.dotted-box::before {
content: '';
position: absolute;
top: 0;
left: 3px;
right: 3px;
bottom: 0;
border-radius: 16px;
padding: 3px;
background: linear-gradient(270deg, #D2A5EB, #AADCB9, #82BEF0);
-webkit-mask: repeating-linear-gradient(
90deg,
#fff 0px 2px,
rgba(255, 255, 255, 0) 2px 6px
);
mask: repeating-linear-gradient(
90deg,
#fff 0px 2px,
rgba(255, 255, 255, 0) 2px 6px
);
-webkit-mask-composite: destination-out;
mask-composite: exclude;
transition: opacity 0.3s ease-out;
z-index: -1;
}
.dotted-box::after {
content: '';
position: absolute;
top: 3px;
left: 0;
right: 0;
bottom: 3px;
border-radius: 16px;
padding: 3px;
background: linear-gradient(270deg, #D2A5EB, #AADCB9, #82BEF0);
mask: repeating-linear-gradient(
0deg,
#fff 0px 2px,
rgba(255, 255, 255, 0) 2px 6px
);
pointer-events: none;
z-index: -1;
}
.dotted-box p {
position: relative;
padding: 16px;
z-index: 1;
}
.dotted-box p::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
right: 2px;
bottom: 2px;
border-radius: 17px;
background: #fff;
pointer-events: none;
z-index: -1;
}
.dotted-box p {
margin: 0;
}
See the Pen sample,border-image by koya (@dxo-koya) on CodePen.
5. 実際に実装したサイト
実際の挙動は、以下のサイトで確認できます。
細かいアニメーションもグラデーションを加えたりしているので、各種リンクをhoverしてみてください!
6. まとめ
border
に直接グラデーションやアニメーションを適用できませんが、擬似要素とマスクを組み合わせることで表現できます。
ちょっと力技感がありますが、SVG以外だとこれくらいしか思いつきませんでした。
静的な場合は border-image
、動的で複雑な表現には擬似要素+マスクの方法がおすすめです。
この記事が誰かの参考になれば幸いです。他に良い方法をご存知の方は、ぜひコメントで教えてくださると助かります。