JS/jQuery

Фиксированное горизонтальное меню с активными пунктами

Пример горизонтального меню для лэндингов, в котором реализовано:

  • При прокрутке меню фиксируется.
  • Выделение активного пункта меню по текущему блоку.
  • По клику на меню происходит плавная прокрутка до якоря.
  • Адаптация позиции меню при изменении ширины окна браузера.
1

HTML вёрстка

<div class="wrp">
    <div class="header">Шапка сайта</div>
</div>

<div class="header-menu-wrp">
    <div class="wrp">
        <div class="header-menu">
            <ul>
                <li><a href="#block-1">Блок 1</a></li>
                <li><a href="#block-2">Блок 2</a></li>
                <li><a href="#block-3">Блок 3</a></li>
                <li><a href="#block-4">Блок 4</a></li>
            </ul>
        </div>
    </div>
</div>

<div class="wrp">
    <div id="block-1" class="block">Блок id="block-1"</div>
    <div id="block-2" class="block">Блок id="block-2"</div>
    <div id="block-3" class="block">Блок id="block-3"</div>
    <div id="block-4" class="block">Блок id="block-4"</div>
</div>
2

CSS стили

/* Стили блоков */
.wrp {
    width: 600px;
    margin: 0 auto;
}
.header {
    text-align: center;
    border: 1px dashed #ddd;
    padding: 50px 0;
    margin: 20px 0;
    font-size: 18px;
}
.block {
    text-align: center;
    border: 1px dashed #ddd;
    padding: 100px 0;
    margin-bottom: 20px;
    font-size: 18px;
    background: #eeeeee; 
}

/* Фиксированное меню */
.header-menu-wrp {
    height:40px; 
    line-height:40px; 
    width:100%;
    background: #f48221;
    color: white;
    margin-bottom: 20px;
}
.header-menu-wrp.cloned {
    position: fixed;
    top: 0;
    margin-top: 0;
    z-index: 9999;
    display: none;
}

/* Растягивание меню на всю ширину */
.header-menu {
    width: 100%;
    display: table;
    border-left: 1px solid #ffa44c;
}
    .header-menu ul {
        display: table-row;
    }
    .header-menu li {
        display: table-cell;
        float: none;
        border-right: 1px solid #ffa44c;
    }
    .header-menu li.active {
        background: orange;
    }
    .header-menu li a {
        display: block;
        color: #fff;
        text-align: center;
    }
3

JS/jquery

Для работы потребуется jquery:

<script src="https://code.jquery.com/jquery-2.2.4.js"></script>

Код разнесен на две независимые секции - «Фиксация меню» и «Выделение активных пунктов».

(function() {
    /* Фиксация меню при прокрутке */
    $('.header-menu-wrp')
        .addClass('original')
        .clone()
        .insertAfter('.header-menu-wrp')
        .addClass('cloned')
        .removeClass('original');

    function resizeMenu(){
        var $original = $('.header-menu-wrp.original');
        var $cloned = $('.header-menu-wrp.cloned');
        
        if ($(window).scrollTop() >= ($original.offset().top)){    
            $cloned.css({
                'top': 0, 
                'width': $original.css('width'), 
                'display': 'block',
                'left': $original.offset().left+'px'
            });
            $original.css('visibility', 'hidden');
        } else {
            $cloned.css('display', 'none');
            $original.css('visibility', 'visible');
        }
    }

    $(window).scroll(function(){
        resizeMenu();
    });

    $(window).resize(function(){
        resizeMenu();    
    });

    /* Выделение активных пунктов меню */
    var last_id;
    var $top_menu = $('.header-menu-wrp.cloned');
    var menu_height = $top_menu.outerHeight(true);
    var $menu_items = $top_menu.find('a');
    var $scroll_items = $menu_items.map(function(){
        var item = $($(this).attr('href'));
        if (item.length){
            return item;
        }
    });

    $menu_items.click(function(e){
        var href = $(this).attr('href'),
        offset_top = href === '#' ? 0 : $(href).offset().top - menu_height;
        $('html, body').stop().animate({
            scrollTop: offset_top
        }, 300);
        e.preventDefault();
    });

    $(window).scroll(function(){
        var from_top = $(this).scrollTop() + menu_height;
        var mar = parseInt($top_menu.css('margin-bottom'));
        var cur = $scroll_items.map(function(){
            if ($(this).offset().top < from_top + mar){
                return this;
            }
        });
        cur = cur[cur.length - 1];
        var id = cur && cur.length ? cur[0].id : '';
        if (last_id !== id){
            last_id = id;
            $menu_items.parent()
                .removeClass('active')
                .end()
                .filter("[href='#" + id + "']")
                .parent()
                .addClass('active');
        }
    });
})();
19 декабря 2018