box-shadow と :active で押し込む立体ボタン
ぼかしのない box-shadow で厚みを作り、:active で押し込まれる立体ボタンを実装します。押し込み方の比較と12色のバリエーションまで、デモと同じ見た目で再現できるHTML・CSSを掲載しています。
HTML・CSS・JSコードプレビューツールでも動作を確認できます。
① 基本形 — box-shadow と :active で押し込む
ボタンを押すと、影が縮みながら下へ沈みます
<button class="btn-3d" type="button">Click!</button>
.btn-3d {
padding: 12px 28px;
border: none;
border-radius: 8px;
font-size: 15px;
font-weight: 700;
letter-spacing: 0.02em;
cursor: pointer;
user-select: none;
color: #fff;
background-color: #3498db;
box-shadow: 0 0.3em 0 #2980b9;
}
.btn-3d:hover {
opacity: 0.85;
}
.btn-3d:active {
transform: translateY(0.2em);
box-shadow: 0 0.1em 0 #2980b9;
}
box-shadow: 0 0.3em 0 #2980b9 のように、ぼかしを 0 にしてメインカラーより暗い色を指定すると、ボタンの下に硬い段差ができて立体に見えます。クリック中(:active)は transform: translateY(0.2em) でボタンを下げ、同時に影の高さを 0.1em へ縮めると、押し込んだ感触が生まれます。
② 押し込み方の比較 — margin-top と translateY
margin-top 版
押すと「下の要素」も一緒に下がる
translateY 版(推奨)
押しても「下の要素」は動かず、ボタンが重なる
<div class="btn-cmp-wrap">
<div class="btn-cmp-col">
<p>margin-top 版</p>
<div class="btn-cmp-box">
<span class="btn-cmp-base">基準線</span>
<button class="btn-cmp-margin" type="button">Click!</button>
<span class="btn-cmp-neighbor">下の要素</span>
</div>
</div>
<div class="btn-cmp-col">
<p>translateY 版</p>
<div class="btn-cmp-box">
<span class="btn-cmp-base">基準線</span>
<button class="btn-cmp-move" type="button">Click!</button>
<span class="btn-cmp-neighbor">下の要素</span>
</div>
</div>
</div>
.btn-cmp-wrap {
display: flex;
flex-wrap: wrap;
gap: 24px;
}
.btn-cmp-col {
flex: 1;
min-width: 180px;
}
.btn-cmp-box {
display: flex;
flex-direction: column;
align-items: stretch;
gap: 12px;
padding: 20px;
border: 1px solid #d8dee9;
border-radius: 12px;
background: #fff;
}
.btn-cmp-base {
display: block;
padding: 6px 10px;
border: 1px dashed #94a3b8;
border-radius: 6px;
background: #f8fafc;
color: #64748b;
font-size: 12px;
font-weight: 700;
text-align: center;
}
.btn-cmp-neighbor {
display: block;
padding: 8px 12px;
border-radius: 6px;
background: #e2e8f0;
color: #475569;
font-size: 13px;
font-weight: 700;
text-align: center;
}
.btn-cmp-margin,
.btn-cmp-move {
align-self: center;
margin: 0;
padding: 12px 28px;
border: none;
border-radius: 8px;
font-size: 15px;
font-weight: 700;
cursor: pointer;
user-select: none;
color: #fff;
background-color: #e74c3c;
box-shadow: 0 8px 0 #c0392b;
}
.btn-cmp-margin:active {
margin-top: 6px;
box-shadow: 0 2px 0 #c0392b;
}
.btn-cmp-move:active {
transform: translateY(6px);
box-shadow: 0 2px 0 #c0392b;
}
どちらもボタンを 6px 下げつつ、影を 8px から 2px へ縮めています。影の下端がほぼその場に残るので、側面に沈む押し込み感が出ます。違いはレイアウトだけで、margin-top は「下の要素」も 6px 下げ、translateY は描画だけずらすので下の要素は動きません。立体ボタンには translateY を使うのが安全です。
③ カラーバリエーション — 12色の立体ボタン
<div class="btn-wrap">
<button class="btn-3d btn-red" type="button">Click!</button>
<button class="btn-3d btn-blue" type="button">Click!</button>
<button class="btn-3d btn-green" type="button">Click!</button>
<button class="btn-3d btn-yellow" type="button">Click!</button>
<button class="btn-3d btn-cyan" type="button">Click!</button>
<button class="btn-3d btn-orange" type="button">Click!</button>
<button class="btn-3d btn-purple" type="button">Click!</button>
<button class="btn-3d btn-pink" type="button">Click!</button>
<button class="btn-3d btn-indigo" type="button">Click!</button>
<button class="btn-3d btn-white" type="button">Click!</button>
<button class="btn-3d btn-gray" type="button">Click!</button>
<button class="btn-3d btn-dark" type="button">Click!</button>
</div>
.btn-wrap {
display: flex;
flex-wrap: wrap;
gap: 16px;
padding: 20px;
}
.btn-3d {
padding: 12px 28px;
border: none;
border-radius: 8px;
font-size: 15px;
font-weight: 700;
letter-spacing: 0.02em;
cursor: pointer;
user-select: none;
min-width: 90px;
}
.btn-3d:hover {
opacity: 0.85;
}
.btn-3d:active {
transform: translateY(0.2em);
}
.btn-red {
color: #fff;
background-color: #e74c3c;
box-shadow: 0 0.3em 0 #c0392b;
}
.btn-red:active {
box-shadow: 0 0.1em 0 #c0392b;
}
.btn-blue {
color: #fff;
background-color: #3498db;
box-shadow: 0 0.3em 0 #2980b9;
}
.btn-blue:active {
box-shadow: 0 0.1em 0 #2980b9;
}
.btn-green {
color: #fff;
background-color: #2ecc71;
box-shadow: 0 0.3em 0 #27ae60;
}
.btn-green:active {
box-shadow: 0 0.1em 0 #27ae60;
}
.btn-yellow {
color: #333;
background-color: #f1c40f;
box-shadow: 0 0.3em 0 #f39c12;
}
.btn-yellow:active {
box-shadow: 0 0.1em 0 #f39c12;
}
.btn-cyan {
color: #fff;
background-color: #1abc9c;
box-shadow: 0 0.3em 0 #16a085;
}
.btn-cyan:active {
box-shadow: 0 0.1em 0 #16a085;
}
.btn-orange {
color: #fff;
background-color: #e67e22;
box-shadow: 0 0.3em 0 #ca6f1e;
}
.btn-orange:active {
box-shadow: 0 0.1em 0 #ca6f1e;
}
.btn-purple {
color: #fff;
background-color: #8e44ad;
box-shadow: 0 0.3em 0 #6c3483;
}
.btn-purple:active {
box-shadow: 0 0.1em 0 #6c3483;
}
.btn-pink {
color: #fff;
background-color: #e91e8c;
box-shadow: 0 0.3em 0 #b5166d;
}
.btn-pink:active {
box-shadow: 0 0.1em 0 #b5166d;
}
.btn-indigo {
color: #fff;
background-color: #3f51b5;
box-shadow: 0 0.3em 0 #303f9f;
}
.btn-indigo:active {
box-shadow: 0 0.1em 0 #303f9f;
}
.btn-white {
color: #333;
background-color: #ecf0f1;
box-shadow: 0 0.3em 0 #bdc3c7;
border: 1px solid #ddd;
}
.btn-white:active {
box-shadow: 0 0.1em 0 #bdc3c7;
}
.btn-gray {
color: #fff;
background-color: #95a5a6;
box-shadow: 0 0.3em 0 #7f8c8d;
}
.btn-gray:active {
box-shadow: 0 0.1em 0 #7f8c8d;
}
.btn-dark {
color: #fff;
background-color: #2c3e50;
box-shadow: 0 0.3em 0 #1a252f;
border: 1px solid #4a4a4a;
}
.btn-dark:active {
box-shadow: 0 0.1em 0 #1a252f;
}
各色クラスでは、背景色とその少し暗い色を影に使っています。薄い影や黒の半透明影でも立体感は出せますが、同系色の硬い影のほうが「ボタンの側面」に見えやすくなります。白や黄など明るい色は文字色を濃くし、白背景でも輪郭が分かるよう薄い枠線を付けています。
立体ボタンはどのプロパティで作りますか?
基本は box-shadow と :active の組み合わせです。ぼかしを 0 にした影で厚みを作り、クリック中に transform: translateY() で下げつつ影を縮めます。JavaScriptは不要です。
margin-top と translateY のどちらを使うべきですか?
translateY を推奨します。見た目は似ていても、margin-top は周囲のレイアウトを動かしてしまいます。②のデモで、「下の要素」が動くかどうかを比べられます。
影の色はどう決めると自然ですか?
ボタン本体より一段暗い同系色が扱いやすいです。黒の半透明でも立体には見えますが、同系色の硬い影のほうが「側面」らしくなります。詳しい影の調整はbox-shadow の解説も参照してください。
ホバーで少し浮かせることもできますか?
できます。:hover で transform: translateY(-0.1em) と影を少し大きくし、:active で再び沈めると、浮いて押される動きになります。ホバー演出全般はホバー時のアニメーションも参考になります。
当サイトで公開しているWebデザインやUIの実装例は、一覧として以下記事に纏めています。

