Intro
サイトを作成する際、input
タグのRangeスライダーを縦に配置したくなる場面が稀にあると思います。
この記事では、スライダーを縦に表示する2種類の方法とそれぞれの問題点、そしてレスポンシブ対応について解説します。
方法
縦スライダーを表示するには主に以下の2通りがあります。
webkit-appearance
で設定transform
で回転させる
それぞれの方法と問題点について解説します。
webkit-appearance
2021年の9月末、Firefoxを除くChromeやSafariなどの主要ブラウザが縦スライダーの表示をサポートしました。
やり方は簡単で、input
のCSSプロパティに-webkit-appearance: slider-vertical
を設定すれば縦方向に表示されます。
input[type=range].vertical {
-webkit-appearance: slider-vertical;
}
以下が実際に動作するデモです。
See the Pen spectrum-web-analyzer by FOURIER Inc. (@fourier-inc) on CodePen.
この方法の利点として、後述する回転させるやり方と比較すると、親要素が回転後のスライダーの大きさに合うためレスポンシブ対応がしやすいという利点があります。
ただ、以下のような多くの欠点があります。
- Firefoxがこの文法に対応していない
- thumb(丸い部分)のスタイリングが効かない
- track(thumbの可動範囲)が細すぎると表示が崩れる
現状この機能を使うにはまだ時期尚早と言え、実用的な解決策とは言えません。
transform
次に、昔からある方法として、input
要素のCSSプロパティにtransform: rotate(-0.25turn);
を追加する方法があります。これはスライダーを90°回転させて表示させるやり方です。
input[type=range].vertical {
transform: rotate(-0.25turn);
}
このやり方にwebkit-apparance
で発生したスタイリングが当たらない問題や対応ブラウザの問題はないため、こちらのほうが実用的です。
ただ、そのままだと以下の例のように親要素をはみ出してしまいます。
See the Pen spectrum-web-analyzer by FOURIER Inc. (@fourier-inc) on CodePen.
これは、親要素の大きさが回転前のinput
タグの大きさに合わせており、回転後のスライダーの大きさ(height
、width
が逆になる)に合ってないからです。
はみ出さないようにする
スライダーを親要素からはみ出さないようにする最も簡単な解決方法は、親要素の大きさをスライダーに合わせて指定する方法です。しかし、そのやり方だとレスポンシブ対応になっていないという問題があります。
レスポンシブなスライダーを作成するために、以下のコンポーネントと機能を実装します。
まず、input
要素をラップしたコンポーネントを作成します。そして、ラッパー要素のwidth
、height
プロパティを読み込み、input
要素のheight
、width
プロパティに適応させるJavaScriptコードを書きます。
customElements.define(
'vertical-slider',
class extends HTMLElement {
get min() {
return this.getAttribute('min') || 0;
}
set min(val) {
this.setAttribute('min', val);
}
get max() {
return this.getAttribute('max') || 100;
}
set max(val) {
this.setAttribute('max', val);
}
get step() {
return this.getAttribute('step') || 1;
}
set step(val) {
this.setAttribute('step', val);
}
get value() {
return this.getAttribute('value') || 50;
}
set value(val) {
this.setAttribute('value', val);
}
render() {
const input = document.createElement('input');
input.setAttribute('type', 'range');
input.setAttribute('min', this.min);
input.setAttribute('max', this.max);
input.setAttribute('step', this.step);
input.setAttribute('value', this.value);
wrapper.appendChild(input);
const style = document.createElement('style');
style.textContent = `
:host {
--width: 16px;
--height: 175px;
display: inline-block;
position: relative;
margin-right: calc(var(--width) / 2);
width: var(--width);
height: var(--height);
}
input[type=range] {
position: absolute;
left: 0;
bottom: -0.75em;
transform: rotate(-90deg) translateY(calc(var(--width) / 2));
transform-origin: left;
width: var(--height);
height: var(--width);
}
`;
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.append(input);
shadowRoot.append(style);
}
connectedCallback() {
this.render();
}
attributeChangedCallback() {
this.render();
}
}
)
次に、親要素のheight
を読み取り、スライダーに適用させる機能を実装します。これはResizeObserver
というクラスを使用して実装します。
new ResizeObserver(entries => {
const height = entries[0].contentRect.height;
const slider = document.getElementById('vs');
slider.setAttribute('style', `
--height: ${height}px;
`);
}).observe(document.getElementById('frame'));
このコンポーネントによって、外側から見たときにレスポンシブに大きさが変化する縦スライダーを使用することができます。
<div class="container">
<p>vertical</p>
<div class="frame" id="frame">
<vertical-slider id="vs"></vertical-slider>
</div>
</div>
これらをWeb Componentとして実装したのが以下のコードです。白い枠がリサイズできるようになっており、ドラッグしてスライダーの大きさが変わることが確認できます。
See the Pen spectrum-web-analyzer by FOURIER Inc. (@fourier-inc) on CodePen.
まとめ
この記事では縦スライダーを表示する方法をwebkit-appearance
で設定する方法とtransform
で回転させる方法の2つを紹介し、それぞれの問題点を取り上げた後に、transform
で回転させた場合のレスポンシブ対応について取り上げました。
現状では実装するにはなかなか難易度が高く複雑なため、早く-webkit-appearance: slider-vertical;
で設定できるようになってほしいと思います。
新しいメンバーを募集しています
Hirayama / Engineer
1997年生まれ、南伊豆出身。学生時代にC#で画像処理アプリケーションを作ったりしていました。業務では主にLaravelを使用してサーバーサイドのプログラミングをしています。趣味はドライブとシミュレーションゲーム。