Смена хэша при скроллировании

Иногда на одной странице имеется множество разделов, заголовок каждого из которого имеет якорь. Задача состоит в том, чтобы при прокрутке страницы посредством колёсика мышкой или полосы прокрутки в адресной строке изменялся бы хэш, добавляемый к адресу. Здесь описаны 4 способа решить эту задачу. Такой скрипт может работать совместно с оглавлением с плавной прокруткой страницы до якоря по нажатию пункта оглавления (TOC – table of contents).

jQuery:

//uses on instead of bind, so it works with 1.9.1/2.0 +
$(document).on('scroll',function(e)
{
    $('section').each(function()
    {
        if ( $(this).offset().top < window.pageYOffset + 10 
        &&   $(this).offset().top + 
             $(this).height() > window.pageYOffset + 10
           ) 
        {
          var data = $(this).data('id');
          window.location.hash = data;
        }
    });
});

HTML:

<div id="" data-id="">Содержимое div</div>

GitHub

Вариант 2

jQuery:

$(document).ready(function(){
  var sections = {};
  
  $(".section").each(function(){
  	var hash = $(this).data("hash"),
            topOffset = $(this).offset().top;
        sections[topOffset] = hash;
  });
  
  $(window).scroll(function(e){
  	var scrollTop = $(window).scrollTop();
        setHash(scrollTop);
  });
  
  function setHash(st){
  	var hash = "";
  	for(section in sections){
    	if (section < st + ($(window).height()/2)) hash = sections[section];
    }
    console.log(`SETTING HASH: ${hash}`);
    window.location.hash = hash;
  }
});

CSS:

section{
  position: relative;
  display: block;
  width: 100%;
  height: 800px;
  background: #fff;
  border-bottom: 1px solid #000;
}

HTML:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="section" data-hash="about">
  #about
</section>
<section class="section" data-hash="works">
  #works
</section>
<section class="section" data-hash="contact">
  #contact
</section>

Вариант 3

jQuery:

$(document).bind('scroll',function(e){
    $('section').each(function(){
        if (
           $(this).offset().top < window.pageYOffset + 10
//begins before top
        && $(this).offset().top + $(this).height() > window.pageYOffset + 10
//but ends in visible area
//+ 10 allows you to change hash before it hits the top border
        ) {
            window.location.hash = $(this).attr('id');
        }
    });
});

HTML:

<section id="home">
  Home
</section>
<section id="works">
  Works
</section>
<section id="about">
  About
</section>

Вариант 4

Последний, четвёртый вариант корректно работает в браузере IE 11 (а не только в Google Chrome и ему подобных).

jQuery:

(function () {
    //Find all  top,bottom and Hash of each sections
    var section = $.map($("section"), function (e) {
        var $e = $(e);
        var pos = $e.position();
        return {
            top: pos.top - 100,
            bottom: pos.top - 100 + $e.height(),
            hash: $e.attr('id')
        };
    });
     //Checking scroll 
    var top = null;
    var changed = false;
    var currentHash = null;

    $(window).scroll(function () {
        var newTop = $(document).scrollTop();
       
        changed = newTop != top;
        if (changed) {
            top = newTop;
        }

    });
    //set up for Hash while start scroll and the checking only every 300ms to prevent FPS
    function step() {
        if (!changed) {
            return setTimeout(step, 200);
            console.log("End");
        }
        var count = section.length;
        var p;

        while (p = section[--count]) {
            if (p.top >= top || p.bottom <= top) {
                continue;
            }
            if (currentHash == p.hash) {
                break;
            }
            var scrollTop = $(document).scrollTop();
            window.location.hash = currentHash = p.hash;
            // prevent browser to scroll
            $(document).scrollTop(scrollTop);
        }
        setTimeout(step, 200);
    }
    setTimeout(step, 200);
})();

HTML:

<section class="block" id="block-1" data-program="block-1">Block 1</section>
<section class="block" id="block-2" data-program="block-2">Block 2</section>
<section class="block" id="block-3" data-program="block-3">Block 3</section>
<section class="block" id="block-4" data-program="block-4">Block 4</section>

CSS:

.block {
    border: 1px solid #666;
    box-shadow: 2px 2px 2px #333;
    background: #f1f1f1;
    height: 979px;
    padding: 100px;
    font-size: 20px;
    color: #333;
    max-height: 100%;
    text-align: center;
}
.block:nth-child(1) {
    background-color: red;
}
.block:nth-child(2) {
    background-color: green;
}
.block:nth-child(3) {
    background-color: blue;
}
.block:nth-child(4) {
    background-color: yellow;
}