# 数量ステッパー（−／＋）のCSS実装

> ECのカートで使う数量選択UI。number入力の標準スピナーを消して−／＋ボタンを自作し、最小・最大値でクランプします。

- カテゴリ: ボタン・操作
- URL: https://www.css-dictionary.com/recipes/quantity-stepper/

## HTML

```html
<div class="stepper">
  <button type="button" id="dec" aria-label="数量を減らす">−</button>
  <input type="number" id="qty" value="1" min="1" max="99" aria-label="数量" />
  <button type="button" id="inc" aria-label="数量を増やす">＋</button>
</div>
```

## CSS

```css
.stepper {
  display: inline-flex;
  border: 1px solid #cbbfa5;
  border-radius: 8px;
  overflow: hidden;
  background: #fff;
}

.stepper button {
  width: 40px;
  height: 40px;
  border: none;
  background: #f3ecd9;
  font-size: 18px;
  color: #5c5445;
  cursor: pointer;
  user-select: none; /* 連打時にテキスト選択が走らないように */
  transition: background-color 0.15s;
}

.stepper button:hover {
  background: #e2d8c2;
}

.stepper button:focus-visible {
  outline: 2px solid #b0413e;
  outline-offset: -2px;
}

.stepper input {
  width: 56px;
  border: none;
  text-align: center;
  font: inherit;
  appearance: textfield; /* 標準スピナーを消す（Firefox） */
}

.stepper input::-webkit-outer-spin-button,
.stepper input::-webkit-inner-spin-button {
  appearance: none; /* 標準スピナーを消す（Chrome/Safari） */
  margin: 0;
}

.stepper input:focus-visible {
  outline: 2px solid #b0413e;
  outline-offset: -2px;
}
```

## JavaScript

```js
const qty = document.getElementById('qty');
const step = (n) => {
  const next = Number(qty.value || 1) + n;
  qty.value = Math.min(Number(qty.max), Math.max(Number(qty.min), next));
};
document.getElementById('dec').addEventListener('click', () => step(-1));
document.getElementById('inc').addEventListener('click', () => step(1));
```

## 仕組みの解説

実体は input type="number" なので、キーボードの上下キーや直接入力はそのまま使えます。ブラウザ標準のスピナーは appearance で消し、大きくタップしやすい−／＋ボタンを自作します。JSはmin/max属性の範囲に収める加算だけで、値の検証ロジックをHTML属性に寄せているのがポイントです。

## 実装のポイント

合計金額の表示がある場合は、その要素にaria-liveを付けると数量変更が支援技術にも伝わります。

## AIに依頼するときの文例

ECカート用の数量ステッパーを作ってください。input type="number"の標準スピナーをappearanceで消し、−／＋ボタン（aria-label付き）で増減、min/max属性の範囲でクランプしてください。

## 使っているプロパティ

- [display-flex](https://www.css-dictionary.com/property/display-flex.md)
- [appearance](https://www.css-dictionary.com/property/appearance.md)
- [border-radius](https://www.css-dictionary.com/property/border-radius.md)
- [user-select](https://www.css-dictionary.com/property/user-select.md)

