input type=range レンジスライダーをカスタマイズ

ブラウザによってデフォルトのスタイルが異なるレンジスライダーをCSS でスタイルを統一する方法や JavaScript を使って入力値に合わせてトラックの色を塗り分ける方法について。

作成日:2023年5月10日

レンジスライダー

input 要素の type 属性の値に range を指定するとスライダー形式のユーザインタフェースが表示され、レンジスライダーやレンジ入力欄と呼ばれる数値の入力欄になります。

<input type="range">

上記を記述すると以下のようなスライダー形式のユーザインタフェースが表示されます。

但し、形状や色、幅などの見た目はブラウザにより異なります。

type=range の input 要素の概要

レンジ入力の数値の範囲は min 属性と max 属性で指定でき、値を省略した場合はデフォルト値の 0 と 100 が適用されます。

入力値の初期値は value 属性で指定しますが、value 属性もしくはその値が省略された場合はデフォルト値である min属性値 + ( max属性値 - min属性値) /2 が適用されます。

例えば、min 属性値が0で max 属性値が100の場合、0+(100-0)/2 で、50となります。

また、step 属性を使うと、数値の刻みを指定できます。省略した場合は、デフォルト値である1が適用されます。

カスタマイズ例

以下は異なるブラウザでも同じスタイルで表示できるようにカスタマイズした例です。

レンジスライダーの構造

レンジスライダーは Track と Thumb と呼ばれる2つのコンポーネントで構成されています。

Track 選択できる値の範囲を表す要素(トラック)。この部分を Thumb が移動。
Thumb ユーザーが範囲値を選択するために移動できる Track 上の要素(つまみの部分)。
input type="range"(Track + Thumb) Track Thumb

これらのコンポーネントにスタイルを適用してレンジスライダーをカスタマイズすることができます。

開発者ツールで確認してみる

開発者ツールで確認してみると input 要素のみが表示され、Track と Thumb の要素は表示されません。

これは、レンジスライダーが Web コンポーネントとして実装されているためで、ブラウザーはシャドウ DOM 内のレンジスライダーを構成する要素とスタイルを内部的にカプセル化して非表示にしています。

Chrome を使用している場合であれば、開発者ツール(デベロッパーツール)の[設定] から [ユーザーエージェント シャドウ DOM を表示] オプションを有効にして、Shadow DOM を表示できます。

以下は Chrome の開発者ツールで上記オプションを有効にして input 要素を確認する例です。

Chrome の場合、以下のように Track は ::-webkit-slider-runnable-track、Thumb は ::-webkit-slider-thumb というベンダープレフィックスの付いた疑似要素にスタイルが設定されているのがわかります。

ベンダープレフィックスの付いた疑似要素

Track や Thumb をスタイリングする場合、関連する要素に適切なスタイルを適用するために、ブラウザー固有のベンダープレフィックスの付いた疑似要素を利用することができます。

-webkit で始まる疑似要素は、WebKit 及び Blink ベースのブラウザー (Chrome、Safari、Opera、Edge など) に適用され、 -moz で始まるものは Firefox に適用されます。

コンポーネント WebKit Blink (Chrome、Safari、Opera、Edge など) Mozilla (Firefox)
Track ::-webkit-slider-runnable-track ::-moz-range-track
Thumb ::-webkit-slider-thumb ::-moz-range-thumb

スタイルのカスタマイズ

レンジスライダーのスタイルはブラウザごとに異なるため、カスタマイズするにはまずブラウザ固有のスタイルを削除し、必要な要素のスタイルをリセット(設定)します。

また、Track はベンダープレフィックスの付いた疑似要素を使って個別に設定することもできますが、レンジスライダー自体に直接設定することもできます。

以下は2つの異なる方法でレンジスライダーのスタイルをカスタマイズする CSS の例です。

Track をベンダープレフィックス付疑似要素を使って個別に設定する場合
/* ベーススタイル */
input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  outline: none;
  background: transparent;
  cursor: pointer;
  width: 100%;
}

/* Track: Chrome, Safari, Opera, Edge Chromium */
input[type="range"]::-webkit-slider-runnable-track {
  background: #efafda;
  height: 8px;
  border-radius: 8px;
}

/* Thumb: Chrome, Safari, Opera, Edge Chromium */
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  height: 20px;
  width: 20px;
  margin-top: -6px; /* 位置の調整が必要 */
  background-color: #4cabe2;
  border-radius: 50%;
}

/* Track: Firefox */
input[type="range"]::-moz-range-track {
  background: #efafda;
  height: 8px;
  border-radius: 8px;
}

/* Thumb: Firefox */
input[type="range"]::-moz-range-thumb {
  border: none;
  height: 20px;
  width: 20px;
  background-color: #4cabe2;
  border-radius: 50%;
}

以下のように表示されます。

Track をレンジスライダー自体に直接設定する場合
/* ベーススタイルに Track も合わせて設定 */
input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  outline: none;
  cursor: pointer;
  width: 100%;
  /* Track のスタイル */
  background: #efafda;
  height: 8px;
  border-radius: 8px;
}

/* Thumb: Chrome, Safari, Opera, Edge Chromium */
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  height: 20px;
  width: 20px;
  background-color: #4cabe2;
  border-radius: 50%;
}

/* Thumb: Firefox */
input[type="range"]::-moz-range-thumb {
  border: none;
  height: 20px;
  width: 20px;
  background-color: #4cabe2;
  border-radius: 50%;
}

以下のように表示されます(前述の例と同じ)。

ベーススタイル

ベースとなるスタイルを input[type="range"] に設定します。

以下ではセレクタを input[type="range"] としていますが、クラスなどを指定して特定のレンジスライダーに適用することもできます。

各ブラウザのデフォルトの(固有の)スタイルを取り除くため、-webkit-appearanceappearancenone を指定します。

appearance はプラットフォームネイティブのスタイル付けに使用されるプロパティです。none を指定することでデフォルトのスタイルを削除し、カスタマイズするためのスタイルを適用できるようにします。

outline: none を指定してデフォルトの focus のスタイルを削除し、別途 focus や active のスタイルを設定します。

また、背景色は Track を個別にベンダープレフィックスを使ってカスタマイズする場合のために透明にしていますが、Track を input[type="range"] に直接設定してカスタマイズする場合は不要です。

カーソルは操作できる要素であることがわかりやすいように pointer にしています。幅もデフォルトの値はブラウザにより異なるので統一するため指定しています。

input[type="range"] {
  /* デフォルトの appearance を削除(必須)*/
  -webkit-appearance: none;
  appearance: none;

  /* outline を削除してデフォルトの focus のスタイルを無効に */
  outline: none;

  /* デフォルトの背景色を透明に(Track をベンダープレフィックスで設定する場合)*/
  background: transparent;

  /* カーソルを pointer に */
  cursor: pointer;

  /* 幅を設定(任意の値)*/
  width: 100%;
}

上記のスタイルを適用すると Track の部分が取り除かれ、以下のように Thumb の部分のみが表示された状態になります。 Thumb の形状はブラウザにより異なります。Firefox の場合は Thumb のボーダーや背景色も取り除かれます。

※ 上記及び以降のサンプルではわかりやすいように親要素にグレーの背景色を指定して表示しています。

background: transparent を指定しない場合、input[type="range"] 自体の背景色(白)が残ります。

何もスタイルを指定していないデフォルトのレンジスライダーは以下のように表示されます。

Track を input 要素に直接設定

以下は Track のスタイルを input[type="range"] を使って設定(input 要素に直接指定)する例です。

input[type="range"] に指定したベーススタイルに Track のスタイルを追加します。

Track の背景色と高さを input 要素に指定し、角丸にする場合は border-radius を設定します。ベーススタイルに指定していた background: transparent; は Track の背景色を指定するので削除します。

input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  outline: none;
  /* background: transparent; 不要なので削除 */
  cursor: pointer;
  width: 100%;

  /* Track のスタイルを追加 */
  background: #efafda;  /* Track の背景色 */
  height: 8px;  /* Track の高さ */
  border-radius: 8px;  /* Track の角丸 */
}

上記は以下のように表示されます。Track は各ブラウザで同じように表示されますが、Thumb(つまみ部分)はブラウザにより異なって表示されます。

Thumb をカスタマイズ

Thumb(つまみ部分)のスタイルを ::-webkit-slider-thumb と ::-moz-range-thumb に設定します。

-webkit ベースのブラウザではデフォルトのスタイルを取り除くため、-webkit-appearance と appearance に none を指定してカスタマイズします。

つまみ部分の大きさと背景色、及び角丸を設定します。Firefox は枠線がデフォルトで設定されているので削除しています。

/* Thumb: Chrome, Safari, Opera, Edge Chromium */
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  height: 20px;
  width: 20px;
  background-color: #4cabe2;
  border-radius: 50%;
}

/* Thumb: Firefox */
input[type="range"]::-moz-range-thumb {
  border: none; /* つまみ部分の枠線を削除 */
  height: 20px;
  width: 20px;
  background-color: #4cabe2;
  border-radius: 50%;
}

上記を記述すると以下のように表示され、各ブラウザで同じように表示されます。

input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  outline: none;
  cursor: pointer;
  width: 100%;
  background: #efafda;
  height: 8px;
  border-radius: 8px;
}

/* Thumb: Chrome, Safari, Opera, Edge Chromium */
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  height: 20px;
  width: 20px;
  background-color: #4cabe2;
  border-radius: 50%;
}

/* Thumb: Firefox */
input[type="range"]::-moz-range-thumb {
  border: none;
  height: 20px;
  width: 20px;
  background-color: #4cabe2;
  border-radius: 50%;
}

Thumb に border を設定

以下は Thumb に枠線(border)を設定した例です。Firefox では、box-sizing に border-box を指定しています。

input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  outline: none;
  cursor: pointer;
  width: 100%;
  background: #efafda;
  height: 8px;
  border-radius: 8px;
}

/* Thumb: Chrome, Safari, Opera, Edge Chromium */
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  height: 20px;
  width: 20px;
  background-color: #4cabe2;
  border-radius: 50%;
  border: 2px solid #333; /* つまみ部分に枠線を設定 */
}

/* Thumb: Firefox */
input[type="range"]::-moz-range-thumb {
  box-sizing: border-box; /*  border-box を設定 */
  height: 20px;
  width: 20px;
  background-color: #4cabe2;
  border-radius: 50%;
  border: 2px solid #333;
}

Track をベンダープレフィックスで設定

Track のコンポーネントをベンダープレフィックスの付いた疑似要素で個別に設定する方法です。

この方法の場合、Thumb の位置の調整が必要になるなどの手間が増え、記述量も多くなります。また、input[type="range"] に background: transparent の指定が必要です。

以下は ::-webkit-slider-runnable-track 疑似要素と::-moz-range-track 疑似要素を使って Track をカスタマイズする例です。

/* Chrome, Safari, Opera, Edge Chromium */
input[type="range"]::-webkit-slider-runnable-track {
  background: #efafda;
  height: 8px;
  border-radius: 8px;
}

/* Firefox */
input[type="range"]::-moz-range-track {
  background: #efafda;
  height: 8px;
  border-radius: 8px;
}

上記の設定とベーススタイルにより以下のように表示されます。

Chrome や Safari などの Webkit ベースのブラウザでは Thumb が Track の中心から下にずれて表示されので、別途 Thumb のスタイルで調整する必要があります。

Thumb をカスタマイズ

Thumb(つまみ部分)のスタイルを ::-webkit-slider-thumb と ::-moz-range-thumb に設定します。

/* Thumb: Chrome, Safari, Opera, Edge Chromium */
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  height: 20px;
  width: 20px;
  margin-top: -6px;   /* Thumb の位置を調整 */
  background-color: #4cabe2;
  border-radius: 50%;
}

/* Thumb: Firefox */
input[type="range"]::-moz-range-thumb {
  border: none;   /* ボーダーを削除 */
  height: 20px;
  width: 20px;
  background-color: #4cabe2;
  border-radius: 50%;
}

-webkit ベースのブラウザでは Thumb の位置を調整する必要があります。

Thumb の位置調整

Thumb をトラックの中心に配置するには、以下の値を margin-top に指定します。

margin-top = (track height / 2) - (thumb height / 2)

この例の場合、track height は 8px、thumb height は 20px なので、8/2 - 20/2 = -6(4-10 = -6)となり、-6px を指定しています(上記7行目)。

以下のように表示されます。

input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  outline: none;
  background: transparent; /* 背景を透明に*/
  cursor: pointer;
  width: 100%;
}

/* Track: Chrome, Safari, Opera, Edge Chromium */
input[type="range"]::-webkit-slider-runnable-track {
  background: #efafda;
  height: 8px;
  border-radius: 8px;
}

/* Thumb: Chrome, Safari, Opera, Edge Chromium */
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  height: 20px;
  width: 20px;
  margin-top: -6px;   /* Thumb の位置を調整 */
  background-color: #4cabe2;
  border-radius: 50%;
}

/* Track: Firefox */
input[type="range"]::-moz-range-track {
  background: #efafda;
  height: 8px;
  border-radius: 8px;
}

/* Thumb: Firefox */
input[type="range"]::-moz-range-thumb {
  border: none;
  height: 20px;
  width: 20px;
  background-color: #4cabe2;
  border-radius: 50%;
}

Thumb に border を設定

以下は Thumb(つまみ部分)に枠線を設定する例です。

/* Thumb: Chrome, Safari, Opera, Edge Chromium */
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  height: 20px;
  width: 20px;
  margin-top: -6px;
  background-color: #4cabe2;
  border-radius: 50%;
  border: 2px solid #333; /* ボーダーを設定 */
}

/* Thumb: Firefox */
input[type="range"]::-moz-range-thumb {
  box-sizing: border-box;  /* box-sizing: border-box を指定 */
  height: 20px;
  width: 20px;
  background-color: #4cabe2;
  border-radius: 50%;
  border: 2px solid #333; /* ボーダーを設定 */
}
input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  outline: none;
  background: transparent; /* 背景を透明に*/
  cursor: pointer;
  width: 100%;
}

/* Track: Chrome, Safari, Opera, Edge Chromium */
input[type="range"]::-webkit-slider-runnable-track {
  background: #efafda;
  height: 8px;
  border-radius: 8px;
}

/* Thumb: Chrome, Safari, Opera, Edge Chromium */
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  height: 20px;
  width: 20px;
  margin-top: -6px;   /* Thumb の位置を調整 */
  background-color: #4cabe2;
  border-radius: 50%;
  border: 2px solid #333;
}

/* Track: Firefox */
input[type="range"]::-moz-range-track {
  background: #efafda;
  height: 8px;
  border-radius: 8px;
}

/* Thumb: Firefox */
input[type="range"]::-moz-range-thumb {
  box-sizing: border-box;
  height: 20px;
  width: 20px;
  background-color: #4cabe2;
  border-radius: 50%;
  border: 2px solid #333;
}

hover active focus

アクセシビリティのために focus スタイルを追加します。また、active と hover を追加することで、スライダーの操作中に視覚効果を提供することができます。

追加で :hover、:active 及び :focus 擬似クラスを Thumb(::-webkit-slider-thumb と ::-moz-range-thumb)に設定します。

デフォルトの focus のスタイルを削除するため、input[type="range"] に outline: none を指定します。この例ではベーススタイルで指定しています。

/* hover、active & focus(Thumb: Webkit) */
input[type="range"]::-webkit-slider-thumb:hover {
  box-shadow: 0 0 0 7px rgba(0, 30, 255, 0.1)
}
input[type="range"]:active::-webkit-slider-thumb {
  box-shadow: 0 0 0 10px rgba(0, 30, 255, .2)
}
input[type="range"]:focus::-webkit-slider-thumb {
  box-shadow: 0 0 0 10px rgba(0, 30, 255, .2)
}

/* hover、active & focus(Thumb: Firfox) */
input[type="range"]::-moz-range-thumb:hover {
  box-shadow: 0 0 0 7px rgba(0, 30, 255, .1)
}
input[type="range"]:active::-moz-range-thumb {
  box-shadow: 0 0 0 10px rgba(0, 30, 255, .2)
}
input[type="range"]:focus::-moz-range-thumb {
  box-shadow: 0 0 0 10px rgba(0, 30, 255, .2)
}

Thumb(つまみ部分)にホバーしたり、操作すると半透明の box-shadow が表示されます。

input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  outline: none; /* outline: none を指定 */
  cursor: pointer;
  width: 100%;
  background: #efafda;
  height: 8px;
  border-radius: 8px;
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  height: 20px;
  width: 20px;
  background-color: #4cabe2;
  border-radius: 50%;
}

input[type="range"]::-moz-range-thumb {
  border: none;
  height: 20px;
  width: 20px;
  background-color: #4cabe2;
  border-radius: 50%;
}

input[type="range"]::-webkit-slider-thumb:hover {
  box-shadow: 0 0 0 7px rgba(0, 30, 255, 0.1)
}
input[type="range"]:active::-webkit-slider-thumb {
  box-shadow: 0 0 0 10px rgba(0, 30, 255, .2)
}
input[type="range"]:focus::-webkit-slider-thumb {
  box-shadow: 0 0 0 10px rgba(0, 30, 255, .2)
}

input[type="range"]::-moz-range-thumb:hover {
  box-shadow: 0 0 0 7px rgba(0, 30, 255, .1)
}
input[type="range"]:active::-moz-range-thumb {
  box-shadow: 0 0 0 10px rgba(0, 30, 255, .2)
}
input[type="range"]:focus::-moz-range-thumb {
  box-shadow: 0 0 0 10px rgba(0, 30, 255, .2)
}

JavaScript で領域を塗り分ける

デフォルトの(カスタマイズしていない) Chrome や Firefox のレンジスライダーではつまみの左側の領域が異なる色で表示されますが、これを CSS で実装するのは難しいので JavaScript で色を塗り分けます。

この例では全てのレンジスライダーを対象にしていますが、必要に応じてセレクタを変更します。

レンジスライダーに input イベントのリスナーを設定し、スライダーが変更される度に Track の背景色の塗りの範囲を更新する関数 updateSlider() を呼び出します。

updateSlider() では、現在の値から割合(%)を取得して、linear-gradient を使って Track の背景色を塗り分けます。linear-gradient では位置を % で指定できるので取得した割合(%)を指定して塗り分けます。

document.addEventListener('DOMContentLoaded', () => {

  // 全てのレンジスライダーの要素を取得(必要に応じてセレクタを変更)
  const rangeSliders = document.querySelectorAll('input[type="range"]');
  // Track の元の色
  const baseColor = '#efafda';
  // Track のつまみの左側の部分の色
  const activeColor = '#87ac98';

  // 取得したレンジスライダーの各要素に対して実行
  rangeSliders.forEach((slider) => {
    // input イベントのリスナーを設定
    slider.addEventListener('input', (e) => {
      // updateSlider を呼び出す
      updateSlider(e.target);
    });
    // updateSlider を実行して現在の値を反映
    updateSlider(slider);
  });

  // input イベントで呼び出される関数(トラックの塗りの範囲と色を設定する関数)
  function updateSlider(slider) {
    // max 属性の値が省略されている場合は100を設定
    if(!slider.max) {
      slider.max = 100;
    }
    // 現在の値から割合(%)を取得
    const progress = (slider.value / slider.max) * 100;
    // linear-gradient で Track の色を設定
    slider.style.background = `linear-gradient(to right, ${activeColor} ${progress}%, ${baseColor} ${progress}%)`;
  }

});

linear-gradient では、グラデーションの開始色と終了色を同じ色を指定するとグラデーションではなく単色で塗ることができます。

.dual-color {
  background: linear-gradient(to right, red 30%, blue 30%);
}

上記は 0% と 100% を省略しているので以下と同じことです。

.dual-color {
  background: linear-gradient(to right, red 0%, red 30%, blue 30%, blue 100%);
}

カスタムデータ属性の利用

Track を input 要素に直接設定する方法で、input[type="range"] にカスタムデータ属性(data-* 属性)を設定して、Track の色を HTML 側で指定する例です。

HTML では data-bgc に Track の背景色を、data-active-bgc につまみの左側の領域の背景色を指定します。省略した場合は、JavaScript でデフォルトを設定した値が適用されます(片方のみを指定可能)。

但し、CSS で input[type="range"] に設定した背景色は上書きされます。

HTML
<input type="range" data-bgc="#b9dd83" data-active-bgc="#83c8dd">

JavaScript ではカスタムデータ属性の値を dataset プロパティを使って取得して、設定されていればその値を使用し、設定されていない場合はデフォルトの値を設定します。

JavaScript
document.addEventListener('DOMContentLoaded', () => {
  const rangeSliders = document.querySelectorAll('input[type="range"]');

  rangeSliders.forEach((slider) => {
    slider.addEventListener('input', (e) => {
      updateSlider(e.target);
    });
    updateSlider(slider);
  });

  function updateSlider(slider) {
    if(!slider.max) {
      slider.max = 100;
    }

    //Track の色(data-bgc が設定されていればその色を使用し、なければデフォルト値を設定)
    const bc =
      slider.dataset.bgc ? slider.dataset.bgc : '#efafda';

    //Track のつまみの左側の部分の色(data-active-bgc が設定されていればその色を使用)
    const ac =
      slider.dataset.activeBgc ? slider.dataset.activeBgc : '#87ac98';

    const progress = (slider.value / slider.max) * 100;
    slider.style.background =
       `linear-gradient(to right, ${ac} ${progress}%, ${bc} ${progress}%)`;
  }

});