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

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

При создании сайта часто возникает необходимость держать в поле зрения горизонтальное меню, в котором расположена основная навигация сайта. Метод «фиксации» горизонтального меню является удобным с точки зрения посетителя, у которого «навигация всегда под рукой», сколько не крути колёсиком вниз или вверх.

Фиксируем горизонтальное меню с CSS: position:fixed

С одной стороны всё просто и легко решается средствами css в два счёта. Пример HTML вёрстки фиксированного горизонтального меню:

<body>
<div id="menu-top-almost-fixed" class="menu-top-almost-fixed">
<ul>
    <li><a href="#">Главная</a></li>
    <li><a href="#">Новости</a></li>
    <li><a href="#">Контакты</a></li>
    <li class="last"><a href="#">Поиск</a></li>
</ul>
</div>
<div id="content">
[содержимое страницы]
</div>
<div id="footer">
[подвал сайта]
</div>
</body>

CSS вёрстка фиксированного горизонтального меню:

<style type="text/css">
# menu-top-almost-fixed{
position: fixed;
top: 10px;
left: 0;
height: 30px;
width: 100%;
margin: 0;
}
</style>

А теперь зададим отступ для содержимого страницы, равный высоте меню:

   CSS:

<style type="text/css">
#content {
margin-top: 30px;
}
</style>

И вот у нас «почти» всё получилось. Меню у посетителя «всегда на виду». Но что же делать, если у нас в дизайне расположена шапка сайта, после которой следует само меню, а в шапке у нас логотип, девиз сайта, баннеры.

Ну что ж, мы можем зафиксировать и шапку сайта, сделав отступ содержимого равным по высоте шапки и меню, вместе с отступами между ними. Но возникает проблема. Мы значительно ограничиваем пространство просмотра содержимого страницы для наших посетителей. Вариант отказаться от шапки вообще нас не устраивает.

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

Итак, рассмотрим вариант, когда меню «идёт» за шапкой сайта, но если посетитель активно прокручивает вниз, меню «фиксируется» вверху и остаётся на месте. Шапка сайта при этом не видна. Если же посетитель возвращается к шапке страницы, меню «становится» на своё место «за шапкой сайта». Для начала привёдем полную HTML вёрстку примера макета страницы:

HTML:

<body id="bd">
<div id="header">
    <h2>Логотип сайта</h2>
    <h3>Слоган сайта</h3>
    <div id="banner">Баннер</div>
</div>
<div id="menu-top-almost-fixed" class="menu-top-almost-fixed">
<ul>
    <li><a href="#">Главная</a></li>
    <li><a href="#">Новости</a></li>
    <li><a href="#">Контакты</a></li>
    <li class="last"><a href="#">Поиск</a></li>
</ul>
</div>
<div class="content">
     [содержимое страницы]
</div>
<div id="footer">
[подвал сайта]
</div>
</body>

Шаблон нашего сайта состоит из нескольких типичных областей:

  • шапки сайта — #header, высотой 150px
  • горизонтального меню — #menu-top-almost-fixed – высотой 30px,
  • основной информационной области страницы — #content,
  • подвала сайта — #footer.

Приведём css вёрстку:

   CSS:

    #menu-top-almost-fixed{
        position: fixed;
        margin: 0;
        left: 0;
        top: 150px;
        height: 30px;
    }
    #header{
        display: block;
        height: 150px;
        overflow: hidden;
        position: relative;
        margin-bottom: 55px;
    }
    #menu-top-almost-fixed ul,
    #menu-top-almost-fixed li{
         list-style: none;
         margin: 0;
         padding: 0;
     }
    #menu-top-almost-fixed ul{
         display: block;
         text-align: center;
         width: 100%;
         float: left;
     }
    #menu-top-almost-fixed ul li{
         display: inline;
         line-height: 30px;
         width: 120px;
         padding: 0 5px;
         text-align: center;
}

Для начала зададим отступ от шапки до содержимого, равный высоте нашего меню + небольшой отступ с запасом для эстетической красоты. #header { margin-bottom: 55px; } . Зафиксируем наше меню сразу за шапкой: #menu-top-almost-fixed{ position: fixed; margin: 0; left: 0; top: 150px; height: 30px; } .

А теперь позаботимся о том, чтобы при прокрутке меню «фиксировалось» точно вверху страницы. Поместим следующий javascript между <head> и </head>:

   Javascript:

<script type="text/javascript">
var m1 = 150; /* высота шапки в пикселях */
var m2 = 2; /* отступ, когда во время прокрутки шапка
 уже не видна */
var menuID = "menu-top-almost-fixed";
/* id горизонтального меню для закрепления */
var menuOpacityOnChange = "0.7";
/* прозрачность меню при
скроллинге:
1 — непрозрачное,
0.5 — полупрозрачное
0.0 — полностью прозрачное*/
var menuOpacityOnChangeIE = menuOpacityOnChange * 100;
/* функция кроссбраузерного определения
отступа от верха документа к текущей позиции
скроллера прокрутки */
function getScrollTop() {
           var scrOfY = 0;
           if( typeof( window.pageYOffset ) == "number" ) {
                   //Netscape compliant
                   scrOfY = window.pageYOffset;
           } else if( document.body
           && ( document.body.scrollLeft
           || document.body.scrollTop ) ) {
                   //DOM compliant
                   scrOfY = document.body.scrollTop;
           } else if( document.documentElement
           && ( document.documentElement.scrollLeft
            || document.documentElement.scrollTop ) ) {
                   //IE6 Strict
                   scrOfY = document.documentElement.scrollTop;
           }
           return scrOfY;
}
/* функция, которая устанавливает верхний отступ
 для «плавающего» фиксированного горизонтального
меню в зависимости от положения
 скроллера и видимости шапки */
function marginMenuTop() {
            var top  = getScrollTop();
            var s    = document.getElementById(menuID);
            if(typeof s != "undefined" && s){
              if (top+m2 < m1) {
                  s.style.top       = (m1-top) + "px";
                  s.style.filter    = s.style.filter.replace("progid:DXImageTransform.Microsoft.Alpha(opacity="+menuOpacityOnChangeIE+")","");
                  s.style.opacity   = "1";
              } else {
                  s.style.top       = m2 + "px";
                  s.style.opacity   = menuOpacityOnChange;
                  s.style.filter    = s.style.filter.replace("progid:DXImageTransform.Microsoft.Alpha(opacity="+menuOpacityOnChangeIE+")","");
                  s.style.filter    += "progid:DXImageTransform.Microsoft.Alpha(opacity="+menuOpacityOnChangeIE+")";
              }
            }
}
/** функция регистрирует
вычисление позиции
 «плавающего» меню при прокрутке страницы
**/
function setMenuPosition(){
if(typeof window.addEventListener != "undefined"){
    window.addEventListener("scroll", marginMenuTop, false);
} else if(typeof window.attachEvent != "undefined"){
    window. attachEvent("onscroll", marginMenuTop);
}
    marginMenuTop();
}
/** регистрируем вызов
необходимых функций после
 загрузки страницы **/
if(typeof window.addEventListener != "undefined"){
    window.addEventListener("load", setMenuPosition, false);
} else if(typeof window.attachEvent != "undefined"){
    window. attachEvent("onload", setMenuPosition);
}
</script>

Примечание автора: разбор данного javascript а мы выполняли в одной из предыдущих статей «Как зафиксировать вертикальное меню», но всё итак можно понять по условным комментариям.

А пример реализации Вы можете посмотреть по этой ссылке, и воспользовавшись колёсиком прокрутки. Итак, здесь всё просто. В настройках мы передаём скрипту следующие параметры:

  • var m1 = 150; — высота шапки в пикселях,
  • var m2 = 2; — отступ, когда во время прокрутки шапка уже не видна,
  • var menuID = «menu-top-almost-fixed»; — id горизонтального меню для закрепления,
  • var menuOpacityOnChange = «0.7»; — прозрачность меню при скроллинге:
    • 1 — непрозрачное
    • 0.5 – полупрозрачное
    • 0.0 — полностью прозрачное

В этом варианте мы немножко «тюнинговали» наше меню, и при прокрутке мы добавляем ему полупрозрачности. Сразу напрашивается более классический вариант, когда мы не меняем прозрачность меню, а просто делаем для меню подложку в виде фона с цветом меню и нижней полупрозрачной границей (в которой градиент плавно «переходит» от непрозрачного цвета к прозрачному):

Изменяем немного CSS вёрстку для нашего горизонтального фиксированного меню:

   CSS:

#menu-top-almost-fixed{
        position: fixed;
        margin: 0;
        left: 0;
        top: 150px;
        height: 30px;
        background: url(./images/white-gradient-l.png) bottom left repeat-x;
 }

А теперь приведём изменённый javascript код, который поместим между <head> и </head>:

   Javascript:

<script type="text/javascript">
var m1 = 150; /* высота шапки в пикселях */
var m2 = 0; /* отступ, когда во время прокрутки шапка
 уже не видна */
var menuID = "menu-top-almost-fixed";
/* функция кроссбраузерного определения
отступа от верха документа к текущей позиции
скроллера прокрутки */
function getScrollTop() {
           var scrOfY = 0;
           if( typeof( window.pageYOffset ) == "number" ) {
                   //Netscape compliant
                   scrOfY = window.pageYOffset;
           } else if( document.body
           && ( document.body.scrollLeft
           || document.body.scrollTop ) ) {
                   //DOM compliant
                   scrOfY = document.body.scrollTop;
           } else if( document.documentElement
           && ( document.documentElement.scrollLeft
            || document.documentElement.scrollTop ) ) {
                   //IE6 Strict
                   scrOfY = document.documentElement.scrollTop;
           }
           return scrOfY;
}
/* функция, которая устанавливает верхний отступ
 для «плавающего» фиксированного горизонтального
меню в зависимости от положения
 скроллера и видимости шапки */
function marginMenuTop() {
            var top  = getScrollTop();
            var s    = document.getElementById(menuID);
            if(typeof s != "undefined" && s){
              if (top+m2 < m1) {
                  s.style.top       = (m1-top) + "px";
              } else {
                  s.style.top       = m2 + "px";
              }
            }
}
/** функция регистрирует
вычисление позиции
 «плавающего» меню при прокрутке страницы
**/
function setMenuPosition(){
if(typeof window.addEventListener != "undefined"){
    window.addEventListener("scroll", marginMenuTop, false);
} else if(typeof window.attachEvent != "undefined"){
    window. attachEvent("onscroll", marginMenuTop);
}
}
/** регистрируем вызов
необходимых функций после
 загрузки страницы **/
if(typeof window.addEventListener != "undefined"){
    window.addEventListener("load", setMenuPosition, false);
} else if(typeof window.attachEvent != "undefined"){
    window. attachEvent("onload", setMenuPosition);
}
</script>

Итак, здесь всё просто. В настройках мы передаём скрипту следующие параметры:

  • var m1 = 150; — высота шапки в пикселях,
  • var m2 = 0; — отступ, когда во время прокрутки шапка уже не видна.

Меню работает отлично, но, если перезагрузить страницу, меню появляется с первым отступом

При наличии такой проблемы необходимо вызвать меню после загрузки страницы единоразово. Для этого изменим код вызова функции с:

function setMenuPosition(){
if(typeof window.addEventListener != "undefined"){
    window.addEventListener("scroll", marginMenuTop, false);
} else if(typeof window.attachEvent != "undefined"){
    window. attachEvent("onscroll", marginMenuTop);
}
};

На следующий код:

function setMenuPosition(){
if(typeof window.addEventListener != "undefined"){
    window.addEventListener("scroll", marginMenuTop, false);
} else if(typeof window.attachEvent != "undefined"){
    window. attachEvent("onscroll", marginMenuTop);
}
    marginMenuTop();
};

После загрузки страницы мы сразу вызываем нашу функцию marginMenuTop, которая проверит положение меню на странице, и применит нужный стиль

Реализуем частично фиксированное меню при помощи jQuery плагина Afixx из Twitter Bootstrap

В продолжение этой темы для Вас была написана статья реализации почти фиксированного меню при помощи jQuery плагина Affix из Twitter Bootstrap framework.

Комментарии