JavaScriptで一時的にスクロールを無効化する その2
前回とは異なる方法でスクロールを無効化する方法を探ってみました。今回はちゃんとIE (8以上) で動きます!
コード
コードはこちら。addCSS
と scrollBarWidth
はそれぞれコメントで示したURLを参考にさせていただきました。
// http://seussnu.b.sourceforge.jp/?p=22var addCSS = (function() { var style = document.createElement('style'); style.setAttribute('type', 'text/css'); document.getElementsByTagName('head')[0].appendChild(style); var stylesheet = document.styleSheets[0]; if (stylesheet.insertRule) { return function(selector, property, value) { stylesheet.insertRule(selector + '{' + property + ':' + value + ';}', stylesheet.cssRules.length); }; } else { return function(selector, property, value) { stylesheet.addRule(selector, property + ':' + value); }; }})();
// http://davidwalsh.name/detect-scrollbar-widthvar scrollBarWidth = (function() { var scrollDiv = document.createElement("div"); scrollDiv.style.width = '100px'; scrollDiv.style.height = '100px'; scrollDiv.style.overflow = 'scroll'; scrollDiv.style.position = 'absolute'; scrollDiv.style.top = '-9999px'; document.body.appendChild(scrollDiv);
var w = scrollDiv.offsetWidth - scrollDiv.clientWidth;
document.body.removeChild(scrollDiv);
return w;})();
addCSS('.noscroll', 'position', 'relative');addCSS('.noscroll', 'overflow', 'hidden');addCSS('.noscroll', 'padding-right', scrollBarWidth + 'px');
使い方
使う時はbody要素のクラスにnoscrollを追加するとスクロールが無効化され、削除すると再びスクロールできるようになります。
var addClass = function(element, className) { var classes = element.className.split(/\s+/); var i, n; for (i = 0, n = classes.length; i < n; ++i) { if (classes[i] == className) { return; } } classes.push(className); element.className = classes.join(' ');};
var removeClass = function(element, className) { var classes = element.className.split(/\s+/); var result = []; var i, n; for (i = 0, n = classes.length; i < n; ++i) { if (classes[i] != className) { result.push(classes[i]); } } element.className = result.join(' ');};
addClass(document.body, 'noscroll');removeClass(document.body, 'noscroll');
jQueryを使っているのであればクラスの操作は以下のようにできます。
$('body').addClass('noscroll');$('body').removeClass('noscroll');
実現方法
overflow:hiddenをbody要素に適用してスクロールバーを消し、スクロールさせないようにしています。しかし、それだけだとスクロールバーが消えた分描画領域が広がってしまい、一瞬表示が崩れてしまうので、事前にスクロールバーの幅を計算しておき、その分だけbody要素のpadding-rightを設定して縮めることで崩れを防いでいます。
問題点
スクロールバーを消した分の幅はpaddingで埋めているのですが、これでは誤魔化せない場所もあります。例えば、CSSのMedia Queriesの条件に使うスクリーンサイズはスクロールバーの有無で変わってしまうので、スタイルが切り替わる境界付近でスクロールを禁止すると、レイアウトが変化して見苦しくなる可能性があります。
2013-05-26 追記
この挙動、仕様ではなくWebKitのバグだったみたいですね。Blinkでは修正されたようです。WebKitも早く修正されるといいですね。