Ответ 1
Если кто-то попадет сюда через Google, один из его собственных инженеров найдет решение с использованием IntersectionObserver, пользовательских событий и часовых:
https://developers.google.com/web/updates/2017/09/sticky-headers
Я использую новый position: sticky
(info), чтобы создать список контента, подобный iOS.
Он работает хорошо и намного превосходит предыдущий вариант JavaScript (пример), однако, насколько я знаю, ни одно событие не запускается, когда оно срабатывает, что означает, что я могу" t делать что-либо, когда панель попадает в верхнюю часть страницы, в отличие от предыдущего решения.
Я хотел бы добавить класс (например, stuck
), когда элемент с position: sticky
попадает в верхнюю часть страницы. Есть ли способ слушать это с помощью JavaScript? Использование jQuery в порядке.
Ниже приведена демонстрация нового position: sticky
здесь.
Если кто-то попадет сюда через Google, один из его собственных инженеров найдет решение с использованием IntersectionObserver, пользовательских событий и часовых:
https://developers.google.com/web/updates/2017/09/sticky-headers
В настоящее время нет собственного решения. См. Позиция таргетинга: липкие элементы, которые в настоящее время находятся в состоянии "застряли" . Однако у меня есть решение CoffeeScript, которое работает как с родным position: sticky
, так и с полиполками, которые реализуют липкое поведение.
Добавьте "липкий" класс к элементам, которые вы хотите быть липкими:
.sticky {
position: -webkit-sticky;
position: -moz-sticky;
position: -ms-sticky;
position: -o-sticky;
position: sticky;
top: 0px;
z-index: 1;
}
CoffeeScript для контроля "липких" позиций элементов и добавления "застрявшего" класса, когда они находятся в "липком" состоянии:
$ -> new StickyMonitor
class StickyMonitor
SCROLL_ACTION_DELAY: 50
constructor: ->
$(window).scroll @scroll_handler if $('.sticky').length > 0
scroll_handler: =>
@scroll_timer ||= setTimeout(@scroll_handler_throttled, @SCROLL_ACTION_DELAY)
scroll_handler_throttled: =>
@scroll_timer = null
@toggle_stuck_state_for_sticky_elements()
toggle_stuck_state_for_sticky_elements: =>
$('.sticky').each ->
$(this).toggleClass('stuck', this.getBoundingClientRect().top - parseInt($(this).css('top')) <= 1)
ПРИМЕЧАНИЕ. Этот код работает только для вертикального липкого положения.
// get the sticky element
const stickyElm = document.querySelector('header')
const observer = new IntersectionObserver(
([e]) => e.target.classList.toggle('isSticky', e.intersectionRatio < 1),
{threshold: [1]}
);
observer.observe(stickyElm)
body{ height: 200vh; font:20px Arial; }
section{
background: lightblue;
padding: 2em 1em;
}
header{
position: sticky;
top: -1px; /* <- the trick */
padding: 1em;
padding-top: calc(1em + 1px); /* <- compensate for the trick */
background: salmon;
transition: .1s;
}
/* styles for when the header is in sticky mode */
header.isSticky{
font-size: .8em;
opacity: .5;
}
<section>Space</section>
<header>Sticky Header</header>
После добавления Chrome position: sticky
было обнаружено, что недостаточно готов и отнесено на флаг --enable-experimental-webkit-features. Paul Irish сказал в феврале "функция находится в странном состоянии limbo atm".
Я использовал polyfill, пока не стал слишком много головной боли. Он работает красиво, но когда есть, но есть угловые случаи, такие как проблемы CORS, и это замедляет загрузку страниц, делая запросы XHR для всех ваших ссылок CSS и переписывая их для объявления "position: sticky", которое браузер игнорировал.
Теперь я использую ScrollToFixed, который мне нравится лучше StickyJS, потому что это не испортит мой макет с помощью обертки.
Я придумал это решение, которое работает как шарм и довольно мало. :)
Никаких дополнительных элементов не требуется.
Он запускается при событии прокрутки окна, что является небольшим недостатком.
var _$stickies = [].slice.call(document.querySelectorAll('.sticky'));
_$stickies.forEach(function(_$sticky){
if (CSS.supports && CSS.supports('position', 'sticky')) {
apply_sticky_class(_$sticky);
window.addEventListener('scroll', function(){
apply_sticky_class(_$sticky);
})
}
})
function apply_sticky_class(_$sticky){
var currentOffset = _$sticky.getBoundingClientRect().top;
var stickyOffset = parseInt( getComputedStyle(_$sticky).top.replace('px','') );
var isStuck = currentOffset <= stickyOffset;
_$sticky.classList.toggle('js-is-sticky', isStuck);
}
Примечание. Это решение не учитывает элементы, которые имеют нижнюю липкость. Это работает только для таких вещей, как липкий заголовок. Вероятно, он может быть адаптирован для учета нижней липкости.
Я знаю, что прошло некоторое время с тех пор, как был задан вопрос, но я нашел хорошее решение для этого. Плагин stickybits использует position: sticky
, где поддерживается, и применяет класс к элементу, когда он "застревает". Я использовал его недавно с хорошими результатами, и, в момент написания, это активное развитие (что для меня плюс):)