如何检测浏览器的哪一侧是滚动条-右侧还是左侧(对于RTL)?

时间:2018-09-19 10:57:16

标签: javascript scrollbar arabic right-to-left hebrew

对于<html dir="rtl">,某些浏览器(Safari,Edge,IE)会自动将滚动条移动到左侧,这是正确的行为:

enter image description here

不幸的是,主要的浏览器(Chrome和Firefox)的行为方式不同,滚动条仍位于浏览器的右侧。

是否可以通过编程方式(最好是Vanilla JS)检测滚动条在哪一侧?


UPD(28.09.2018):到目前为止,答案中没有有效的解决方案,人们正在尝试使用getBoundingClientRect().left.offsetLeft检测滚动条的位置,而不会< / strong>之所以起作用,是因为它至少始终独立于滚动条位置而位于0中。


UPD(15.10.2018):TLDR:没有办法。

似乎浏览器不提供用于检测滚动条一侧的API。在下面的答案中,有一些技巧,可以插入一个虚拟div并计算该div中的滚动条在哪里。我不能将这些技巧当作答案,因为可以使用多种方式(<html dir="rtl">,操作系统的RTL版本,浏览器设置等)来定位文档滚动条

8 个答案:

答案 0 :(得分:3)

here所示,滚动条不会改变侧面,在Firefox中dir="rtl"html HTML标记上带有body, Chrome,Opera和Safari。它适用于IE和Edge。我尝试过(在Edge 17,IE 11,Firefox 62,Chrome 69,Opera 56,Safari 5.1上使用),但它在2018年10月仍然有用(如果dir="rtl",Safari> 9.1显示滚动条在左侧)。

到目前为止,我没有找到任何跨浏览器本机解决方案,可以按照您的要求找到滚动条的位置。我不认为你有一个。我们只能尝试找到“ hack”来解决它...

根据您的问题/评论和您的实际问题here,我认为最好集中注意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上将在正确的位置显示滚动条。它适用于最新版本的浏览器。

确切的兼容性是(经过测试的最旧的工作版本):

  • IE => v6-2001
  • Edge =>全部
  • Firefox => v4-2011
  • Opera => v10-2009
  • Chrome => v19-2012
  • Safari => v10.1-2016

使用兼容的浏览器,您可以根据dir属性“信任”滚动条的位置。这意味着对于上面列出的浏览器,滚动条将在dir="rtl"的左侧,在dir="ltr"的右侧。我已经测试过并且可以正常工作。

对于较旧的浏览器版本,我暂时没有修复。这意味着您将不完全兼容,但是如您所见,这主要是野生动物园的问题。

编辑:进行搜索以找到滚动条的位置

如上所述,我认为我们可以尝试找到“ hack”来查找滚动条的位置。我不是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>

兼容性是(经过测试的最旧的工作版本):

  • IE => v6-2001
  • Edge =>全部
  • Firefox => v4-2011
  • Opera => v10-2009
  • Chrome => v15-2011
  • Safari => 不起作用

如果滚动位于body标记上,则此解决方案不是很有用,因为如上所述,在这种情况下,我们可以“信任” dir属性。我把它放在这里是因为它可以可能适应html标签上的滚动。

答案 1 :(得分:2)

我对Andreanswer进行了改进:

您只需要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>

答案 2 :(得分:0)

这不是一个非常可靠的解决方案,但可以用作创建更好的解决方案的基础。

基本逻辑是,当容器元素的左侧有滚动条时,子元素将向右移动。我们要做的就是测量是否存在滚动条。

这是一个基于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;
}

答案 3 :(得分:0)

首先想到的是使用getBoundingClientRect(兼容IE 4 +)

唯一的问题是,如果滚动条的宽度为0px(与Mac一样)-这将无法检测到


第二个想法是使用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>

答案 4 :(得分:0)

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}

答案 5 :(得分:-1)

据我所知,没有办法做到这一点。但是,如果将滚动条包装到可滚动的DIV中,则可以将其强制向左侧移动。我不确定这是否是您想要的,但是可以。 (它可以在我的机器上运行-我只能在Mac上的Firefox,Chrome和Safari中对其进行测试)

您可以使用CSS控制滚动条。更改direction属性也会更改滚动条。 而且,在Javascript中,您可以对所有事件或属性更改或所需的内容做出反应。

这是一个样板游戏

const btn = document.querySelector('Button');
const html = document.querySelector('html');
const wrap = document.querySelector('#myBodyWrapper');
let state = 'ltr';
var inner = '';
for (let i = 0; i < 500; i++) {
  inner += 'Lorem ipsum Bla bla bla<br>';
}
wrap.innerHTML = inner;
btn.addEventListener('click', function() {
  state = (state === 'ltr') ? 'rtl' : 'ltr';
  wrap.style.direction = state;
}, false);
body {
  margin: 0;
  padding: 0;
  overflow: hidden;
}

div#myBodyWrapper {
  direction: ltr;
  overflow: auto;
  height: 100vh;
  width: 100vw;
}
button{
    background-color:gold;
    padding:5px;
    margin:5px 0;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <button>Switch scrollbar</button>
  <div id="myBodyWrapper">

  </div>

</body>

</html>

现在,您可以使用CSS控制滚动条。而且,在Javascript中,您可以对所有事件或属性更改或所需的内容做出反应。 如果要更改dir属性,然后对此做出反应,则可能需要在HTML元素上使用mutationObserver。

答案 6 :(得分:-1)

滚动条是body元素的一部分,您将无法“检查”非HTML元素。

答案 7 :(得分:-1)

这个问题的解决方案可能非常创新,我有一个主意:

  1. 我声明了一个JavaScript函数,以将元素的左侧位置返回到整个文档中。
  2. 我声明了另一个函数,用于在体内创建visibility: hidden之类的div元素,其名称为parent
  3. 我在父级div内创建另一个div,将其命名为child,然后使用#1中的函数计算左侧的子位置。
  4. 我将overflow-y: scroll设置为父div,然后重新计算子div的左侧位置。
  5. 如果孩子的第二个计算位置减小,则表示滚动条在右侧。如果增加,则表示滚动条在左侧。如果未显示任何更改,则表示根本没有像使用滚动板或魔术鼠标的Mac OSX浏览器那样的滚动条。

请参见以下代码:

function leftOffset(el) {
  const rect = el.getBoundingClientRect();
  const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
  return rect.left + scrollLeft;
}

上面的函数只是计算左位置,现在请看下面的代码以了解浏览器滚动条的侧面:

function getScrollbarSide() {
  const parent = document.createElement('div'); // parent
  parent.style.visibility = 'hidden';
  parent.style.width = '100px';
  parent.style.height = '50px';
  parent.style.position = 'relative';

  const child = document.createElement('div'); // child
  child.style.width = '1px';
  child.style.height = '1px';
  child.style.position = 'absolute';
  child.style.left = '50%';

  document.body.appendChild(parent);
  parent.appendChild(child);

  const leftOffsetNoScroll = leftOffset(child); // calculate left offset of child without parent scrollbar
  parent.style.overflowY = 'scroll';

  const leftOffsetWithScroll = leftOffset(child); // calculate left offset of child with parent scrollbar

  const calc = leftOffsetNoScroll - leftOffsetWithScroll;

  if (calc > 0) {
    return 'right';
  }
  if (calc < 0) {
    return 'left';
  }
  return 'no-scrollbar';
}

现在,只需运行getScrollbarSide()