Получение липкого заголовка для "push up", как в приложении iPhone Instagram с использованием CSS и jQuery
приложение Instagram имеет хороший липкий заголовок, который толкает текущий вверх вместо нового. Я нашел отличный учебник о том, как это сделать изначально для Android, но я хочу сделать это с помощью JavaScript и CSS.
я смог заставить свой заголовок переключиться на новый, но я не могу найти способ имитировать то, как это делает Instagram. Любая помощь очень ценится.
*Edit: я смог получить заголовок, чтобы придерживаться верхняя часть страницы при прокрутке с использованием путевых точек, как Cj в комментариях указал. (ссылка на путевые).
Основная проблема, с которой я сталкиваюсь, - это эффект "push up", который instagram использует в своем мобильном приложении для iPhone. Я бы ссылку на пример, но я никогда не видел его раньше.*
* * Edit 2: используя части codepen, что @Chris при условии, что я был в состоянии получить заголовки придерживаться. Затем я добавил А.эффект скольжения. Моя проблема сейчас заключается в получении .эффект скольжения произойдет только при достижении следующего заголовка. Прямо сейчас эффект активируется при прокрутке.
вот код:
(function() {
function stickyTitles(stickies) {
this.load = function() {
stickies.each(function(){
var thisSticky = jQuery(this);
jQuery.data(thisSticky[0], 'pos', thisSticky.offset().top);
});
}
this.scroll = function() {
stickies.each(function(){
var thisSticky = jQuery(this),
pos = jQuery.data(thisSticky[0], 'pos');
if (pos <= jQuery(window).scrollTop()) {
thisSticky.addClass("fixed");
// added this
$(".followMeBar:parent").slideUp();
} else {
thisSticky.removeClass("fixed");
}
});
}
}
jQuery(document).ready(function(){
var newStickies = new stickyTitles(jQuery(".followMeBar"));
newStickies.load();
jQuery(window).on("scroll", function() {
newStickies.scroll();
});
});
})();
7 ответов:
там не быстрый или простой ответ на это, но с немного творческого уговаривания мы можем эмулировать ту же функциональность.
нам нужна серия элементов, которые мы можем идентифицировать, перебирать и затем настраивать так, чтобы при попадании их позиции на странице предыдущий элемент был поднят, а новый элемент стал фиксированным. Нам нужно будет получить начальную позицию элемента с помощью jQuery
offset().topспособ и хранить его вdataтег, чтобы мы могли ссылаться на него позже. Потом остальные будет рассчитываться по мере прокрутки.это должно сделать трюк:
var stickyHeaders = (function() { var $window = $(window), $stickies; var load = function(stickies) { if (typeof stickies === "object" && stickies instanceof jQuery && stickies.length > 0) { $stickies = stickies.each(function() { var $thisSticky = $(this).wrap('<div class="followWrap" />'); $thisSticky .data('originalPosition', $thisSticky.offset().top) .data('originalHeight', $thisSticky.outerHeight()) .parent() .height($thisSticky.outerHeight()); }); $window.off("scroll.stickies").on("scroll.stickies", function() { _whenScrolling(); }); } }; var _whenScrolling = function() { $stickies.each(function(i) { var $thisSticky = $(this), $stickyPosition = $thisSticky.data('originalPosition'); if ($stickyPosition <= $window.scrollTop()) { var $nextSticky = $stickies.eq(i + 1), $nextStickyPosition = $nextSticky.data('originalPosition') - $thisSticky.data('originalHeight'); $thisSticky.addClass("fixed"); if ($nextSticky.length > 0 && $thisSticky.offset().top >= $nextStickyPosition) { $thisSticky.addClass("absolute").css("top", $nextStickyPosition); } } else { var $prevSticky = $stickies.eq(i - 1); $thisSticky.removeClass("fixed"); if ($prevSticky.length > 0 && $window.scrollTop() <= $thisSticky.data('originalPosition') - $thisSticky.data('originalHeight')) { $prevSticky.removeClass("absolute").removeAttr("style"); } } }); }; return { load: load }; })(); $(function() { stickyHeaders.load($(".followMeBar")); });.followMeBar { background: #999; padding: 10px 20px; position: relative; z-index: 1; color: #fff; } .followMeBar.fixed { position: fixed; top: 0; width: 100%; box-sizing: border-box; z-index: 0; } .followMeBar.fixed.absolute { position: absolute; } /* For aesthetics only */ body { margin: 0; font-family: Segoe, "Segoe UI", "DejaVu Sans", "Trebuchet MS", Verdana, sans-serif; }<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="followMeBar">A</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">B</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">C</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">D</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">E</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">F</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">G</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">H</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">I</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">J</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">K</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">L</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">M</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">N</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">O</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">P</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">Q</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">R</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">S</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">T</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">U</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">V</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">W</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">X</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">Y</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <div class="followMeBar">Z</div> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>вот только версия CSS:
прежде чем сказать "что?! Я просто прошел через все это, когда есть только версия CSS?!"Он работает только в нескольких браузерах. попробуйте это в firefox для пример:
.sticky { position: -webkit-sticky; position: -moz-sticky; position: -o-sticky; position: -ms-sticky; position: sticky; top: 0; left: 0; right: 0; display: block; z-index: 1; background: #999; color: #fff; padding: 10px 20px; } /* For aesthetics only */ body { margin: 0; font-family: Segoe, "Segoe UI", "DejaVu Sans", "Trebuchet MS", Verdana, sans-serif; }<div data-lorem="p"> <span class="sticky">a</span> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> </div> <div data-lorem="p"> <span class="sticky">b</span> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> </div> <div data-lorem="p"> <span class="sticky">c</span> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> </div> <div data-lorem="p"> <span class="sticky">d</span> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> </div> <div data-lorem="p"> <span class="sticky">e</span> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> </div> <div data-lorem="p"> <span class="sticky">f</span> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> </div> <div data-lorem="p"> <span class="sticky">g</span> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> </div> <div data-lorem="p"> <span class="sticky">h</span> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> </div>
во-первых, спасибо @Крис плевков за прекрасный ответ.
Я создал модифицированную версию, которая устраняет необходимость обернуть каждый липкий элемент, так как он просто меняет их относительное положение вместо использования фиксированного позиционирования.
var stickyHeaders = (function() { var $stickies; var load = function(stickies, target) { if (typeof stickies === "object" && stickies instanceof jQuery && stickies.length > 0) { $stickies = stickies.each(function() { var $thisSticky = $(this); $thisSticky .data('originalPosition', $thisSticky.offset().top) .data('originalHeight', $thisSticky.outerHeight()); }); target.off("scroll.stickies").on("scroll.stickies", function(event) { _whenScrolling(event); }); } }; var _whenScrolling = function(event) { var $scrollTop = $(event.currentTarget).scrollTop(); $stickies.each(function(i) { var $thisSticky = $(this), $stickyPosition = $thisSticky.data('originalPosition'), $newPosition, $nextSticky; if ($stickyPosition <= $scrollTop) { $newPosition = Math.max(0, $scrollTop - $stickyPosition); $nextSticky = $stickies.eq(i + 1); if($nextSticky.length > 0) { $newPosition = Math.min($newPosition, ($nextSticky.data('originalPosition') - $stickyPosition) - $thisSticky.data('originalHeight')); } } else { $newPosition = 0; } $thisSticky.css('transform', 'translateY(' + $newPosition + 'px)'); //could just as easily use top instead of transform //$thisSticky.css('top', $newPosition + 'px'); }); }; return { load: load }; })(); $(function() { stickyHeaders.load($(".followMeBar"), $(window)); });css упрощается до:
.followMeBar { background: #999; padding: 10px 20px; position: relative; z-index: 1; color: #fff; } /* For aesthetics only */ body { margin: 0; font-family: Segoe, "Segoe UI", "DejaVu Sans", "Trebuchet MS", Verdana, sans-serif; }http://plnkr.co/edit/wk3h40LfBdN1UFtDLZgY?p=preview
и вот еще один пример, показывающий, как вы можете иметь смещение при использовании исправлен заголовок:
Я пробовал решения, представленные выше, но ни один из них не работает отлично без ошибок (в основном ошибка при прокрутке и совместимости с браузером). Только что нашел этот https://github.com/sarahdayan/feedify и это работает хорошо для меня.
У меня были проблемы с получением ответа Криса, чтобы точно работать для меня, поскольку все липучки были внутри относительно расположенного div (с заголовком над всем этим, вне относительного div) - ответ на это просто сохраняет .смещение.)(верхняя часть относительного контейнера div В var и вычитание его из .css ('top',стоимостью) в скрипте. Как и в версии Криса, верхнее значение отталкивается от верхней части документа, который отлично работает. При добавлении в относительный div, вместо этого top теперь нажимает сверху, поэтому любое пространство над относительным div включается в значение, которое вам не нужно. Надеюсь, это поможет кому-то еще. Джеймс
базовая версия решение:
CSS
.sectionWrapper{ background-color: #1E1E1E; padding: 10px 20px; color: #FF7B05; width: 100% height: 45px; min-height: 45px; margin-top: 30px; position: relative; z-index: 10; } .sectionHeader{ } .sectionEmbed { } .sectionFixed { background-color: #1E1E1E; padding: 10px 20px; color: #FF7B05; width: 100%; height: 45px; position: fixed; top: 0; left: 0; margin: 0; }HTML
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 sectionWrapper sectionEmbed"> <div class="sectionHeader">Headers here</div> </div>JQuery
//check doc is ready $(function() { $(window).on("scroll.sectionWrapper", function() { stickSections(); }); }); //function stickSection function stickSections() { //detach the listener $(window).off("scroll.sectionWrapper"); $scrollPos = $(window).scrollTop(); $currentSticky = null; $('.sectionWrapper').each(function(){ $(this).children().removeClass('sectionFixed'); if($scrollPos >= ($(this).offset().top - ($(this).height() - $(this).children().height() - 6)) ){ $currentSticky = $(this); } else $(this).children().addClass('sectionEmbed'); }); //apply the fixed class to our scrollPos match if($currentSticky) $currentSticky.children().addClass('sectionFixed'); //reattach the listener $(window).on("scroll.sectionWrapper", function() { stickSections(); }); }пример
https://codepen.io/ZombiesByte/pen/EyYwVO
удачи :)
это не всегда хорошо работает, если есть содержимое выше div с липкими заголовками:
$thisSticky.css('transform', 'translateY(' + $newPosition+ 'px)');эта строка делает трюк
//could just as easily use top instead of transform $thisSticky.css('top', $newPosition+ 'px');
предоставленное решение @chris-spittles очень помогло мне, но я также хочу предоставить решение для Javascript vanilla. Кроме того, я добавил функциональность, которая обрабатывает последний липкий для ситуаций, когда вы не хотите, чтобы он продолжал исправляться мимо его области содержимого.
https://codepen.io/jamigibbs/pen/QZWjBy
const StickySubsections = (function(){ let el return { elements: function () { return { stickies: [...document.querySelectorAll('.followMeBar')] } }, init: function () { el = this.elements() this.load() }, load: function () { this.setupStickyWrap() window.addEventListener('scroll', () => this.whenScrolling()) }, setupStickyWrap: function(){ el.stickies.forEach((sticky, i) => { const stickyWrap = this.addWrap(sticky, 'sticky-wrap') const heightToTop = sticky.getBoundingClientRect().top + window.scrollY const outerHeight = sticky.offsetHeight stickyWrap.parentElement.id = `sticky-content-${i}` sticky.setAttribute('data-originalPosition', heightToTop) sticky.setAttribute('data-originalHeight', outerHeight) stickyWrap.style.height = outerHeight + 'px' }) }, addWrap: function(el, className, wrap = 'div') { const wrapper = document.createElement(wrap) wrapper.classList.add(className) el.parentNode.insertBefore(wrapper, el) wrapper.appendChild(el) return wrapper }, elementExists: function(el){ return typeof(el) != 'undefined' && el != null }, stickyPosition: function(el){ return el.getAttribute('data-originalPosition') }, nextStickyPosition: function(current, next){ return next.getAttribute('data-originalPosition') - current.getAttribute('data-originalHeight') }, scrollingPositionTop: function(el){ return el.getBoundingClientRect().top + window.scrollY }, offsetTop: function(el){ return el.getBoundingClientRect().top }, scrollingPositionBottom: function(el){ return el.getBoundingClientRect().bottom + window.scrollY }, headerPosition: function(){ return window.scrollY }, bottomSectionHit: function(contentElement, sticky){ const contentSection = document.getElementById(contentElement) const sectionBottom = contentSection.getBoundingClientRect().bottom + window.scrollY const stickyPositionScrolling = sticky.getBoundingClientRect().bottom + window.scrollY return stickyPositionScrolling >= sectionBottom }, whenScrolling: function() { el.stickies.forEach((sticky, i) => { const nextSticky = el.stickies[i + 1] const prevSticky = el.stickies[i - 1] if (this.stickyPosition(sticky) <= this.headerPosition()) { sticky.classList.add('fixed') if (this.elementExists(nextSticky)) { while (this.scrollingPositionBottom(sticky) >= this.nextStickyPosition(sticky, nextSticky) + 50) { sticky.classList.add('absolute') sticky.style.top = this.nextStickyPosition(sticky, nextSticky) } // Handle last sticky element } else { if (this.bottomSectionHit(`sticky-content-${i}`, sticky)) { sticky.classList.remove('fixed') } } } else { sticky.classList.remove('fixed') if (this.elementExists(prevSticky) && window.scrollY <= this.stickyPosition(sticky)){ prevSticky.classList.remove('absolute') prevSticky.removeAttribute('style') } } }) } } }()) StickySubsections.init()
Comments