概要
2024年か2025年頃からでしょうか、PinterestやDribbbleでUIデザインを調べると、エフェクトやテクスチャが多いものを見かけるようになったと思います。
こういったUIは、見た目はおしゃれですが「実装するときどうするの?」という意見がよく出ます。
見た目の再現のためだけに不要なdivが増えたり画像に頼るのは避けたいですよね。
また、CSSだけでどの程度のスタイリングができるかを把握しておけば、デザイナーとエンジニアの間で実現可能なラインの共通認識を持ちやすくなると思います。
今回、Tailwind CSS v4だけで4パターンのボタンを再現してみたので、その方法を紹介します。
対象読者
- Webデザインをする方、それを実装する方
- Tailwind CSSを使ったことがある方
最初にまとめ
- 角丸つきグラデーションボーダーは
mask-compositeを使って実現できる -
::beforeや::afterにblurを組み合わせることでグローエフェクトを表現できる -
inset-shadowとshadowを重ねることで立体感を出せる - Tailwind CSS v4の
@utilityディレクティブを使えば、複雑なスタイルも再利用可能なユーティリティとして定義できる
環境
- Tailwind CSS 4.1.18
以下のリポジトリで、試してみた際のコードもご覧いただけます。
今回はトレンド的によく見るスタイルの再現に主眼を置いているため、色の組み合わせはアクセシビリティの観点では十分でないと思われます。実務で利用する際は注意してください。
本題
共通のベーススタイル
4つのボタンには以下のTailwindクラスを指定していて、形状、余白、文字そのもののスタイルは統一してあります。
<button class="rounded-full px-5 py-2 font-bold text-lg text-white text-shadow-xs text-shadow-orange-600">
以降のセクションでは、各ボタンの完成形のコードと、ボタンごとに異なる部分を解説します。
Button 1: ソリッドな光沢
<button
class="
rounded-full px-5 py-2 font-bold text-lg text-white text-shadow-xs text-shadow-orange-600
gradient-border
bg-linear-to-b from-amber-400 to-orange-600
shadow-lg shadow-orange-500/50
[--_gradient-border-before-color:var(--color-amber-200),var(--color-orange-600)30%,var(--color-orange-700)80%,var(--color-amber-400)]
[--_gradient-border-before-width:2px]
before:rounded-full
"
>
Button
</button>
このボタンでのスタイルの特徴は以下です。
-
gradient-border: グラデーションボーダーを適用するカスタムユーティリティ(仕組みは後述) -
bg-linear-to-b from-amber-400 to-orange-600: 上から下へのグラデーション背景- 明るい側にamber(黄色寄り)、暗い側にorange(赤寄り)とあえて色相をずらしている
- 同一色相の明暗だけで作るよりも、自然な陰影感のあるグラデーションになる
-
[--_gradient-border-before-color:...]: ボーダーのグラデーション色をCSSカスタムプロパティで指定 -
[--_gradient-border-before-width:2px]: ボーダーの太さを2pxに設定 -
before:rounded-full: 擬似要素にもピル型の角丸を適用
Button 2: 柔らかなグラデーション
<button
class="
rounded-full px-5 py-2 font-bold text-lg text-white text-shadow-xs text-shadow-orange-600
relative z-0 overflow-clip
bg-orange-500
inset-shadow-[0_0_6px_2px_var(--color-amber-200)]
shadow-lg shadow-orange-500/50
before:absolute before:top-1/2 before:right-2 before:-bottom-1/2 before:left-2 before:-z-10 before:rounded-full before:bg-yellow-200/50 before:blur before:content-['']
"
>
Button
</button>
このボタンでのスタイルの特徴は以下です。
-
inset-shadow-[0_0_6px_2px_var(--color-amber-200)]: ボタン内側にamber-200の光沢を入れる -
overflow-clip: ボタンの範囲外にはみ出す擬似要素を切り取る -
relative z-0とbefore:-z-10: ボタン本体より擬似要素を背面に配置する
::before擬似要素がグローエフェクトの本体です。
-
before:top-1/2 before:right-2 before:-bottom-1/2 before:left-2: ボタン下部に配置 -
before:bg-yellow-200/50: 50%透過の黄色の背景 -
before:blur: ぼかしフィルターをかけて光っているように見せる
overflow-clipがないと、ぼかした擬似要素がボタンの外にはみ出してしまいます。
Button 3: フリーグラデーション風
<button
class="
rounded-full px-5 py-2 font-bold text-lg text-white text-shadow-xs text-shadow-orange-600
relative z-0 overflow-clip
bg-linear-to-r from-orange-600 to-amber-500
shadow-lg shadow-orange-500/50
before:absolute before:-top-1/3 before:right-6 before:bottom-2/3 before:-left-4 before:-z-10 before:rounded-full before:bg-yellow-200/50 before:blur before:content-['']
after:absolute after:top-2/3 after:right-0 after:-bottom-1/3 after:left-4 after:-z-10 after:rounded-full after:bg-pink-300/50 after:blur after:content-['']
"
>
Button
</button>
このボタンでのスタイルの特徴は以下です。
-
bg-linear-to-r from-orange-600 to-amber-500: 背景を左から右へのグラデーションに変更 -
::beforeと::afterの両方を使い、上下2つのグローを配置
Button 2では::beforeのみでボタン下部にグローを作っていましたが、Button 3では::afterも使い、ボタン上部にもグローを追加しています。
背景色をグラデーションし、その上で2つのグローの位置を左右にずらすことで、フリーグラデーションのような見た目を作り出しています。
Button 4: 透明なガラス
<button
class="
rounded-full px-5 py-2 font-bold text-lg text-white text-shadow-xs text-shadow-orange-600
gradient-border
bg-linear-to-b from-amber-200 to-orange-300
inset-shadow-[0_6px_3px_var(--color-orange-200),0_8px_16px_var(--color-orange-400)]
shadow-[0_4px_6px_-4px_var(--color-yellow-100),0_10px_15px_-3px_--alpha(var(--color-orange-500)/50%)]
[--_gradient-border-before-color:var(--color-white),var(--color-white)5%,var(--color-orange-600)30%,var(--color-orange-500)80%,var(--color-orange-100)95%,var(--color-orange-100)]
[--_gradient-border-before-width:2px]
before:rounded-full
[--_gradient-border-after-color:var(--color-amber-400),var(--color-orange-100)30%,var(--color-orange-300)80%,var(--color-orange-400)]
after:rounded-full
"
>
Button
</button>
このボタンでのスタイルの特徴は以下です。
-
inset-shadow-[...] shadow-[...]: シャドウを重ねて透明な素材に光が当たって背景に影が落ちているような質感を表現 -
gradient-borderの::beforeと::afterの両方を活用し、二重のグラデーションボーダーを実現
Button 1ではgradient-borderの::beforeのみを使っていましたが、Button 4では::afterにも別のグラデーション色を指定しています。
--_gradient-border-before-colorで外側のボーダー(白からオレンジ系)を、--_gradient-border-after-colorで内側のボーダー(amber-400からorange-500)を定義しており、二重のボーダーが異なる色で表現されています。
外側のシャドウにyellow-100のような明るい色を含めているのは、ガラスに光が当たった際に見られるコースティクス(集光模様)風の表現を意識したものです。
gradient-borderユーティリティの仕組み
Button 1とButton 4で使用したgradient-borderは、Tailwind CSS v4の@utilityディレクティブで定義したカスタムユーティリティです。
ここではその仕組みを解説します。
なぜこのようなコードでグラデーションボーダーを実現しているのか
CSSにはborder-imageというプロパティがあり、ボーダーにグラデーションを適用できます。
しかし、border-imageはborder-radiusと併用できないという制約があります。
つまり、角丸のボタンにグラデーションボーダーをつけたい場合、border-imageは使えません。
mask-compositeによる解決
代わりに使うのが、CSSのmask-compositeを利用したテクニックです。
考え方は以下のとおりです。
- 擬似要素を使い、ボタンと同じサイズの要素を重ねる
- その擬似要素にグラデーション背景を設定する
-
mask-composite: excludeを使い、ボーダー部分だけが見えるようにくり抜く
「くり抜く」部分をもう少し詳しく説明します。
2つのマスクを用意します。
- 1つ目:
padding-boxに制限されたマスク(内側の領域) - 2つ目:
border-boxに制限されたマスク(外側の領域)
mask-composite: excludeを指定すると、2つ目のマスクから1つ目のマスクが除外されます。
結果として、border-boxとpadding-boxの差分、つまりボーダー部分だけが表示されます。
このテクニックについては、TAKさんの以下のポストで見本つきで紹介されています。
コード全体
@utility gradient-border {
--_gradient-border-before-color: linear-gradient(
to var(--_gradient-border-before-direction),
#fff,
#000
);
--_gradient-border-before-direction: bottom;
--_gradient-border-before-width: 1px;
--_gradient-border-after-color: linear-gradient(
to var(--_gradient-border-after-direction),
#fff,
#000
);
--_gradient-border-after-direction: bottom;
--_gradient-border-after-width: 1px;
position: relative;
isolation: isolate;
&::before,
&::after {
content: "";
position: absolute;
inset: 0;
z-index: -1;
mask-image: conic-gradient(black), conic-gradient(black);
mask-clip: padding-box, border-box;
mask-composite: exclude;
-webkit-mask-composite: destination-out;
background-origin: border-box;
}
&::before {
background-image: linear-gradient(
to var(--_gradient-border-before-direction),
var(--_gradient-border-before-color)
);
border: solid var(--_gradient-border-before-width) transparent;
}
&::after {
background-image: linear-gradient(
to var(--_gradient-border-after-direction),
var(--_gradient-border-after-color)
);
border: solid var(--_gradient-border-after-width) transparent;
}
}
コードのポイントは以下です。
-
mask-image: conic-gradient(black), conic-gradient(black): 2つの不透明なマスクを定義- 色は不透明であればなんでもよく、
blackである必要はない
- 色は不透明であればなんでもよく、
-
mask-clip: padding-box, border-box: 1つ目のマスクをpadding-box、2つ目をborder-boxに制限 -
mask-composite: exclude: 2つのマスクの差分を取り、ボーダー部分だけを表示 -
-webkit-mask-composite: destination-out: 上記の、WebKit系ブラウザ向けの指定 -
border: solid var(--_gradient-border-before-width) transparent: 透明なボーダーを設定し、ボーダー領域を確保 -
background-origin: border-box: グラデーション背景がボーダー領域まで広がるように指定 -
isolation: isolate: 新しいスタッキングコンテキストを作成し、z-index: -1の擬似要素が親の背面に回り込むのを防ぐ
mask-compositeは比較的新しいプロパティですが、Baseline 2023 Newly availableであり、2023年12月以降の主要ブラウザで対応しています。
CSSカスタムプロパティ(--_gradient-border-before-colorなど)をデフォルト値付きで定義しているため、使う側でTailwindの任意値([--_gradient-border-before-color:...])を使って色や幅を上書きできます。
::beforeと::afterの両方を用意しているため、Button 4のように二重のグラデーションボーダーも実現できます。
まとめ
PinterestやDribbbleで見かけるおしゃれなボタンを、Tailwind CSS(v4)だけで4パターン再現しました。
中心的なテクニックは、mask-compositeによるグラデーションボーダーと、擬似要素 + blurによるグローエフェクトの2つです。
色や影の値は目視で調整した部分が多く、特定の計算式に基づくものではありません。
Tailwind CSS v4の@utilityディレクティブを使えば、mask-compositeのような複雑なスタイルもユーティリティクラスとして管理でき、Tailwind CSSの開発体験を損なわずに使えるのは便利だと思います。
