Почему ссылка offsetLeft учитывает заполнение списка? - PullRequest
0 голосов
/ 30 апреля 2020

Я читаю атрибут offsetLeft элемента ссылки и изменяю положение другого соответственно. Однако это работает, как и ожидалось, только без каких-либо стилей (даже по умолчанию в браузере), применяемых к атрибутам позиции. Например: изменение в ul padding влияет на li offsetLeft и приводит к сдвигу от ожидаемой позиции.

navbarElementsList = document.getElementsByClassName('js-element');
navbarUnderline = document.getElementById('js-underline');
let navbarElement;

for (let i = 0, len = navbarElementsList.length; i < len; i++) {
    navbarElement = navbarElementsList[i];
    navbarElementsList[i].addEventListener('click', function(event){
        let underlineStart = this.offsetLeft;
        let underlineWidth = this.offsetWidth;
        document.getElementById('js-underline').style.left = underlineStart.toString() + "px";
        document.getElementById('js-underline').style.width = underlineWidth.toString() + "px";
    });
}
ul {
    list-style-type: none;
}
li {
    display: inline;
}
a {
    cursor: pointer;
}
#js-underline {
    position: relative;
    left: 0;
    width: 25px;
    height: 5px;;
    background-color: blue;
    transition: 0.5s ease;
    -moz-transition: 0.5s ease;
    -webkit-transition: 0.5s ease;
}
<!DOCTYPE html>
<html lang="pl">
<head>

  <meta charset="utf-8"/>
  <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>test</title>
  
</head>
<body>

    <ul style=" margin-left: 40px ;">
      <li><a class="c-navbar__element js-element">aaaaaaa</a></li>
      <li><a class="c-navbar__element js-element">bbbb</a></li>
      <li><a class="c-navbar__element js-element">c</a></li>
      <li><a class="c-navbar__element js-element">ddddddddddddddd</a></li>
      <li><div id="js-underline" class="c-navbar__underline"></div></li>
    </ul>

</body>
</html>

В приведенном выше примере я изменил ul margin-left на 40px, и, к сожалению, он добавляет к итоговой позиции #underline. Кто-нибудь может объяснить это поведение и сказать мне, как правильно это реализовать? Буду очень признателен за вашу помощь.

1 Ответ

1 голос
/ 30 апреля 2020

Element.offsetNNN относительно его offsetParent, здесь все ваши элементы имеют offsetParent для элемента <body>.

На ваш #js-underline также влияет это заполнение, или, точнее, его родительский элемент.

Так что, когда вы устанавливаете этот элемент слева от других offsetLeft, его собственный offsetLeft все еще там.

Один уродливый обходной путь - это измерение offsetLeft, когда стиль left равен 0;

const navbarElementsList = document.getElementsByClassName('js-element');
const navbarUnderline = document.getElementById('js-underline');
const default_left = navbarUnderline.offsetLeft;
let navbarElement;

for (let i = 0, len = navbarElementsList.length; i < len; i++) {
    navbarElement = navbarElementsList[i];
    navbarElementsList[i].addEventListener('click', function(event){
        let underlineStart = this.offsetLeft;
        let underlineWidth = this.offsetWidth;
        navbarUnderline.style.left = underlineStart - default_left + "px";
        navbarUnderline.style.width = underlineWidth.toString() + "px";
    });
}
ul {
    list-style-type: none;
}
li {
    display: inline;
}
a {
    cursor: pointer;
}
#js-underline {
    position: relative;
    left: 0;
    width: 25px;
    height: 5px;;
    background-color: blue;
    transition: 0.5s ease;
    -moz-transition: 0.5s ease;
    -webkit-transition: 0.5s ease;
}
<!DOCTYPE html>
<html lang="pl">
<head>

  <meta charset="utf-8"/>
  <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>test</title>
  
</head>
<body>

    <ul style=" margin-left: 40px ;">
      <li><a class="c-navbar__element js-element">aaaaaaa</a></li>
      <li><a class="c-navbar__element js-element">bbbb</a></li>
      <li><a class="c-navbar__element js-element">c</a></li>
      <li><a class="c-navbar__element js-element">ddddddddddddddd</a></li>
      <li><div id="js-underline" class="c-navbar__underline"></div></li>
    </ul>

</body>
</html>

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

const navbarElementsList = document.getElementsByClassName('js-element');
const navbarUnderline = document.getElementById('js-underline');

let navbarElement;

for (let i = 0, len = navbarElementsList.length; i < len; i++) {
    navbarElement = navbarElementsList[i];
    navbarElementsList[i].addEventListener('click', function(event){
        let underlineStart = this.offsetLeft;
        let underlineWidth = this.offsetWidth;
        navbarUnderline.style.left = underlineStart + "px";
        navbarUnderline.style.width = underlineWidth + "px";
    });
}
// set to firt item
navbarElementsList[0].click();
ul {
    list-style-type: none;
}
li {
    display: inline;
}
a {
    cursor: pointer;
}
#js-underline {
    position: absolute;
    left: 0;
    width: 25px;
    height: 5px;;
    background-color: blue;
    transition: 0.5s ease;
    -moz-transition: 0.5s ease;
    -webkit-transition: 0.5s ease;
}
<!DOCTYPE html>
<html lang="pl">
<head>

  <meta charset="utf-8"/>
  <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>test</title>
  
</head>
<body>

    <ul style=" margin-left: 40px ;">
      <li><a class="c-navbar__element js-element">aaaaaaa</a></li>
      <li><a class="c-navbar__element js-element">bbbb</a></li>
      <li><a class="c-navbar__element js-element">c</a></li>
      <li><a class="c-navbar__element js-element">ddddddddddddddd</a></li>
      <li>
        <div id="js-underline" class="c-navbar__underline"></div>      
      </li>
    </ul>


</body>
</html>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...