_<html dir="rtl">
_の場合、一部のブラウザー(Safari、Edge、IE)は自動的にスクロールバーを左側に移動しますが、これは正しい動作です。
残念ながら、主要なブラウザー(ChromeおよびFirefox)の動作は異なり、スクロールバーはブラウザーの右側にあります。
プログラム的に(できればバニラJSで)どちらの側がスクロールバーであるかを検出することは可能ですか?
UPD(28.09.2018):これまでのところ、答えには実用的な解決策はありません。人々はgetBoundingClientRect().left
または_.offsetLeft
_を使用してスクロールバーの位置を検出しようとしています動作しませんスクロールバーの位置とは関係なく、少なくともEdgeでは常に_0
_になるためです。
UPD(15.10.2018):TLDR:方法はありません。
ブラウザがスクロールバー側を検出するためのAPIを提供していないようです。以下の回答では、ダミーdiv
を挿入し、そのdivのどこにスクロールバーがあるかを計算するトリックがあります。ドキュメントのスクロールバーが複数の方法(_<html dir="rtl">
_、OSのRTLバージョン、ブラウザー設定など)で配置されている可能性があるため、これらのトリックを回答と見なすことはできません。
それが示されているように here 、スクロールバーはhtml
またはbody
HTMLタグの_dir="rtl"
_でサイドを変更しません Firefox、Chrome、Opera&Safari。これはIE&Edgeで動作します。私は(Edge 17でIE = 11、Firefox 62、Chrome 69、Opera 56、Safari 5.1)であり、2018年10月にも引き続き関連があります(Safari> 9.1左側のディスプレイスクロールバーif _dir="rtl"
_)。
これまでクロスブラウザーネイティブソリューションが見つかりませんでしたスクロールバーの位置を見つけますあなたが尋ねたように。持っているとは思いません。私たちはそれを修正するために「ハック」を見つけようとするだけです...
あなたの質問/コメントとあなたの本当の問題 ここ に基づいて、_dir="rtl"
_の互換性に焦点を当てた方が良いと思います。そもそもスクロールバーが期待どおりに機能していなかったため、スクロールバーの位置を調べようとしています。期待どおりに機能させるには、body
要素にスクロールを配置することで簡単に修正できます。
_<!DOCTYPE html>
<html dir="rtl">
<head>
<meta charset="utf-8">
<title></title>
<style>
html, body {
height: 100%;
overflow: hidden;
}
body {
padding: 0;
margin: 0;
overflow-y: auto; /* or overflow: auto; */
}
p {
margin: 0;
font-size: 8em;
}
</style>
</head>
<body>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</body>
</html>
_
このcssコードは、body
要素ではなくhtml
要素をスクロールするようにします。厳密に言えば、body
にスクロールを置くと、適切な場所にスクロールバーが表示されます。最近のバージョンのブラウザで動作します。
正確な互換性は(テスト済みの最も古い動作バージョン)です。
互換性のあるブラウザでは、dir
属性に基づいてスクロールバーの位置を「信頼」できます。つまり、上記のブラウザの場合、スクロールバーは、左側に_dir="rtl"
_があり、右側に_dir="ltr"
_があります。私はテストし、それは動作します。
古いバージョンのブラウザの場合、今のところ修正はありません。これは完全には互換性がないことを意味しますが、ご覧のように主にサファリの問題です。
編集:スクロールバーの位置を見つけるための検索
上で述べたように、スクロールバーの位置を見つけるための「ハック」を見つけることができると思います。私はCSSのエキスパートではないので、私の解決策はあまりきれいではありません。 CSSスキルを持つ誰かがおそらく良い解決策を見つけることができます。
スクロールが本体にある場合(上記のソリューション)、css配置要素でスクロールバーの位置を検出できます。たとえば、次のコード:
_<!DOCTYPE html>
<html dir="rtl">
<head>
<meta charset="utf-8">
<title></title>
<style>
html, body {
height: 100%;
overflow: hidden;
}
body {
padding: 0;
margin: 0;
overflow-y: auto;
}
p {
margin: 0;
font-size: 8em;
}
#sc { position: relative; float: left; }
#sc_2 { position: relative; float: right; }
#sc_3 { position: absolute; width: 100%; }
</style>
</head>
<body>
<div id="sc"></div>
<div id="sc_2"></div>
<div id="sc_3"></div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<script>
var html = document.getElementsByTagName('html')[0];
var sc = document.getElementById('sc');
var sc_2 = document.getElementById('sc_2');
var sc_3 = document.getElementById('sc_3');
if (sc_2.offsetLeft < html.clientWidth && !(sc_3.offsetLeft < 0)) {
console.log('bar on the right');
} else if (sc.offsetLeft > 0 || sc_3.offsetLeft < 0) {
console.log('bar on the left');
} else {
console.log('no bar');
}
</script>
</body>
</html>
_
互換性は(テスト済みの最も古い動作バージョン)です。
スクロールがbody
タグ上にある場合、この解決策はあまり役に立ちません。この場合、上記のように、dir
属性を「信頼」できるためです。 html
タグのスクロールにおそらく適応できるため、ここに配置しました。
必要なのはgetComputedStyle()
だけです
console.clear();
const btn = document.querySelector('Button');
const html = document.querySelector('html');
const wrap = document.querySelector('#myBodyWrapper');
const input = document.querySelector('input');
var state = 'ltr';
var inner = '';
for (var i = 0; i < 500; i++) {
inner += 'Lorem ipsum Bla bla bla<br>';
}
wrap.innerHTML = inner;
btn.addEventListener('click', function() {
toggleDirection(html)
}, false);
function getDirection(elem) {
return window.getComputedStyle(elem).direction
}
function setDirection(elem, direction) {
elem.setAttribute('dir', direction)
}
function toggleDirection(elem) {
if (getDirection(elem) === 'ltr' || getDirection(elem) === undefined) {
setDirection(elem, 'rtl')
} else {
setDirection(elem, 'ltr')
}
input.value = getDirection(elem)
}
input.value = getDirection(html)
body {
margin: 0;
padding: 0;
overflow: hidden;
text-align: center;
}
div#myBodyWrapper {
overflow: auto;
height: 80vh;
text-align: start;
margin: 10px 40px;
padding: 10px;
background-color: goldenrod;
}
button {
background-color:gold;
padding:5px;
margin:5px 0;
}
input {
background-color: silver;
text-align: center;
padding: 5px;
font-size: 20px;
}
<button>Switch scrollbar</button><br>
<input type="text" value="">
<div id="myBodyWrapper"></div>
これは非常に堅牢なソリューションではありませんが、より優れたソリューションを作成するための基礎として使用できます。
基本的なロジックは、コンテナ要素の左側にスクロールバーがある場合、子要素が右にシフトすることです。私たちがしなければならないのは、スクロールバーの有無の変化を測定することだけです。
これはjQuery
に基づく単純な関数で、これを実行します。 scrollElement
は、スクロールバーの位置を検出する必要がある要素です。ほとんどはhtml/body
必ずしもそうとは限りませんが、それを見つける簡単な方法は知りません。
function isScrollLeft(scrollElement) {
var $scrollElement = $(scrollElement);
$scrollElement.append('<div id="scroll_rtl_tester" style="width=100%;height: 1px;"/>');
var $scrollTester = $('#scroll_rtl_tester');
var beforeLeftOffset = $scrollTester.offset().left;
var originalOverflow = $scrollElement.css('overflow-y');
$scrollElement.css('overflow-y', 'hidden');
var afterLeftOffset = $scrollTester.offset().left;
$scrollElement.css('overflow-y', originalOverflow);
$scrollTester.remove();
var isRtl = false;
if(beforeLeftOffset > afterLeftOffset) {
isRtl = true;
}
return isRtl;
}
document.elementFromPoint(-1、0)は、スクロールバーが左側にあるときにルート要素を返します。
var scrollbarInfo = (function() {
var body = document.body;
var styleAttr = body.getAttribute("style") || "";
body.setAttribute("style", styleAttr + ";overflow-y:scroll!important");
var outer = body.appendChild(document.createElement("div"));
outer.setAttribute("style", "position:fixed;overflow:scroll");
var inner = outer.appendChild(document.createElement("div"));;
try {
return {
width: outer.offsetWidth - inner.offsetWidth,
outerPosition: document.elementFromPoint(-1, 0) ? "left" : "right",
innerPosition: outer.getBoundingClientRect().left < inner.getBoundingClientRect().left ? "left" : "right",
};
} finally {
body.setAttribute("style", styleAttr);
body.removeChild(outer);
}
})();
IE/Edge:
{outerPosition: "left", innerPosition: "left", width: 12}
Chrome/Firefox:
{outerPosition: "right", innerPosition: "left", width: 17}
Android/iOS:
{outerPosition: "right", innerPosition: "right", width: 0}
MacOS Safari:
{outerPosition: "right", innerPosition: "right", width: 0}
頭に浮かんだ最初のアイデアは、使用することです getBoundingClientRect (compatibility IE 4+)
唯一の問題は、Macのようにスクロールバーの幅が0pxの場合、これが検出されないことです。
2番目のアイデアは getComputedStyle を使用することです(互換性:IE9 +)
スニペットコードを読んでください:
let outer = document.querySelector('.outer');
let inner = document.querySelector('.inner');
let pre = document.querySelector('pre');
// ***
// Bounding client rect detection
// ***
let posOuter = outer.getBoundingClientRect();
let posInner = inner.getBoundingClientRect();
let found = false;
if (posOuter.left !== posInner.left) {
pre.innerHTML += "getBoundingClientRect detection: Scroll at left side\n";
found = true;
}
if (posOuter.right !== posInner.right) {
pre.innerHTML += "getBoundingClientRect detection: Scroll at right side\n";
found = true;
}
if (!found) {
pre.innerHTML += "getBoundingClientRect detection: Scroll in not found\n";
}
pre.innerHTML += "\n\n\n";
// ***
// getComputedStyle detection
// ***
let style = window.getComputedStyle(outer);
pre.innerHTML += "getComputedStyle detection: CSS direction is: " + style.getPropertyValue('direction') + "\n";
pre.innerHTML += "getComputedStyle detection: so scroll is on " + (style.getPropertyValue('direction') === 'rtl' ? 'left' : 'right') + ' side';
.outer{
width: 100px;
height: 100px;
overflow-x: scroll;
outline: 1px solid red;
border: none; /* !!! */;
}
.inner{
height: 105px;
box-sizing: border-box;
border: 15px dashed green;
}
<div class="outer">
<div class="inner">dummy</div>
</div>
<pre>
</pre>