スピンボタン
2024年6月15日
みなさんこんにちは。
ケミストのWeb担当みやのです。
「Web」記事では、これまでに得たWebに関する知識を記録として残していきたいと思います。
今回はinput type="number"における「スピンボタン」を作ってみたいと思います。
スピンボタンとは
input type="number"にマウスカーソルを乗せる、またはフォーカスすると右側に現れる数値の増減ボタンのことをスピンボタン(スピナーボタン)というらしいです。
スマホではスピンボタンは表示されません。
単に「スピナー」だと、画面読み込み時によく出てくるグルグルするやつ のことを指すみたいですね。
ちっちゃくて押しにくい気がしますね。
アレンジしてみよう
・スマホでも表示されて
・ボタンを押しやすい大きさにして
・長押しで連続で増減できる
ようにしてみましょう。
とりあえず試作品はこちらです。
参考:PisukeCode|CSSでinput type="number"のスピンボタンをカスタマイズ!コード例
input type="number"と増減ボタンを設置します。
<label class="number-spinner-wrap">
<input type="number" value="0">
<button class="spinner spinner-down">-</button>
<button class="spinner spinner-up">+</button>
</label>
CSSはこんな感じです。
html {
touch-action: manipulation;
}
body {
-webkit-touch-callout: none;
-webkit-user-select: none;
}
.number-spinner-wrap {
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 4rem;
}
.number-spinner-wrap input::-webkit-outer-spin-button, .number-spinner-wrap input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
.number-spinner-wrap input {
width: calc(100% - 8rem);
height: 100%;
text-align: center;
margin: 0 auto;
font-size: 2.5rem;
border-radius: 0;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
box-shadow: none;
background: transparent;
border: 2px solid #eee;
}
.number-spinner-wrap input:focus {
outline: none;
box-shadow: none;
border-color: #32bdeb;
}
.number-spinner-wrap .spinner {
position: absolute;
top: 50%;
width: 4rem;
height: 4rem;
transform: translate(0, -50%);
font-size: 3rem;
cursor: pointer;
user-select: none;
display: flex;
justify-content: center;
align-items: center;
}
.number-spinner-wrap .spinner-down {
left: 0;
}
.number-spinner-wrap .spinner-up {
right: -4px;
}
中央揃えがわからなかったのでヤケクソでdisplay:flex、justify-content:center、align-items:centerをぶち込んでみましたが合ってるかはわかりません。
スクリプトはちょっとだけChatGPTに手伝ってもらいました。
const $wrap = document.querySelector('.number-spinner-wrap');
const $input = $wrap.querySelector('input');
let intervalId;
$wrap.querySelector('.spinner-down').onclick = () => {
$input.stepDown()
}
$wrap.querySelector('.spinner-up').onclick = () => {
$input.stepUp()
}
$wrap.querySelector('.spinner-down').addEventListener('mousedown', startInterval);
$wrap.querySelector('.spinner-up').addEventListener('mousedown', startInterval);
$wrap.querySelector('.spinner-down').addEventListener('touchstart', startInterval);
$wrap.querySelector('.spinner-up').addEventListener('touchstart', startInterval);
document.addEventListener('mouseup', stopInterval);
document.addEventListener('touchend', stopInterval);
function startInterval() {
intervalId = setInterval(() => {
if (this.classList.contains('spinner-down')) {
$input.stepDown();
} else {
$input.stepUp();
}
}, 100);
}
function stopInterval() {
clearInterval(intervalId);
}
最初はonclickだったのを、長押しのためにmousedownとmouseupに変更して、さらにタッチデバイスのためにtouchstartとtouchendを追加してみたところ「しっかりクリック」「しっかりタッチ」しないと反応しなくなってしまったので、onclickも併記してみました。そしたら敏感になりすぎた
まとめ
本当は、押し続けることでだんだん加速するようにしたかったのですが、うまくいきませんでした。
この長押しで増減する機能をなんとか活動限界タイマーに組み込みたいなあ