Если вы читали статью « Очевидный дизайн всегда побеждает » Аннариты Транфики, вы можете согласиться с ее утверждением:
Люди ожидают увидеть общие шаблоны: найти главное меню в верхней части страницы, поле поиска в верхнем правом углу, нижний колонтитул внизу и т. Д.
Я согласен, что люди ожидают, что определенные компоненты сайта будут размещены в определенном месте, и, на мой взгляд, это еще более верно, когда речь идет о главном меню.
Иногда из-за запроса клиента или из-за того, что мы определили, что это лучший подход, мы можем потребовать, чтобы основная навигация оставалась видимой на странице постоянно, без фиксации на месте, по существу следуя содержимому страницы. В последние годы многие решения, основанные на JavaScript, увидели свет, потому что только CSS не смог решить эту задачу.
В этой статье мы обсудим position: sticky
, новое решение CSS для этой проблемы.
Какую проблему мы решаем?
Прежде чем обсуждать это новое значение для свойства position
, давайте лучше поймем, какую проблему мы пытаемся решить.
Давайте представим, что главное меню нашего удивительного веб-сайта находится сразу после заголовка, но все еще в верхней части страницы (не на боковой панели) и что оно занимает всю доступную ширину. Это может выглядеть так:
Мы хотим добиться того, чтобы, когда пользователь прокручивал страницу, как только меню располагалось в верхней части окна просмотра, вместо того, чтобы прокручивать меню вне поля зрения, оно оставалось в верхней позиции, как если бы оно имело position: fixed
применяется к нему (только когда он достигает вершины области просмотра).
Чтобы достичь этого с помощью традиционного кода, нам нужно добавить немного JavaScript. Мы прослушиваем событие прокрутки страницы и используем JavaScript, чтобы изменить значение position
и свойства top
соответствии с текущей позицией области просмотра. В частности, нам нужно добавить top: 0
и position: fixed
в меню, когда оно находится в верхней части окна просмотра, а затем вернуть свойства обратно к их значениям по умолчанию.
Альтернативный, но похожий подход состоит в том, чтобы создать класс в нашем CSS, где присутствуют эти значения, а затем добавить и удалить класс по мере необходимости с помощью JavaScript, который может выглядеть следующим образом:
var menu = document.querySelector('.menu') var menuPosition = menu.getBoundingClientRect().top; window.addEventListener('scroll', function() { if (window.pageYOffset >= menuPosition) { menu.style.position = 'fixed'; menu.style.top = '0px'; } else { menu.style.position = 'static'; menu.style.top = ''; } });
Обратите внимание, что этот фрагмент не относится к более старым версиям Internet Explorer. Если вам нужно разобраться с этими браузерами (бедняжка!), Я предоставлю несколько вариантов полизаполнения, которые вы можете рассмотреть.
Демонстрация этого второго шага показана ниже:
Но ждать! Можете ли вы определить проблему, вызванную этим кодом? Многие реализации, которые я видел, включая ту, которую мы разработали до сих пор, не учитывают важную проблему. Когда мы меняем положение элемента на fixed
, он покидает поток страницы, поэтому элементы под ним «подпрыгивают» на количество пикселей, примерно равное высоте элемента (высота этого «прыжка» зависит на полях, границах и тд).
Возможное решение состоит в том, чтобы внедрить элемент-заполнитель того же размера, что и тот, который мы хотим «прикрепить», чтобы при обновлении стиля закрепленного элемента не было прыжка. Кроме того, мы не хотим переназначать значения снова и снова без причины, если правильные значения уже установлены. Наконец, мы хотим использовать описанную мной технику с использованием класса CSS.
Окончательная версия кода JavaScript приведена ниже:
var menu = document.querySelector('.menu'); var menuPosition = menu.getBoundingClientRect(); var placeholder = document.createElement('div'); placeholder.style.width = menuPosition.width + 'px'; placeholder.style.height = menuPosition.height + 'px'; var isAdded = false; window.addEventListener('scroll', function() { if (window.pageYOffset >= menuPosition.top && !isAdded) { menu.classList.add('sticky'); menu.parentNode.insertBefore(placeholder, menu); isAdded = true; } else if (window.pageYOffset < menuPosition.top && isAdded) { menu.classList.remove('sticky'); menu.parentNode.removeChild(placeholder); isAdded = false; } });
И это блок объявления для sticky
класса:
.sticky { top: 0; position: fixed; }
Окончательный результат показан в следующей демонстрации:
Теперь, когда вы хорошо понимаете, в чем заключается проблема и каково возможное решение на основе JavaScript, пришло время принять современность и обсудить, в чем заключается эта position: sticky
— это все.
Какое position: sticky
?
Если вы были настолько смелы, чтобы внимательно следовать предыдущему разделу, вы можете спросить: «Почему браузеры не могут сделать это для меня?» Рад, что вы спросили!
sticky
— это новое значение, введенное для свойства CSS position
. Предполагается, что это значение будет вести себя как position: static
внутри своего родителя, пока не будет достигнут заданный порог смещения, и в этом случае оно действует так, как если бы значение было fixed
. Другими словами, используя position: sticky
мы можем решить проблему, обсужденную в предыдущем разделе, без JavaScript.
Вспоминая наш предыдущий пример и используя это новое значение, мы можем написать:
.menu { margin: 0; padding: 0; width: 100%; background-color: #bffff3; position: sticky; }
И браузер сделает все остальное! Это так просто.
Поддержка браузера и Polyfills
Поддержка этого нового значения в настоящее время довольно скудна. Вот как все складывается для каждого браузера:
- Firefox 26+ — поддерживается установкой
css.sticky.enabled
в значение «true» вabout:config
. - Chrome 23+ — поддерживается включением «экспериментальных функций веб-платформы» в
chrome://flags
. - Chrome 38 (?) — команда Chrome недавно удалила эту функцию из Blink , поэтому в настоящее время она недоступна в Chrome Canary (версия 38.x), даже с флагом. Вы можете прочитать отчет об ошибке, объясняющий удаление, но мы подозреваем, что эта функция будет вскоре реализована и, возможно, без сбоев в поддержке стабильной версии.
- Safari 6.1+ — поддерживается с использованием префикса
-webkit
vendor для значения (тposition: -webkit-sticky
) - Opera 23+ — поддерживается включением «экспериментальных функций веб-платформы» в
about:flags
. - Internet Explorer — не поддерживается ( см. Статус )
Смотрите положение: наклейка «Могу ли я использовать …» для всех деталей.
К счастью, есть несколько вариантов заполнения:
- Фиксированная группа Filament Group (требуется jQuery)
- позиция-липучка Мэтью Филлипса (использует Modernizr для обнаружения)
- позиция: липкая , часть библиотеки Филиппа Уолтона Polyfill.js
- позиция: липкая демонстрация CodePen от Фабриса Вайнберга (требуется jQuery)
- Stickyfill от Олега Корсунского (IE9 +)
демонстрация
Следующая демонстрация показывает position: sticky
в действии. Как уже упоминалось, чтобы увидеть, как это работает, и в зависимости от браузера, который вы используете, вам нужно активировать флаг.
Вывод
Хотя новая функция не имеет большой поддержки браузера, и вы, возможно, не решитесь ее заполнить, она будет постепенно снижаться до position: static
по умолчанию position: static
или position: fixed
, если вы определяете альтернативный стиль с помощью Modernizr.
Если вы экспериментировали с этим свойством или знаете о других полифиллах, сообщите нам об этом в комментариях.