こんにちは。KOUKIです。
本記事は、Udemyの「50 Projects In 50 Days – HTML, CSS & JavaScript」で学習したことを載せています。
実装するもの
今回は、フィードバック機能を実装します。
demoは「こちら」で確認できます。
環境構築
簡単な環境構築をお願いします。
必要なファイルは、以下の通りです。
1 2 3 4 5 6 |
$ tree . ├── index.html ├── script.js └── style.css |
CSS版
ページ(HTML)の作成
最初にページを作成しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="style.css" /> <title>Custom Range Slider</title> </head> <body> <h2>Custom Range Slider</h2> <div class="range-container"> <input type="range" id="range" min="0" max="100"> <label for="range">50</label> </div> <script src="script.js"></script> </body> </html> |
このHTMLをブラウザ上で表示すると以下のようになります。

スタイル(CSS)を装飾
次は、ページにスタイルをつけます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
@import url('https://fonts.googleapis.com/css?family=Lato&display=swap'); * { box-sizing: border-box; } body { background-image: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); font-family: 'Lato', sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; overflow: hidden; margin: 0; } h2 { position: absolute; top: 10px; } .range-container { position: relative; } input[type='range'] { width: 300px; margin: 18px 0; -webkit-appearance: none; } input[type='range']:focus { outline: none; } input[type='range'] + label { background-color: #fff; position: absolute; top: -25px; left: 110px; width: 80px; padding: 5px 0; text-align: center; border-radius: 4px; box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); } /* Chrome & Safari */ input[type='range']::-webkit-slider-runnable-track { background: purple; border-radius: 4px; width: 100%; height: 10px; cursor: pointer; } input[type='range']::-webkit-slider-thumb { -webkit-appearance: none; height: 24px; width: 24px; background: #fff; border-radius: 50%; border: 1px solid purple; margin-top: -7px; cursor: pointer; } /* Firefox */ input[type='range']::-moz-range-track { background: purple; border-radius: 4px; width: 100%; height: 13px; cursor: pointer; } input[type='range']::-moz-range-thumb { -webkit-appearance: none; height: 24px; width: 24px; background: #fff; border-radius: 50%; border: 1px solid purple; margin-top: -7px; cursor: pointer; } /* IE */ input[type='range']::-ms-track { background: purple; border-radius: 4px; width: 100%; height: 13px; cursor: pointer; } input[type='range']::-ms-thumb { -webkit-appearance: none; height: 24px; width: 24px; background: #fff; border-radius: 50%; border: 1px solid purple; margin-top: -7px; cursor: pointer; } |
ここまで実装すると以下のようになります。

JavaScriptの実装
準備は整ったので、JavaScriptを実装していきましょう。
要素を取得する
最初に、画面操作に必要な要素を取得します。
1 2 |
// 要素の取得 const range = document.getElementById('range') |
inputイベントの登録
レンジスライダーは、input要素で作成しています。すなわち、このスライダーの状態が変化したらinputイベントが発火します。
1 2 3 4 |
// レンジスライダーの状態変化時のイベント range.addEventListener('input', (e) => { ... }) |
ラベルの更新
レンジスライダーを動かした時に、ラベルが更新されるようにしましょう。
1 2 3 4 5 6 7 8 9 10 |
// レンジスライダーの状態変化時のイベント range.addEventListener('input', (e) => { // レンジスライダーの値を取得 // + は、string -> numberに変化させる const value = +e.target.value // label要素を取得 const label = e.target.nextElementSibling // labelの更新 label.innerHTML = value }) |
JavaScript では、「+」をつけるとstring->number型に変化できます。ただし、数値に変換できるものだけです。

ラベル位置の調整
レンジスライダーを動かしたら、それに付随してラベル位置も調整しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
range.addEventListener('input', (e) => { // レンジスライダーの値を取得 // + は、string -> numberに変化させる // label要素を取得 .... // レンジスライダーに設定されているwidth(XXpx)を取得 const range_width = getComputedStyle(e.target).getPropertyValue('width') // ラベルに設定されているwidth(XXpx)を取得 const label_width = getComputedStyle(label).getPropertyValue('width') // pxをとる(300px -> 300)、かつ、+でnum化 const num_width = +range_width.substring(0, range_width.length - 2) const num_label_width = +label_width.substring(0, label_width.length - 2) // レンジスライダーに設定している最大値、最小値 const max = +e.target.max const min = +e.target.min // レンジスライダーのleftスタイルに設定する値の計算 const left = value * (num_width / max) - num_label_width / 2 + scale(value, min, max, 10, -10) // スタイルへ適用 label.style.left = `${left}px` // labelの更新 ... }) // scaleの計算 // https://stackoverflow.com/questions/10756313/javascript-jquery-map-a-range-of-numbers-to-another-range-of-numbers const scale = (num, in_min, in_max, out_min, out_max) => { return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } |
getComputedStyleとgetPropertyValueは、人生で初めて使いましたw
これで、レンジスライダーやラベルに設定されているwidthをpx付きで取得しています。
ラベルの位置調整は、スタイルの「left」プロパティで設定しているので、「label.style.left 」に計算済みの値を代入すると、レンジスライダーに付随して、ラベルも動くようになります。
1 2 3 4 5 6 7 8 9 10 11 |
input[type="range"] + label { background-color: #fff; position: absolute; top: -25px; left: 110px; <<<<<<<<<<<< ここ width: 80px; padding: 5px 0; text-align: center; border-radius: 4px; box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); } |
肝心の計算方法は結構複雑なので、時間に余裕がある方は解き明かしてみてください。
これで完成です。
おわりに
今回のようにレンジスライダーの動きに連動して、ラベルを動かす処理を実装したことはなかったのですが、結構面白いですよね。JavaScriptとCSSの連携が肝になりますが。。
それでは、また!
JavaScriptまとめ
JavaScript ソースコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
// 要素の取得 const range = document.getElementById('range') // レンジスライダーの状態変化時のイベント range.addEventListener('input', (e) => { // レンジスライダーの値を取得 // + は、string -> numberに変化させる const value = +e.target.value // label要素を取得 const label = e.target.nextElementSibling // レンジスライダーに設定されているwidth(XXpx)を取得 const range_width = getComputedStyle(e.target).getPropertyValue('width') // ラベルに設定されているwidth(XXpx)を取得 const label_width = getComputedStyle(label).getPropertyValue('width') // pxをとる(300px -> 300)、かつ、+でnum化 const num_width = +range_width.substring(0, range_width.length - 2) const num_label_width = +label_width.substring(0, label_width.length - 2) // レンジスライダーに設定している最大値、最小値 const max = +e.target.max const min = +e.target.min // レンジスライダーのleftスタイルに設定する値の計算 // レンジスライダーの値 * (レンジスライダーの幅 / レンジスライダーのmax値) - ラベルの幅 / 2 + スケール const left = value * (num_width / max) - num_label_width / 2 + scale(value, min, max, 10, -10) // スタイルへ適用 label.style.left = `${left}px` // labelの更新 label.innerHTML = value }) // scaleの計算 // https://stackoverflow.com/questions/10756313/javascript-jquery-map-a-range-of-numbers-to-another-range-of-numbers const scale = (num, in_min, in_max, out_min, out_max) => { return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } |
コメントを残す
コメントを投稿するにはログインしてください。