web-dev-qa-db-fra.com

Comment détecter de quel côté du navigateur se trouve la barre de défilement - droite ou gauche (en cas de RTL)?

Pour <html dir="rtl">, certains navigateurs (Safari, Edge, IE) déplacent automatiquement la barre de défilement vers la gauche, ce qui est le comportement correct:

 enter image description here

Malheureusement, les principaux navigateurs (Chrome et Firefox) se comportent différemment, la barre de défilement se trouvant toujours à droite du navigateur.

Est-il possible de détecter par programme (de préférence avec Vanilla JS) de quel côté est la barre de défilement?


UPD (28.09.2018): jusqu'à présent, il n'y a pas de solution de travail dans les réponses, les utilisateurs essaient de détecter la position de la barre de défilement à l'aide de getBoundingClientRect().left ou .offsetLeft et que ne fonctionnera pas car ce sera toujours 0 au moins dans Edge. indépendamment de la position de la barre de défilement.


UPD (15.10.2018): TLDR: c'est impossible. 

Il semble que les navigateurs ne fournissent pas d'API pour détecter le côté barre de défilement. Dans les réponses ci-dessous, il y a des astuces avec l'insertion d'une variable factice div et le calcul de la position de la barre de défilement dans cette div. Je ne peux pas considérer ces astuces comme une réponse car la barre de défilement du document peut être positionnée de plusieurs manières (<html dir="rtl">, version RTL du système d'exploitation, paramètres du navigateur, etc.)

26
Limon Monte

Comme il est montré ici , la barre de défilement ne changera pas de côté avec dir="rtl" sur html ou body balise HTML dans Firefox, Chrome, Opera et Safari. Cela fonctionne sur IE et Edge. J'ai essayé (sur Edge 17, IE 11, Firefox 62, Chrome 69, Opera 56, Safari 5.1) et il est toujours d'actualité en octobre 2018 (Safari> 9.1, barre de défilement à gauche si dir="rtl").

Je n'ai pas trouvé de navigateur croisé solution native jusqu'à présent pour trouver la position de la barre de défilement comme vous l'avez demandé. Je ne pense pas que vous en avez un. Nous pouvons seulement essayer de trouver "bidouille" pour le réparer ...

Sur la base de vos questions/commentaires et de votre véritable problème ici , je pense qu’il serait préférable de se concentrer sur la compatibilité de dir="rtl". Vous essayez de connaître la position de la barre de défilement car elle ne fonctionnait pas comme prévu initialement. Pour que cela fonctionne comme prévu, une solution rapide pourrait être de placer le parchemin sur l'élément 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>

Ce code CSS fera en sorte que l'élément body défile au lieu de l'élément html. Étrangement, placez le parchemin sur body pour afficher la barre de défilement au bon endroit. Cela fonctionne pour les versions récentes des navigateurs.

La compatibilité exacte est (la plus ancienne version de travail testée): 

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

Avec les navigateurs compatibles, vous pouvez "faire confiance" à la position de la barre de défilement en fonction de l'attribut dir. Cela signifie que pour les navigateurs listés ci-dessus, la barre de défilement sera à gauche pour dir="rtl" et à droite pour dir="ltr". J'ai testé et ça marche.

Pour les anciennes versions de navigateurs, je n'ai pas de solution pour le moment. Cela signifie que vous ne serez pas totalement compatible, mais c'est principalement un problème de safari, comme vous pouvez le constater.

EDIT: Recherche pour trouver la position de la barre de défilement

Comme je l'ai mentionné ci-dessus, je pense que nous pouvons essayer de trouver un "hack" pour trouver la position de la barre de défilement. Je ne suis pas un expert en CSS, ma solution n'est donc pas très jolie. Quelqu'un avec des compétences en CSS pourrait probablement trouver une bonne solution.

Si le parchemin est sur le corps (solution ci-dessus), nous pouvons détecter la position de la barre de défilement avec l'élément positionné css. Par exemple ce code:

<!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>

La compatibilité est la plus ancienne (version de travail testée):

  • IE => v6 - 2001
  • Edge => tous
  • Firefox => v4 - 2011
  • Opera => v10 - 2009
  • Chrome => v15 - 2011
  • Safari => _ {ne fonctionne pas

Cette solution n'est pas très utile si le parchemin se trouve sur la balise body car, comme mentionné ci-dessus, nous pouvons "faire confiance" à l'attribut dir. Je le mets ici car il pourrait probablement être adapté au défilement de la balise html.

3
ElJackiste

J'ai amélioré sur Andre 's répondre :

Tout ce dont vous avez besoin est 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
yunzen

Ce n'est pas une solution très robuste mais elle peut être utilisée comme base pour en créer une meilleure.

La logique de base est que les éléments enfants passent à droite lorsqu'il y a une barre de défilement sur le côté gauche de l'élément conteneur. Il suffit de mesurer ce décalage en présence et en absence de barre de défilement.

Voici une fonction simple basée sur jQuery qui le fait. scrollElement est l'élément où nous devons détecter la position de la barre de défilement. Généralement, il devrait s'agir de html/body mais pas nécessairement, je ne connais pas de méthode simple pour le découvrir.

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;
}
0
11thdimension

la première idée qui nous est venue à l’esprit est d’utiliser getBoundingClientRect (compatibilité IE 4+)

Le seul problème est que si la barre de défilement a une largeur de 0 px comme sur Mac, cela ne le détectera pas


La seconde idée consiste à utiliser getComputedStyle (compatibilité: IE9 +)

Veuillez lire le code de l'extrait: 

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>

0
Andrii Muzalevskyi