Reputation: 5166
I am trying to create a post page where user scroll to view the posts. There are multiple posts with a sidebar so I want to display a progress bar to indicate the article position. The code I wrote for this is working good when I navigate to the first element but not for the elements after this.
Here is the code. I tried to set up a fiddle
here I want to achieve something like this in the sidebar Reference link
var contentSections = $('.single_page_post');
jQuery(window).on('scroll', function () {
updateNavigation();
});
function updateNavigation() {
contentSections.each(function () {
$this = $(this);
var theID = $this.attr("id");
if (($this.offset().top - $(window).height() / 2 < $(window).scrollTop()) && ($this.offset().top + $this.height() - $(window).height() / 2 > $(window).scrollTop())) {
var s = $(window).scrollTop(),
d = $this.height(),
c = $this.offset().top;
var scrollPercent = (s / (d - c)) * 100;
var progressheight = 100-scrollPercent;
$("a[href='#" + theID + "']").prev().css({'height' : progressheight+"%", 'display' : 'block'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').addClass("current");
} else {
$("a[href='#" + theID + "']").prev().css({'display' : 'none'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').removeClass("current");
}
});
}
.content_area {
width: 60%;
float:left;
}
.post_page_sidebar {
position: relative;
}
.post_progress {
position: absolute;
width: 5px;
background: red;
bottom:0px;
}
a {
padding: 10px 10px 10px 7px;
display: inline-block;
}
li {
list-style: none;
}
.sidebar {
width: 30%;
position: fixed;
top: 0px;
}
.single_page_post {
height: 500px;
border: 2px solid #e2e2e2;
margin-top: 5px;
margin-left:200px;
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="sidebar">
<ul>
<li id="sidebar_post_267" class="post_page_sidebar">
<div class="post_progress"></div>
<a href="#post_section_267">Dummy Post 4</a>
</li>
<li id="sidebar_post_263" class="post_page_sidebar">
<div class="post_progress"></div>
<a href="#post_section_263">Dummy Post 3</a>
</li>
<li id="sidebar_post_261" class="post_page_sidebar">
<div class="post_progress"></div>
<a href="#post_section_261">Dummy Post 2</a>
</li>
<li id="sidebar_post_131" class="post_page_sidebar">
<div class="post_progress"></div>
<a href="#post_section_131">Test Post</a>
</li>
</ul>
</div>
<div class="content_area">
<div class="single_page_post" id="post_section_267">
</div>
<div class="single_page_post" id="post_section_263">
</div>
<div class="single_page_post" id="post_section_261">
</div>
<div class="single_page_post" id="post_section_131">
</div>
</div>
Upvotes: 2
Views: 1080
Reputation: 1626
There's two issues with your code. The first one is that, logically, you would not be wanting to subtract $this.offset().top
from $this.height()
but rather from $(window).scrollTop()
giving you:
var scrollPercent = ((s-c) / (d)) * 100;
The second one is that your logic to switch which article is the currently visible one is convoluted and wrong. The statement you posted switches active article "too early" and therefore returns something a long the lines of "the user read -30% of this article". It is a lot easier to just check for each item whether:
$this.offset().top - $(window).scrollTop() < 0
to determine if it is completely in the viewport.
These two changes give you the following snippet:
var contentSections = $('.single_page_post');
jQuery(window).on('scroll', function () {
updateNavigation();
});
function updateNavigation() {
contentSections.each(function () {
$this = $(this);
var theID = $this.attr("id");
if ($this.offset().top - $(window).scrollTop() < 0) {
var s = $(window).scrollTop()-13,
d = $this.outerHeight(),
c = $this.offset().top;
var scrollPercent = ((s-c) / (d)) * 100;
var progressheight = 100-scrollPercent;
$("a[href='#" + theID + "']").prev().css({'height' : progressheight+"%", 'display' : 'block'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').addClass("current");
} else {
$("a[href='#" + theID + "']").prev().css({'display' : 'none'});
$("a[href='#" + theID + "']").parents('.post_page_sidebar').removeClass("current");
}
});
}
.content_area {
width: 60%;
float:left;
}
.post_page_sidebar {
position: relative;
}
.post_progress {
position: absolute;
width: 5px;
background: red;
bottom:0px;
}
a {
padding: 10px 10px 10px 7px;
display: inline-block;
}
li {
list-style: none;
}
.sidebar {
width: 30%;
position: fixed;
top: 0px;
}
.single_page_post {
height: 500px;
border: 2px solid #e2e2e2;
margin-top: 5px;
margin-left:200px;
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="sidebar">
<ul>
<li id="sidebar_post_267" class="post_page_sidebar">
<div class="post_progress"></div>
<a href="#post_section_267">Dummy Post 4</a>
</li>
<li id="sidebar_post_263" class="post_page_sidebar">
<div class="post_progress"></div>
<a href="#post_section_263">Dummy Post 3</a>
</li>
<li id="sidebar_post_261" class="post_page_sidebar">
<div class="post_progress"></div>
<a href="#post_section_261">Dummy Post 2</a>
</li>
<li id="sidebar_post_131" class="post_page_sidebar">
<div class="post_progress"></div>
<a href="#post_section_131">Test Post</a>
</li>
</ul>
</div>
<div class="content_area">
<div class="single_page_post" id="post_section_267">
</div>
<div class="single_page_post" id="post_section_263">
</div>
<div class="single_page_post" id="post_section_261">
</div>
<div class="single_page_post" id="post_section_131">
</div>
</div>
Upvotes: 1