Q:

Как выполнить "липкий сайдбар" с остановкой скролла на определенном элементе и возвращением скролла при пролистывании данного элемента?

Имеется следующий код:

body {
  color: #fff;
}

header, footer {
  background-color: green;
  padding: 50px 25px 50px;
}

.content-1, .content-2 {
  background-color: lightblue;
  padding: 50px 20px 50px;
  height: 800px;
  margin-top: 30px;
  margin-bottom: 30px;
}

#sidebar {
  background-color: lightblue;
  padding: 50px 25px 50px;
  height: 200px;
  margin-top: 30px;
  margin-bottom: 30px;
}

#large-content-block {
  background-color: red;
  padding: 50px 25px 50px;
  height: 200px;
  margin-bottom: 30px;
}
  <header>Header</header>
  <main>
    <div class="container">
      <div class="row justify-content-around">
        <div class="col-12 col-sm-8 col-md-6 col-lg-5 content-1">Content 1</div>
    <div class="col-12 col-sm-8 col-md-6 col-lg-5" id="sidebar">Sidebar</div>
        <div class="col-12" id="large-content-block">Large content</div>
        <div class="col-12 col-sm-8 col-md-6 col-lg-5 content-2">Content 2</div>
        <div class="col-lg-5"></div>
      </div>
    </div>
   </main>
  <footer>Footer</footer>
 

Необходимо выполнить следующее:

Сделать #sidebar липким, при этом скролл данного элемента должен останавливаться при достижении #large-content-block.
После того, как мы проскроллим элемент #large-content-block, #sidebar снова должен скроллиться. Скролл должен останавливаться при достижении футера.

Каким путем можно реализовать данный функционал?
Codepen: https://codepen.io/anon/pen/byqQyp

A:

Определяем блок, рядом с которым надо залипнуть
Определяем отступ sidebar и через position: relative и top корректируем, чтобы sidebar залип
Также кладем sidebar рядом с content у которого необходимо залипнуть

https://codepen.io/anon/pen/yWMdXJ
var stickyTargets = $('.content-1, .content-2'),
    sidebar = $('#sidebar'),
    sidebarPaddingTop = 30;

// вдруг загрузились внизу страницы - надо сразу спозиционироваться
positionSidebar();

$(window).scroll(function(){
  // ну и на скролл
  positionSidebar();
});

function positionSidebar() {
  var target = getStickyTarget(), // найдем блок рядом с которым надо залипнуть
      offset = getSidebarTargetOffset(sidebar, target); // вычислим отступ сверху

  if (target) {
    // если есть блок рядом с которым надо залипнуть - положим рядом с ним sidebar
    sidebar.insertAfter(target);
  }

  sidebar.css('top', offset+'px');
}

function getStickyTarget() {
  var windowOffsetTop = $(window).scrollTop();
  for(i=0; i<stickyTargets.length; i++) {
    var target = $(stickyTargets[i]);
    var offsetTop = target.offset().top,
        offsetBottom = offsetTop + target.outerHeight();
    if ((windowOffsetTop > offsetTop) && (windowOffsetTop < offsetBottom)) {
      return target;
    }
  }
}

function getSidebarTargetOffset(sidebar, target) {
  if (!target || !target.length) {
    return 0;
  }

  var offset = $(window).scrollTop() - target.offset().top + sidebarPaddingTop;

  if (offset < 0) {
    return 0;
  }

  // чтобы sidebar не опускался ниже content вычислим разницу, чтобы sidebar перестал скроллиться
  var sidebarCouldOffsetBottom = $(window).scrollTop() + sidebar.height() + sidebarPaddingTop,
      targetOffsetBottom = target.offset().top + target.height(),
      bottomDiff = sidebarCouldOffsetBottom - targetOffsetBottom;
  if (bottomDiff > 0) {
    offset -= bottomDiff;
  }

  return offset;
}

