CSS 및 jQuery를 사용하는 Instagram의 iPhone 앱에서와 같이 "푸시 업"하는 고정 헤더 가져 오기
Instagram 앱에는 새 헤더 대신 현재 헤더를 밀어주는 멋진 고정 헤더가 있습니다. Android 용으로 기본적으로이 작업을 수행하는 방법에 대한 훌륭한 자습서를 찾았지만 JavaScript 및 CSS로 수행하려고합니다.
머리글을 새 머리글로 바꿀 수 있었지만 Instagram이하는 방식을 모방하는 방법을 찾을 수없는 것 같습니다. 어떤 도움이라도 대단히 감사합니다.
* 편집 : 지적 된 주석에서 Cj로 웨이 포인트를 사용하여 스크롤 할 때 헤더가 페이지 상단에 고정되도록 할 수있었습니다. ( 경유지 링크 ). 내가 겪고있는 주요 문제는 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();
});
});
}) ();
이에 대한 빠르고 쉬운 대답은 없지만 약간의 창의적인 결합으로 동일한 기능을 에뮬레이션 할 수 있습니다.
필요한 것은 일련의 요소를 식별하고 반복 한 다음 설정하여 페이지에서 해당 위치에 도달하면 이전 항목이 밀리고 새 항목이 고정되도록 설정할 수 있습니다. 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 전용 버전이있을 때이 모든 과정을 살펴 봤어요?!" 몇 개의 브라우저에서만 작동합니다. 예를 들어 파이어 폭스에서 이것을 시도하십시오.
.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>
http://caniuse.com/#feat=css-sticky
우선, 그의 훌륭한 답변에 대해 @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));
});
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
다음은 고정 헤더를 사용할 때 오프셋을 가질 수있는 방법을 보여주는 또 다른 예입니다.
http://plnkr.co/edit/8YBqdCIKruVKYRXbZnCp?p=preview
위에 제공된 솔루션을 시도했지만 버그없이 완벽하게 작동하는 솔루션은 없습니다 (대부분 스크롤 및 브라우저 호환성에 대한 버그). 방금 https://github.com/sarahdayan/feedify를 찾았 으며 나에게 잘 작동합니다.
나는 모든 스티커가 상대적으로 배치 된 div (상대 div 외부에 헤더가 있음) 내부에 있었기 때문에 Chris의 대답이 나를 위해 정확하게 작동하는 데 어려움을 겪었습니다. 이에 대한 대답은 .offset () var에있는 상대 컨테이너 div의 .top 및 스크립트 의 .css ( 'top', value )에서 이를 뺍니다 . chris의 버전에서와 같이 최상위 값은 잘 작동하는 문서의 상단을 밀어내는 것입니다. 상대 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 솔루션도 제공하고 싶습니다. 또한 콘텐츠 영역을 지나서 계속 수정하지 않으려는 상황에 대해 마지막 고정을 처리하는 기능을 추가했습니다.
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()
'program story' 카테고리의 다른 글
| “volatile int * p”와 같은 point-to-volatile 포인터가 유용한 이유는 무엇입니까? (0) | 2020.11.01 |
|---|---|
| Eclipse에서 마지막 커서 위치로 이동하는 방법은 무엇입니까? (0) | 2020.11.01 |
| int.TryParse가 실제로 작동하는 방식 (0) | 2020.11.01 |
| 형제 노드에 특정 값이있는 경우 XPath를 사용하여 노드를 선택하는 방법은 무엇입니까? (0) | 2020.11.01 |
| gradle-wrapper를 사용할 때 다운로드하지 않고 로컬 시스템에서 gradle zip을 사용하는 방법 (0) | 2020.11.01 |