Javascript – ブラウザのスクロールバーをcssでサクッとデザイン変更。

ブラウザのスクロールバーをサクッと変更したいと思いまして、サクッと。

有名どころで言えば、

perfect-scrollbar
min.js 24,398KB | min.css 4,412KB
SimpleBar
min.js 46,398KB | min.css 2,487KB

があると思いますが、仕様になれるのも面倒なのと、少しファイルサイズも気になるので
作った方が早いのかなと思い作ってみることにしました。

スクリプト設計

まず最初に

  1. 上記二つのスクリプトより軽量
  2. 余計な機能はつけない
  3. 基本CSSの設定で色々変更できるようにする

の三つを念頭に進めていきます。

とりあえずプロジェクト名は「sklorrval(スクロォヴァル)」。

設計的にはスクロールバーがあればバーサイズ分だけ中の要素を広げて、親要素にてoverflow: hidden;で隠すことにしました。
これならブラウザの恩恵もそのままで、余計なコードを書く必要もなさそうです。

出来上がってから気づいたので少し悲しいですが、
上記で進めるとTEXTAREA要素の場合にお粗末な感じになるので再設計。
また、要素にposition: absolute;を設定した場合など色々と問題あり。

やり直し。
TEXTAREAを無視すれば結構簡単だった… 残念。
よく見たらSimpleBarもTEXTAREAには対応していないような感じです。

ターゲットの判別

  1. 自身にoverflow: scroll;, overflow: auto;の設定がある場合
  2. overflowの設定がなくてもスクロール領域がある場合
  3. 指定したHTML要素は除外 & ブロック要素のみ & TEXTAREA要素は強制的

の3つで判別。

2まででいいつもりでしたが、scrollHeightの高さがテキストのbaselineに依存するのか少しズレが生じるため、
特定のHTML要素を除外したりと3で調整することにしました。

判別のスクリプトは下記の感じ。
結構複雑になってしまいました。残念。

1
// Get all styles of element
2
var getStyle = function (el) {
3
    return el.currentStyle || document.defaultView.getComputedStyle(el, '');
4
}
5

6
// Execute the script or determine the target
7
var isTarget = function (el) {
8

9
    var scrollStyle = getStyle(el);
10
    var overflowX = scrollStyle.overflowX;
11
    var overflowY = scrollStyle.overflowY;
12
    var overflow = scrollStyle.overflow;
13
    if (overflowX === "undefined") overflowX === "";
14
    if (overflowY === "undefined") overflowY === "";
15
    if (overflow === "undefined") overflow === "";
16
    if (overflowX === "") overflowX = overflow;
17
    if (overflowY === "") overflowY = overflow;
18

19
    var scrollbarHorizontal = (
20
        (overflowX === "scroll") || (overflowX === "auto") || (
21
            ((overflowX === "hidden") || (overflowX === "visible")) && ((el.scrollWidth > el.clientWidth))
22
        )
23
    );
24
    var scrollbarVertical = (
25
        (overflowY === "scroll") || (overflowY === "auto") || (
26
            ((overflowY === "hidden") || (overflowY === "visible")) && ((el.scrollHeight > el.clientHeight))
27
        )
28
    );
29

30
    var isTextarea = el.nodeName === "TEXTAREA";
31
    var isBlockElement = scrollStyle.display === "block";
32
    var isTargetElement = true;
33
    var excludeHtmlElements = ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'SCRIPT', 'NOSCRIPT', 'STYLE'];
34
    for (var i = 0; i < excludeHtmlElements.length; i++) {
35
        if (excludeHtmlElements[i] === el.nodeName) {
36
            isTargetElement = false;
37
            break;
38
        }
39
    }
40

41
    if ((scrollbarVertical || scrollbarHorizontal) && (isTargetElement && (isTextarea || isBlockElement))) {
42
        return true;
43
    } else {
44
        return false;
45
    }
46
}