「フォームの数値に3桁カンマを振りたい」という要望を受けました。
しかしinput
のvalue
が文字列になると色々都合が悪いので、input
の入力値はそのまま保持しつつ、見た目だけカンマ付きで表示する方法を実装しました。
同じ位置に擬似的なテキスト要素を重ねることで、「あたかもinput自体にカンマが表示されているように見せる」仕組みです。
デモ
See the Pen inputの3桁カンマ区切り by MEMORUKA (@memoruka) on CodePen.
経緯と狙い
依頼を受けた対象はプラン料金のシミュレーションを行うフォームです。
現状のフォームは各input
の入力値をもとにリアルタイムの計算がゴリゴリ入っています。なので単純にvalue
を直接弄って文字列にするわけにはいきません。
かといって、そのあたりの計算ロジックを今更変更し、フォーカス時に一旦、文字列に変換して、数値はどこかに一時保存して…なんて正直言ってやりたくない。
そこで「input
のvalue
はそのまま保持しつつ、CSSと最低限のJavaScriptで見た目だけカンマ付きにする」ということは出来ないかと考えました。
inputの調整
<input type="number" inputmode="numeric" min="0" max="99999" oninput="this.value = this.value.slice(0,5);">
type = number
数値専用のinput
フィールド。スマホでは数字キーボードが出ます。
inputmode = numeric
スマホでは数字キーボードが出ます。本来はtype = text用で、type = numberを利用した際は不要のはずですが、古いiOS端末だと併用しないと効かなかったので保険的に付けています。
min = 0 max = 99999
入力できる値の最小値:0と最大値:99999を制限。値は任意。※ただし手動入力で超えることは可能。そのためsliceを併用して対策。
oninput = this.value = this.value.slice(0,5)
入力イベントを先頭から5文字に制限。これにより最大5桁までしか入力できないようにしています(max = 99999と併用)。
各クラス要素の役割
<div class="number-container">
<input type="number" class="number-input number-input-style" inputmode="numeric" min="0" max="99999" oninput="this.value = this.value.slice(0,5);">
<span class="comma-box number-input-style"></span>
</div>
/* コンテナ */
.number-container {
position: relative;
width: fit-content;
overflow: hidden;
&:not(:last-child) {
margin-bottom: 1em;
}
}
/* input と comma-box(カンマ表示用領域) のスタイルを合わせる */
.number-input-style {
box-sizing: border-box;
display: grid;
place-content: center start;
width: 200px;
font-family: "Yu Gothic", "Meiryo", "Helvetica Neue", "Hiragino Kaku Gothic ProN", "Arial", sans-serif;
font-size: 16px;
font-weight: 400;
padding: 0.5em;
border: 1px solid #ccc;
border-radius: 0;
line-height: 1;
/* type="number"のスピン削除 */
-moz-appearance: textfield;
&::-webkit-inner-spin-button,
&::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
}
/* カンマ区切りにしたいinput */
.number-input {
position: relative;
/* 通常時 - z-index:1でcomma-boxの後ろに。colorは透過 */
&:not(:focus) {
z-index: 1;
color: transparent;
caret-color: #333;
}
/* フォーカス時 - z-index:3でcomma-boxより前に */
&:focus {
z-index: 3;
background-color: #fff;
}
}
/* カンマ表示用。inputと同じ位置に配置する。 pointer-events:noneでクリックは無効化 */
.comma-box {
z-index: 2;
position: absolute;
inset: 0;
border: 0;
background: transparent;
margin: auto;
pointer-events: none;
}
.number-container
input
とカンマ表示用要素の位置をposition
で合わせるための親コンテナ。
.number-input-style
input
とカンマ文字列(.comma-box)の共通スタイル。同じスタイルで見た目を一致させるのがポイント。
type = numberのスピンボタン(上下矢印)もここで削除。
.number-input
ユーザーが直接操作するinput
。
通常は .comma-box が前面にあり見えませんが、フォーカス時にz-index
で前面に出します。
.comma-box
3桁カンマ付きの文字列を表示するための要素。
通常は、z-index
でinput
の前面に表示されますが、pointer-events: none;
によりクリックが無効化され、背後のinput
が操作可能。input
にフォーカスされると、前後のz-index
が切り替わり、後ろに下がります。
javascript(jQuery)
$(function () {
function applyCommaFormat($input) {
const value = $input.val();
const $overlap = $input.next('.comma-box');
$overlap.text(value !== '' ? Number(value).toLocaleString() : '');
}
$('.number-input').on('blur input', function () {
applyCommaFormat($(this));
});
// 初期表示時にもカンマ区切りを適用
$('.number-input').each(function () {
applyCommaFormat($(this));
});
});
toLocaleString()
を使って、数値を3桁カンマで表示しています。
input
の値は数値のままなので、裏側での計算処理にも影響ありません。
参考にした記事
今回の件は、こちらの記事を参考にさせていただきました。
頭の中で描いていた、まさに「やりたかったこと」が紹介されていて、とても助かりました。ありがとうございます。
ただ作者様自身も述べている通り、そのままでの実用化はちょい厳しかったので、必要項目を色々考えた次第です。
- inputの型をnumberにし、各種制限を導入
- スマホ対応や文字数制限など、細かな入力調整
- ページロード時から初期value値にもカンマが表示されるよう、初期処理を追加
まとめ
以上、input
に3桁カンマを表示しつつ、value
は数値のまま保持する方法でした。
input
のvalue
を数値として維持しながら、3桁カンマを「見た目だけ」加えるこの方法は、既存の計算処理を壊すことなくカンマを表示できる、ちょっとした小技です。
先様に軽いノリでしれっとお願いされた際、案の1つとして参考にどうぞ。