Получение липкого заголовка для "push up", например, в приложении Instagram iPhone с использованием CSS и jQuery
Приложение Instagram имеет приятный липкий заголовок, который подталкивает текущий вместо нового. Я нашел отличный учебник о том, как это сделать для Android, но я ищу его с помощью JavaScript и CSS.
Мне удалось заставить мой заголовок переключиться на новый, но я не могу найти способ подражать тому, как это делает Instagram. Любая помощь приветствуется.
* Изменить: Я смог получить заголовок, чтобы придерживаться верхней части страницы при прокрутке с использованием путевых точек как Cj в комментариях. (ссылка на путевые точки).
Основная проблема, с которой я сталкиваюсь, - получить эффект "push up", который использует instagram в своем мобильном приложении для iPhone. Я бы связался с примером, но я никогда не видел его раньше. *
* * Редактировать 2: Используя части кода, предоставленные @Chris, я смог получить заголовки. Затем я добавил эффект .slideUp. Моя проблема теперь заключается в том, что эффект .slideUp возникает только при достижении следующего заголовка. В настоящий момент эффект активируется при прокрутке.
Вот код:
(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();
});
});
})();
Ответы
Ответ 1
Там нет быстрого или легкого ответа на этот вопрос, но с небольшим творческим увлечением мы можем эмулировать ту же функциональность.
Нам нужна серия элементов, которые мы можем идентифицировать, зацикливать, а затем настроить так, чтобы, когда мы нажимаем на их позицию на странице, предыдущий элемент подталкивается и новый элемент фиксируется. Нам нужно будет восстановить начальную позицию элемента с помощью метода 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>
Ответ 2
Прежде всего, благодаря @Chris Spittles за отличный ответ.
Я создал измененную версию, которая устраняет необходимость обертывания каждого липкого элемента, поскольку он просто меняет свое относительное положение вместо использования фиксированного позиционирования.
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));
});
Сss упрощается:
.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
И вот еще один пример, показывающий, как вы можете иметь смещение при использовании фиксированного заголовка:
http://plnkr.co/edit/8YBqdCIKruVKYRXbZnCp?p=preview
Ответ 3
Я пробовал решения, описанные выше, но ни один из них не работает отлично без ошибок (в основном ошибка при прокрутке и совместимость с браузером).
Просто нашел этот https://github.com/sarahdayan/feedify, и он работает хорошо для меня.
Ответ 4
У меня возникли проблемы с получением ответа Криса на то, чтобы работать для меня точно, потому что все листы находились внутри относительно позиционированного div (с заголовком выше всего, вне относительного div) - ответ на этот вопрос просто сохраняется. offset(). Верхняя часть относительного контейнера div в var и вычитание из значения .css('top', ) в script.
Как и в версии chris, верхнее значение отталкивает верхнюю часть документа, который отлично работает.
Когда вы добавляете в относительный div, вершина теперь отталкивается от вершины этого, поэтому любое пространство над относительным div включено в значение, которое вам не нужно.
Надеюсь, это помогает кому-то другому.
Джеймс
Ответ 5
Базовая версия решения:
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
Удачи:)
Ответ 6
Это не всегда хорошо работает, если над div есть содержимое с липкими заголовками:
$thisSticky.css('transform', 'translateY(' + $newPosition+ 'px)');
Но эта линия делает трюк
//could just as easily use top instead of transform
$thisSticky.css('top', $newPosition+ 'px');
Ответ 7
Существует библиотека jQuery fixed-sticky.