Сделайте так, чтобы боковая панель перестала прокручиваться, когда она достигнет нижнего колонтитула

#javascript #html #jquery #css #scroll

Вопрос:

Я создал липкую боковую панель для своего блога, но теперь мне нужен липкий элемент, чтобы остановить прокрутку, когда я дойду до нижнего колонтитула. Причина в том, что боковая панель перекрывает элементы нижнего колонтитула. Как я могу решить эту проблему?

Рабочая возня с перекрывающейся проблемой:

https://jsfiddle.net/j7x5hLy3/

Это ИМЕННО то, чего я пытаюсь достичь:

https://abouolia.github.io/sticky-sidebar/examples/basic.html

Посмотрите, что происходит, когда боковая панель достигает дна. Я НЕ ПЫТАЮСЬ ИСПОЛЬЗОВАТЬ Z-ИНДЕКС. Я говорю это потому, что в некоторых других вопросах люди публикуют «решения», в которых используется z-индекс. Я не пытаюсь ничего скрыть, я пытаюсь заставить его перестать прокручиваться, когда он достигнет нижнего колонтитула.

 jQuery(document).ready(function($) {
    
  function isScrolledTo(elem) {
    var docViewTop = $(window).scrollTop(); //num of pixels hidden above current screen
    var docViewBottom = docViewTop   $(window).height();
    var elemTop = $(elem).offset().top; //num of pixels above the elem
    var elemBottom = elemTop   $(elem).height();

    return ((elemTop <= docViewTop));
  }

  var catcher = $('#bannernormal');
  var sticky = $('#bannerfixo');

  if ($(window).width() >= 100) {               
    $(window).scroll(function() {
      if (isScrolledTo(sticky)) {
        sticky.css('position', 'fixed');
        sticky.css('top', '0px');
      } 
      var stopHeight = catcher.offset().top   catcher.height();
      if (stopHeight > sticky.offset().top) {
        sticky.css('position', 'absolute');
        sticky.css('top', stopHeight);
      }
    });
        
  } else {
    $(window).unbind('scroll');
  }
}); 
 #bannernormal {
  margin: auto;
  display: table;
  width: 200px;
  height: 400px;
  border: 1px solid #000;
  margin: 5px;
}

#bannerfixo {
  margin: 5px;
  width: 200px;
  height: 400px;
  border: 1px solid #000;
  margin: 5px;
}

#sidebar {
  float: left;
}

#content {
  float: right;
}

#footer {
  display: block;
  clear: both;
} 
 <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>

<div id="content">
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
  Content <br><br><br><br><br><br><br><br>
</div>

<div id="sidebar">
  <div id="bannernormal">
    This is the "catcher" <code>div</code>
  </div>
  <div id="bannerfixo" style="position: absolute; top: 413px;">
    This is the "sticky" <code>div</code>
  </div>
</div>

<div id="footer">Everything should stop before this part.

  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>
  1010101010101011010<br/>

</div> 

Ответ №1:

Чтобы все было просто, вот три вложенных дива. Корневой div представляет корень вашего документа (обычно <body ) Содержимое может быть любым div, если оно имеет position: relative

У div <div id="relativeTop"> должно было быть position: absolute . relativeTop теперь он будет располагаться внутри родительского элемента, но вы можете расположить его явно, используя верхний, правый, нижний и левый. Если родитель не relative является таковым , его дети смогут свободно покинуть его границы и вместо этого расположат своих детей относительно окна.

В javascript я слушаю событие прокрутки

 document.addEventListener('scroll', (e) => {
 

Это означает, что вы можете установить верхнее или нижнее значение.
Посмотри на чек:

 if (window.scrollY   rect.height > parentRect.height) {
 

Если это верно, вы будете знать, что div будет находиться вне родительского объекта, и вы можете настроить top: 0px его так, чтобы он был привязан к основанию своего родителя.

В противном случае верхнее значение устанавливается в положение прокрутки документа:

 el.style.top = window.scrollY   "px";
 
 document.addEventListener('scroll', (e) => {
  const el = document.getElementById("relativeTop");
  const parent = el.parentNode;
  
  const parentRect = parent.getBoundingClientRect();
  const rect = el.getBoundingClientRect();
  
  if (window.scrollY   rect.height > parentRect.height) {
    el.style.bottom = "0px";
  } else {
    el.style.top = window.scrollY   "px";
  }
}); 
 #body {
  border: 1px dotted yellow;
  height: 1500px;
}
#content {
  position: relative;
  border: 1px dotted red;
  height: 1000px;
  margin: 10px;
  width: 2000px;
}
#relativeTop {
  border: 1px dotted blue;
  position: absolute;
  left: 0;
  width: 200px;
  height: 100px;
} 
 <div id="body">
  <div id="content">
    <div id="relativeTop">
    </div>
  </div>
</div> 

Комментарии:

1. Когда я пытаюсь использовать ваш код, консоль выдает ошибку «document.addEventListener». Uncaught TypeError: Cannot read properties of null (reading 'parentNode') at HTMLDocument.<anonymous>

2. У вас есть этот раздел на вашей странице: <div id="relativeTop"> ? document.getElementById("relativeTop"); возвращает null, если он не может найти элемент, поэтому const el имеет значение null и null.parentNode не существует 🙂

3. Я должен задаться вопросом, однако, ответ K_Hs идеален, и вы должны быть в состоянии заставить его работать во многих сценариях, если вы готовы работать с flexbox: display: flex

4. «document.addEventListener(‘прокрутка’, (e) => {» также возвращает синтаксическую ошибку в редакторе.

5. Я использовал «document.addEventListener(‘прокрутка’, функция(e) {» вместо этого, это правильно?

Ответ №2:

 .container {
  display: flex;
  margin-bottom: 10px;
}

.section {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
}

.sidebar {
  width: 180px;
  height: 160px;
  background: green;
  margin-right: 10px;
}

.normal {
  background: yellow;
  margin-bottom: 10px;
}

.sticky {
  background: red;
  position: sticky;
  top: 0;
}

.content {
  width: 100%;
  background: lightgray;
}

.footer {
  background: pink;
  height: 800px;
} 
 <div>
  <div class="container">
    <div>
      <div class="sidebar normal section">
        Normal
      </div>
      <div class="sidebar sticky section">
        Sticky
      </div>
    </div>
    <div class="content">
      Content
      <br/><br/><br/><br/><br/><br/><br/><br/><br/> Content
      <br/><br/><br/><br/><br/><br/><br/><br/><br/> Content
      <br/><br/><br/><br/><br/><br/><br/><br/><br/> Content
      <br/><br/><br/><br/><br/><br/><br/><br/><br/> Content
      <br/><br/><br/><br/><br/><br/><br/><br/><br/> Content
      <br/><br/><br/><br/><br/><br/><br/><br/><br/> Content
      <br/><br/><br/><br/><br/><br/><br/><br/><br/> Content
      <br/><br/><br/><br/><br/><br/><br/><br/><br/> Content
      <br/><br/><br/><br/><br/><br/><br/><br/><br/> Content
    </div>
  </div>
  <div class="footer section">
    Footer
  </div>
</div> 

Комментарии:

1. Хорошее решение, но вы, возможно, захотите добавить некоторые объяснения относительно того, почему эта оценка работает так, как она работает.

2. Это не сработает так, как должно. CSS не в состоянии достичь того, что мне нужно.