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

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

enter image description here

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

Можно ли программно обнаруживать (предпочтительно с помощью vanilla JS), на которомсторона является полосой прокрутки?


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


UPD (15.10.2018): TLDR: нет пути.

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

Ответы [ 7 ]

0 голосов
/ 11 октября 2018

Как показано здесь , полоса прокрутки не изменит сторону с dir="rtl" на html или body HTML-тегами в 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>

Этот код CSS будет выполнять прокрутку элемента body вместо элемента html.Как ни странно, если поставить прокрутку на body, появится полоса прокрутки в нужном месте.Работает с последними версиями браузеров.

Точная совместимость (проверена самая старая рабочая версия):

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

Используя совместимые браузеры, вы можете «доверять» положению полосы прокрутки на основе атрибута 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>

Совместимость (проверена самая старая рабочая версия):

  • IE => v6 - 2001
  • Edge => all
  • Firefox => v4 - 2011
  • Opera => v10 - 2009
  • Chrome => v15 - 2011
  • Safari => не работает

Это решение не очень полезно, если прокрутка находится на теге body, поскольку, как упоминалось выше, в этом случае мы можем "доверять" атрибуту dir.Я поставил его здесь, потому что , вероятно, можно адаптировать для прокрутки на теге html.

0 голосов
/ 11 октября 2018

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

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

0 голосов
/ 11 октября 2018

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

0 голосов
/ 10 октября 2018

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

Все, что вам нужно, это 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>
0 голосов
/ 09 октября 2018

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

Вы можете управлять полосой прокрутки с помощью CSS.Изменение свойства direction также изменит полосу прокрутки.И в Javascript вы можете реагировать на все события или изменения атрибутов или что вы хотите.

Вот Boilerplate для игры с

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 вы можете реагировать на все события или изменения атрибутов или что вы хотите.Возможно, вы захотите использовать mutationObserver в HTML-элементе, если хотите изменить атрибут dir, а затем отреагировать на это.

0 голосов
/ 27 сентября 2018

первая идея, которая пришла в голову, это использовать 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;
}

   dummy



0 голосов
/ 22 сентября 2018

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

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

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