Как определить, на какой стороне браузера находится полоса прокрутки - справа или слева (в случае RTL)?

Для <html dir="rtl"> некоторые браузеры (Safari, Edge, IE) будут автоматически перемещать полосу прокрутки влево, что является правильным поведением:

enter image description here

К сожалению, основные браузеры (Chrome и Firefox) ведут себя по-другому, полоса прокрутки по-прежнему находится в правой части браузера.

Можно ли программно определить (желательно с ванильным JS), с какой стороны находится полоса прокрутки?


UPD (28.09.2018): до сих пор в ответах нет рабочего решения, люди пытаются определить позицию полосы прокрутки, используя getBoundingClientRect().left .offsetLeft или .offsetLeft и это не сработает, потому что оно всегда будет 0 по крайней мере в Край независимо от положения полосы прокрутки.


UPD (15.10.2018): TL;DR: нет способа.

Кажется, что браузеры не предоставляют API для обнаружения полосы прокрутки. В нижеприведенных ответах есть трюки с вставкой фиктивного div и вычисление, где находится полоса прокрутки в этом div. Я не могу рассматривать эти трюки как ответ, потому что панель прокрутки документа может располагаться несколькими способами (<html dir="rtl">, RTL-версия ОС, настройки браузера и т.д.).

Ответ 1

Как показано здесь, полоса прокрутки не изменит сторону с dir="rtl" на html или теге HTML body в Firefox, Chrome, Opera и Safari. Он работает на IE & Edge. Я попробовал (на Edge 17, IE 11, Firefox 62, Chrome 69, Opera 56, Safari 5.1), и это все еще актуально в октябре 2018 года (Safari> 9.1 отображает полосу прокрутки с левой стороны, если 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>

Ответ 2

Я улучшил на Андре ответ:

Все, что вам нужно, это 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>

Ответ 3

Это не очень надежное решение, но оно может быть использовано в качестве основы для создания лучшего.

Основная логика заключается в том, что дочерние элементы смещаются вправо, когда на левой стороне элемента контейнера есть полоса прокрутки. Все, что нам нужно сделать, это измерить сдвиг в присутствии и отсутствии полосы прокрутки.

Здесь простая функция, основанная на 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;
}

Ответ 4

первая идея, которая пришла в голову, - использовать getBoundingClientRect (IE совместимости 4+)

Единственная проблема заключается в том, что если полоса прокрутки будет иметь ширину 0 пикселей, как на 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>

Ответ 5

Насколько я знаю, нет никакого способа сделать это. Однако вы можете заставить панель прокрутки с левой стороны, если вы завернете ее в прокручиваемую DIV. Я не уверен, что это то, что вы хотите, но оно работает. (Он работает на моей машине - я могу проверить его только в Firefox, Chrome и Safari на Mac)

Вы можете управлять полосой прокрутки с помощью 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>

Ответ 6

Полоса прокрутки является частью элемента body, вы не сможете "проверять" не-HTML-элемент.

Ответ 7

Решение этого вопроса может быть очень инновационным, у меня есть идея:

  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().