立体的なボタンの作り方|box-shadow と :active で押し込む3Dボタン

box-shadow と :active で押し込む立体ボタン

ぼかしのない box-shadow で厚みを作り、:active で押し込まれる立体ボタンを実装します。押し込み方の比較と12色のバリエーションまで、デモと同じ見た目で再現できるHTML・CSSを掲載しています。
HTML・CSS・JSコードプレビューツールでも動作を確認できます。

無料ツール 色・角丸・影をスライダーで調整する「ボタンデザイン生成ツール」 プレビューを見ながら立体ボタンの見た目を作り、そのままCSSをコピーできます。

① 基本形 — box-shadow と :active で押し込む

ボタンを押すと、影が縮みながら下へ沈みます

HTML
<button class="btn-3d" type="button">Click!</button>
CSS
.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 が「厚み」になる

box-shadow: 0 0.3em 0 #2980b9 のように、ぼかしを 0 にしてメインカラーより暗い色を指定すると、ボタンの下に硬い段差ができて立体に見えます。クリック中(:active)は transform: translateY(0.2em) でボタンを下げ、同時に影の高さを 0.1em へ縮めると、押し込んだ感触が生まれます。

② 押し込み方の比較 — margin-top と translateY

margin-top 版

基準線 下の要素

押すと「下の要素」も一緒に下がる

translateY 版(推奨)

基準線 下の要素

押しても「下の要素」は動かず、ボタンが重なる

HTML
<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>
CSS
.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色の立体ボタン

HTML
<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>
CSS
.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;
}
影の色はメインカラーより一段暗い色を選ぶ

各色クラスでは、背景色とその少し暗い色を影に使っています。薄い影や黒の半透明影でも立体感は出せますが、同系色の硬い影のほうが「ボタンの側面」に見えやすくなります。白や黄など明るい色は文字色を濃くし、白背景でも輪郭が分かるよう薄い枠線を付けています。

注意点:スマホのタッチ操作では、タップ後に :active の見た目が一瞬残ることがあります。気になる場合は、ボタンから指が離れたあとにクラスを外すJavaScriptを足すか、:active ではなく押下中だけ付与するクラスで制御してください。また、親要素に overflow: hidden があると、下にはみ出した影が切れて立体感が弱まります。

立体ボタンはどのプロパティで作りますか?

基本は box-shadow:active の組み合わせです。ぼかしを 0 にした影で厚みを作り、クリック中に transform: translateY() で下げつつ影を縮めます。JavaScriptは不要です。

margin-top と translateY のどちらを使うべきですか?

translateY を推奨します。見た目は似ていても、margin-top は周囲のレイアウトを動かしてしまいます。②のデモで、「下の要素」が動くかどうかを比べられます。

影の色はどう決めると自然ですか?

ボタン本体より一段暗い同系色が扱いやすいです。黒の半透明でも立体には見えますが、同系色の硬い影のほうが「側面」らしくなります。詳しい影の調整はbox-shadow の解説も参照してください。

ホバーで少し浮かせることもできますか?

できます。:hovertransform: translateY(-0.1em) と影を少し大きくし、:active で再び沈めると、浮いて押される動きになります。ホバー演出全般はホバー時のアニメーションも参考になります。


当サイトで公開しているWebデザインやUIの実装例は、一覧として以下記事に纏めています。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次