粘性 Header - 使用标签滚动
Sticky Header - Scroll with Tabs
我的粘性 header.
的行为有问题
Desired behavior:
a) Scrolling to where the bottom of the .nav
hits the top of a section
adds
the active
class to the tab and it remains active
until the .nav
reaches the top of the next section.
b) Clicking a corresponding
section's .tab
always navigates you to the top of that section and adds the active
class to the tab.
因此,无论是滚动还是单击,选项卡的 active
状态始终保持,直到 .nav
进入下一个 section
,在这种情况下 active
状态转到该部分的选项卡等。
测试问题:
1) Half-way 向下滚动 Option Two
.tab
的 active
状态丢失。
2) scrollTop
的使用是滚动到.container
的顶部,而不是选择的section
.
的顶部
class StickyNavigation {
constructor() {
this.currentId = null;
this.currentTab = null;
let self = this;
$(".tab").click(function() {
self.onTabClick(event, $(this));
});
$(".container").scroll(() => {
this.onScroll();
});
$(".container").resize(() => {
this.onResize();
});
}
/*Scrolls down to Tab selection*/
onTabClick(event, element) {
event.preventDefault();
let scrollTop = $(element.attr("href")).offset().top;
if (!$(".nav").hasClass("nav--top")) {
scrollTop = scrollTop;
}
$(".container").animate({
scrollTop: scrollTop
}, 600);
}
onScroll() {
this.navPosition();
this.tabAnimation();
}
navPosition() {
let offset = $(".sticky").offset().top + $(".sticky").height();
if ($(".container").scrollTop() > offset) {
$(".nav").addClass("nav--top");
} else {
$(".nav").removeClass("nav--top");
}
}
tabAnimation() {
$("section").each(function() {
var actual = $(this),
actualHeight = actual.height(),
actualAnchor = $(".sticky").find('a[href="#' + actual.attr("id") + '"]');
if (
actual.offset().top <= $(".container").scrollTop() &&
actual.offset().top + actualHeight > $(".container").scrollTop()
) {
actualAnchor.addClass("active");
} else {
actualAnchor.removeClass("active");
}
});
}
}
new StickyNavigation();
body {
position: fixed;
display: flex;
flex-direction: column;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
section {
height: 600px;
border: 2px solid white;
background: blue;
}
section:nth-child(2) {
background: red;
}
.container {
flex: 1;
display: flex;
position: relative;
flex-direction: column;
overflow: auto;
}
.long {
height: 1200px;
}
.header {
height: 75px;
background: green;
}
.hero {
background: silver;
flex: 0;
border: 1px solid;
}
.nav {
background: white;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.nav--top {
position: fixed;
top: 75px;
}
.sticky {
background: white;
display: flex;
flex-direction: row;
flex-wrap: wrap;
position: relative;
}
.tab {
padding: 30px 45px;
position: relative;
}
.tab.active {
background: #6567c5;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="header">
<h1>Header</h1>
</div>
<div class="container">
<div class="hero">
<h1>Hero</h1>
</div>
<div class="sticky">
<nav role="navigation" class="nav">
<a class="tab" href="#One">Option One</a>
<a class="tab" href="#Two">Option Two</a>
</nav>
</div>
<div class="main">
<section id="One">
</section>
<section class="long" id="Two">
</section>
</div>
</div>
</div>
您的部分滚动到顶部的原因是由于添加和
去除粘性元素。使用 wrapper 代替 sticky 以始终占据高度
粘性元素是否存在。
class StickyNavigation {
constructor() {
this.currentId = null;
this.currentTab = null;
this.setup();
this.onResize();
let self = this;
$(".tab").click(function(event) {
self.onTabClick(event, $(this));
});
$(".container").scroll(() => {
this.onScroll();
});
$(window).resize(() => {
this.onResize();
});
}
setup() {
this.$sticky = $('.sticky');
window.stk = this.$sticky;
this.$stickyWrap = $('<div>').insertAfter(this.$sticky);
this.$sticky.appendTo(this.$stickyWrap);
}
/*Scrolls down to Tab selection*/
onTabClick(event, element) {
event.preventDefault();
let $targetElement = $(element.attr("href"));
let positionTop = $targetElement.position().top;
let scrollTop = $('.container').scrollTop();
$(".container").animate({
scrollTop: scrollTop - this.stickyOuterHeight + positionTop
}, 600);
}
onScroll() {
this.navPosition();
this.tabAnimation();
}
onResize() {
this.stickyOuterHeight = this.$sticky.outerHeight();
this.$sticky.width(this.$stickyWrap.width());
this.$stickyWrap.css('minHeight', this.stickyOuterHeight);
}
navPosition() {
if (this.$stickyWrap.position().top < 0) {
this.$sticky.addClass("fixed");
} else {
this.$sticky.removeClass("fixed");
}
}
tabAnimation() {
let desiredSpace = this.stickyOuterHeight + 10;
$("section").each(function() {
let actual = $(this),
actualHeight = actual.height(),
actualAnchor = $(".sticky").find('a[href="#' + actual.attr("id") + '"]');
let actualTop = actual.position().top;
let actualBottom = actualTop + actualHeight;
if (actualTop < desiredSpace && actualBottom > desiredSpace) {
actualAnchor.addClass("active");
} else {
actualAnchor.removeClass("active");
}
});
}
}
$(function() {
new StickyNavigation();
});
body {
position: fixed;
display: flex;
flex-direction: column;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
section {
height: 600px;
border: 2px solid white;
background: blue;
}
section:nth-child(2) {
background: red;
}
.container {
flex: 1;
display: flex;
position: relative;
flex-direction: column;
overflow: auto;
}
.long {
height: 1200px;
}
.header {
height: 75px;
background: green;
}
.hero {
background: silver;
flex: 0;
border: 1px solid;
}
.nav {
background: white;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.sticky {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.sticky.fixed {
position: fixed;
top: 83px;
}
.tab {
padding: 30px 45px;
position: relative;
}
.tab.active {
background: #6567c5;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="header">
<h1>Header</h1>
</div>
<div class="container">
<div class="hero">
<h1>Hero</h1>
</div>
<div class="sticky">
<nav role="navigation" class="nav">
<a class="tab" href="#One">Option One</a>
<a class="tab" href="#Two">Option Two</a>
</nav>
</div>
<div class="main">
<section id="One">
Content One
</section>
<section class="long" id="Two">
Content Two
</section>
</div>
</div>
我的粘性 header.
的行为有问题Desired behavior:
a) Scrolling to where the bottom of the
.nav
hits the top of asection
adds theactive
class to the tab and it remainsactive
until the.nav
reaches the top of the next section.b) Clicking a corresponding section's
.tab
always navigates you to the top of that section and adds theactive
class to the tab.
因此,无论是滚动还是单击,选项卡的 active
状态始终保持,直到 .nav
进入下一个 section
,在这种情况下 active
状态转到该部分的选项卡等。
测试问题:
1) Half-way 向下滚动 Option Two
.tab
的 active
状态丢失。
2) scrollTop
的使用是滚动到.container
的顶部,而不是选择的section
.
class StickyNavigation {
constructor() {
this.currentId = null;
this.currentTab = null;
let self = this;
$(".tab").click(function() {
self.onTabClick(event, $(this));
});
$(".container").scroll(() => {
this.onScroll();
});
$(".container").resize(() => {
this.onResize();
});
}
/*Scrolls down to Tab selection*/
onTabClick(event, element) {
event.preventDefault();
let scrollTop = $(element.attr("href")).offset().top;
if (!$(".nav").hasClass("nav--top")) {
scrollTop = scrollTop;
}
$(".container").animate({
scrollTop: scrollTop
}, 600);
}
onScroll() {
this.navPosition();
this.tabAnimation();
}
navPosition() {
let offset = $(".sticky").offset().top + $(".sticky").height();
if ($(".container").scrollTop() > offset) {
$(".nav").addClass("nav--top");
} else {
$(".nav").removeClass("nav--top");
}
}
tabAnimation() {
$("section").each(function() {
var actual = $(this),
actualHeight = actual.height(),
actualAnchor = $(".sticky").find('a[href="#' + actual.attr("id") + '"]');
if (
actual.offset().top <= $(".container").scrollTop() &&
actual.offset().top + actualHeight > $(".container").scrollTop()
) {
actualAnchor.addClass("active");
} else {
actualAnchor.removeClass("active");
}
});
}
}
new StickyNavigation();
body {
position: fixed;
display: flex;
flex-direction: column;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
section {
height: 600px;
border: 2px solid white;
background: blue;
}
section:nth-child(2) {
background: red;
}
.container {
flex: 1;
display: flex;
position: relative;
flex-direction: column;
overflow: auto;
}
.long {
height: 1200px;
}
.header {
height: 75px;
background: green;
}
.hero {
background: silver;
flex: 0;
border: 1px solid;
}
.nav {
background: white;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.nav--top {
position: fixed;
top: 75px;
}
.sticky {
background: white;
display: flex;
flex-direction: row;
flex-wrap: wrap;
position: relative;
}
.tab {
padding: 30px 45px;
position: relative;
}
.tab.active {
background: #6567c5;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="header">
<h1>Header</h1>
</div>
<div class="container">
<div class="hero">
<h1>Hero</h1>
</div>
<div class="sticky">
<nav role="navigation" class="nav">
<a class="tab" href="#One">Option One</a>
<a class="tab" href="#Two">Option Two</a>
</nav>
</div>
<div class="main">
<section id="One">
</section>
<section class="long" id="Two">
</section>
</div>
</div>
</div>
您的部分滚动到顶部的原因是由于添加和 去除粘性元素。使用 wrapper 代替 sticky 以始终占据高度 粘性元素是否存在。
class StickyNavigation {
constructor() {
this.currentId = null;
this.currentTab = null;
this.setup();
this.onResize();
let self = this;
$(".tab").click(function(event) {
self.onTabClick(event, $(this));
});
$(".container").scroll(() => {
this.onScroll();
});
$(window).resize(() => {
this.onResize();
});
}
setup() {
this.$sticky = $('.sticky');
window.stk = this.$sticky;
this.$stickyWrap = $('<div>').insertAfter(this.$sticky);
this.$sticky.appendTo(this.$stickyWrap);
}
/*Scrolls down to Tab selection*/
onTabClick(event, element) {
event.preventDefault();
let $targetElement = $(element.attr("href"));
let positionTop = $targetElement.position().top;
let scrollTop = $('.container').scrollTop();
$(".container").animate({
scrollTop: scrollTop - this.stickyOuterHeight + positionTop
}, 600);
}
onScroll() {
this.navPosition();
this.tabAnimation();
}
onResize() {
this.stickyOuterHeight = this.$sticky.outerHeight();
this.$sticky.width(this.$stickyWrap.width());
this.$stickyWrap.css('minHeight', this.stickyOuterHeight);
}
navPosition() {
if (this.$stickyWrap.position().top < 0) {
this.$sticky.addClass("fixed");
} else {
this.$sticky.removeClass("fixed");
}
}
tabAnimation() {
let desiredSpace = this.stickyOuterHeight + 10;
$("section").each(function() {
let actual = $(this),
actualHeight = actual.height(),
actualAnchor = $(".sticky").find('a[href="#' + actual.attr("id") + '"]');
let actualTop = actual.position().top;
let actualBottom = actualTop + actualHeight;
if (actualTop < desiredSpace && actualBottom > desiredSpace) {
actualAnchor.addClass("active");
} else {
actualAnchor.removeClass("active");
}
});
}
}
$(function() {
new StickyNavigation();
});
body {
position: fixed;
display: flex;
flex-direction: column;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
section {
height: 600px;
border: 2px solid white;
background: blue;
}
section:nth-child(2) {
background: red;
}
.container {
flex: 1;
display: flex;
position: relative;
flex-direction: column;
overflow: auto;
}
.long {
height: 1200px;
}
.header {
height: 75px;
background: green;
}
.hero {
background: silver;
flex: 0;
border: 1px solid;
}
.nav {
background: white;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.sticky {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.sticky.fixed {
position: fixed;
top: 83px;
}
.tab {
padding: 30px 45px;
position: relative;
}
.tab.active {
background: #6567c5;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="header">
<h1>Header</h1>
</div>
<div class="container">
<div class="hero">
<h1>Hero</h1>
</div>
<div class="sticky">
<nav role="navigation" class="nav">
<a class="tab" href="#One">Option One</a>
<a class="tab" href="#Two">Option Two</a>
</nav>
</div>
<div class="main">
<section id="One">
Content One
</section>
<section class="long" id="Two">
Content Two
</section>
</div>
</div>