Automatically scroll down as text appears on screen - javascript

I am showing a poem word by word (using lettering.js and jQuery. This is working well. Now I want to add an additional feature: I want the page to scroll down as the text appears on the screen. I am trying:
div.lettering('words');
div.find('span').hide();
div.show().find('span').each(function(i) {
$(this).delay(delay * i).fadeIn(fadeIn);
var _this = $(this);
$('html, body').scrollTop(
_this.offset().top - $('html, body').offset().top + $('html, body').scrollTop()
);
});
Also tried:
div.lettering('words');
div.find('span').hide();
div.show().find('span').each(function(i) {
$(this).delay(delay * i).fadeIn(fadeIn);
var _this = $(this);
$('html, body').animate({
scrollTop: _this.offset().top
}; 500);
});
But the page scrolls to some position on page load, and that's it. I have the feeling that the _this variable I am using isn't correct.
Any idea how to achieve my goal?

If you are adding content directly to your body and the height of your body gets dynamically changed as the elements get added then you need to do this.
div.show().find('span').each(function(i) {
$(this).delay(delay * i).fadeIn(fadeIn,function(){
var _body = $("body");
_body.animate({
scrollTop: document.body.scrollHeight;
}; 500);
});
});
What happens in your case is the animation for scrolling down occured immediately which wasnt needed , doing it this way ensures that the slide down animation occurs only when the fade-in animation has completed .
Otherwise if you are not adding content directly to your body you can still do it using the same technique applied to outer and inner.

As #Abhishek pointed out in his answer, I had to use a callback for the scrolling to work properly. However, the scrolling still wasn't working. So I ended up using Abhishek's code combined with the scrollTo plugin:
div.lettering('words');
div.find('span').hide();
$.scrollTo('h3', {duration:500});
div.show().find('span').each(function(i) {
var _this = $(this);
$(this).delay(delay * i).fadeIn(fadeIn,function(){
$.scrollTo(_this, {duration:100} );
});
});
The animation isn't as smooth as I want it to be because duration: 100 is a bit too quick.. But if I set a higher value, the scrolling will happen after all the text has been displayed, which feels a bit weird.

Related

jQuery scroll to anchor returns NaN as location hash

Friends,
I'm using following jQuery code which implements the animated scroll to an anchor:
(function($){
var jump=function(e)
{
if (e){
e.preventDefault();
var target = $(this).attr("href");
}else{
var target = location.hash;
}
$('html,body').animate(
{
scrollTop: $(target).offset().top - 150
}, 1500, 'swing', function()
{
location.hash = target - 150;
});
};
$('html, body').hide();
$(document).ready(function()
{
$('a[href^=#]:not(#toggle)').on("click", jump);
if (location.hash){
setTimeout(function(){
$('html, body').scrollTop(0).show();
jump()
}, 0);
}else{
$('html, body').show()
}
});
})(jQuery);
As you see from the code above, I use the target offset value of 150px:
scrollTop: $(target).offset().top - 150
In order for this code to work properly, I also need to pass the target with offset to the location.hash. This is how I do that:
location.hash = target - 150;
Under such implementation, the code works fine. Except it always show #NaN in the URL when I scroll to anchor. This is clearly because of the line above. However, if I don't use the -150px, then it scrolls to target with offset and then suddenly jumps to original anchor location without offset.
My question is, how I can achieve both win win situation? I mean, no #NaN in URL and proper scroll to anchor with offset from top. I heard that it's possible to use "e.preventdefault", but somehow it doesn't work for me.
Any suggestions would be very appreciated.
Try
$('html,body').animate(
{
scrollTop: $(target).offset().top - 150
}, 1500, 'swing');
location.hash = target;
};
I had the same problem and now it works
location.hash includes the #, so you if you try to do arithmetic on it it can't be converted to a number.
Use Number(location.hash.substr(1)) instead. You'll need to add the # back in whenever you try to use that number as a DOM ID.
(You might consider changing your code to not use the same variable to indicate both DOM nodes and scroll position, though; it's fairly confusing. If I were refactoring this I'd change those IDs to meaningful labels, and set the scroll position based on those element's offset().top instead of on the numeric content of the hash itself.)

Page scroll to right page from menu anchor but not from direct link

I'am using this free script
http://codyhouse.co/gem/css-faq-template/
http://codyhouse.co/demo/faq-template/index.html#payments
The demo has the same problem as my website, although it's even worse on my website.
If you use the menu, everything works fine. You have some space above the header.
But if you visit the direct link http://codyhouse.co/demo/faq-template/index.html#payments not from the menu
it looks like this
As you can see, there is no space above the header "payments".
It is even worse on my page. It starts at "Can I have.." and the header is hidden. Can not find where I can adjust this when I visit the page direct from the link without it effects how it looks when I visit the section from the menu.
When user clicks on a section
//select a faq section
faqsCategories.on('click', function(event){
event.preventDefault();
var selectedHref = $(this).attr('href'),
target= $(selectedHref);
if( $(window).width() < MqM) {
faqsContainer.scrollTop(0).addClass('slide-in').children('ul').removeClass('selected').end().children(selectedHref).addClass('selected');
closeFaqsContainer.addClass('move-left');
$('body').addClass('overlay');
} else {
$('body,html').animate({ 'scrollTop': target.offset().top - 69}, 200);
}
});
Javascript code: http://codyhouse.co/demo/faq-template/js/main.js
Style: http://codyhouse.co/demo/faq-template/css/style.css
Just a quick hack, use
if(window.location.hash) {
// if url contain '#'
// scroll down a few pixle
}
EDIT:
it's hard to demenstrated this in jsfiddle, since it won't let me play with the # hash.
var url = 'http://example.com/test.html#hash';
//you can get by using window.location.href
var hash = url.split('#')[1];
// this get the 1st hash variable
if(hash) {
// if hash exist
$('html, body').animate({
scrollTop: "5000px"
}, 0);
// scroll down a little bit
}
It's seems there's a couple of problems here. For me it looks like everything happens when a scrolling event fire.
Try this:
$(document).ready(function(){
$(window).scroll();
})

jQuery Smooth Scroll to ID on same and on other page: how to set offset?

Im using jQuery on my page to jump / scroll to IDs.
This works from other pages with anchors like
Jump & Scroll to ID on other page
and on the same page only with anchors like
Jump / Scroll to ID on the same page
Thats not the best solution because I have to change my nav menue but it works (I load another menue with other tags on the page).
Now im looking for a way to add an offset of -230px to the scroll / jump script, beause I have a fixed header on my page.
I think its simple but unfortunately im not a jQuery pro. How can I do this? Please Help me to add the -230 Offset to this function :)
The jQuery Code:
(function($){
var jump=function(e)
{
if (e){
e.preventDefault();
var target = $(this).attr("href");
}else{
var target = location.hash;
}
$('html,body').animate(
{
scrollTop: $(target).offset().top
},1000,function()
{
location.hash = target;
});
}
$('html, body').hide()
$(document).ready(function()
{
$('a[href^=#]').bind("click", jump);
if (location.hash){
setTimeout(function(){
$('html, body').scrollTop(0).show()
jump()
}, 0);
}else{
$('html, body').show()
}
});
})(jQuery)
The responsible for saying how much your page will scroll down is scrollTop: $(target).offset().top, so, if you want to offset -230px just subtract 230 from $(target).offset().top.
But, if you do this in your current code it will not work, because you are changing the hash using location.hash = target;. When you do this, your browser will locate the hash and jump to it (without animating, just jumping).
Observe this demo: http://jsfiddle.net/pcyn2fvk/
If you click in the anchor, the page will scroll down to the content and after the scroll it will jump (this is caused by location.hash = target;).
Here is the demo without using location.hash = target;: http://jsfiddle.net/pcyn2fvk/1/
I assume you will need to change the hash, so, you can try a different approach, like this one explained by Lea Verou (http://lea.verou.me/2011/05/change-url-hash-without-page-jump/) that uses the History API instead of location.hash.
There are some other approaches, for example, you can remove the id of your target section (the one you clicked to scroll to) when you click to the anchor, then, when you change the location using location.hash, the browser will not find the clicked id, and will not jump to it, then, after that, you can reassign the id to your section.
Hope it helps!
I found another approach with anchor hashtags. This allows me to load a different page and scroll to my id with an offset.
In IE the scroll works well on all pages but all other browsers don't scroll on the smae page. If I click my link on the page wehre I want to scroll they jump to the hastags and dont use my jQuery scroll function. If I click the same link from an other URL the scroll works.
(other approach, only working from Link on Page A to Page B)
$(document).ready(function() {
$('html, body').hide();
if (window.location.hash) {
setTimeout(function() {
$('html, body').scrollTop(0).show();
$('html, body').animate({
scrollTop: $(window.location.hash).offset().top -230
}, 1000)
}, 0);
}
else {
$('html, body').show();
}
});

jQuery scroll to next element via up/down buttons - how to add handling for manual scrolling that would otherwise confuse this?

I am trying to implement two static buttons for navigating up or down between about 10 containing div tags on a single fairly deep page of content.
I want the buttons to smoothly scroll to the next part of the page (next containing div) whenever they are clicked on.
The problem with this solution is that if you manually scroll up and down the page using the browser scroll bar or the mouse wheel then the logic of the code is not aware of this and when you next click next/prev a scroll takes place that is not actually relevant to the viewable area you see, totally ruining the user experience.
You can test this in this demo: http://jsfiddle.net/aVJBY/ . If you click NEXT once it works. Now scroll down to near the bottom of the content and click PREV. In theory the page should go one step back from the bottom of the page. Instead it returns to the top of the page.
Maybe I just need to scrap this code and use some external library which is fine, but I can't find anything appropriate. Anyone have an idea on how to make my code resolve this issue?
The code I am using so far is here:
$('div.section').first();
$('a.display').on('click', function(e) {
e.preventDefault();
var t = $(this).text(),
that = $(this);
if (t === 'next' && $('.current').next('div.section').length > 0) {
var $next = $('.current').next('.section');
var top = $next.offset().top;
$('.current').removeClass('current');
$('body').animate({
scrollTop: top
}, function () {
$next.addClass('current');
});
} else if (t === 'prev' && $('.current').prev('div.section').length > 0) {
var $prev = $('.current').prev('.section');
var top = $prev.offset().top;
$('.current').removeClass('current');
$('body').animate({
scrollTop: top
}, function () {
$prev.addClass('current');
});
}
});
I resolved this with the wonderful jQuery inview plugin - https://github.com/protonet/jquery.inview An overview of what I did follows...
I first setup some variables, the pageItems array contains all the divs I need to monitor...
var posNext=0;
var posPrev=0;
var pageItems = ["pageone", "pagetwo", "pagethree", "pagefour", "pagefive"];
I then setup the following in document ready. Thanks to the inview plugin and the jQuery bind event, on a page scroll (of any kind, either by my buttons, manually or via mouse wheel) the plugin is run. I first search the array of page items for a match with what is returned by the $(this).attr("id") value. I then adjust the posNext/posPrev variables with values based on the current div in view.
$(document).ready(function (){
$(".divclass").bind('inview', function(event, isInView, visiblePartX, visiblePartY) {
if (isInView) {
matchPos = pageItems.indexOf($(this).attr("id"));
// Determine prev/next positions now we have an index. The position values used in click events later
if ( (matchPos+1)==pageItems.length ){
posNext=matchPos;
posPrev=matchPos-1;
}else if (matchPos==0){
posNext=matchPos+1;
posPrev=0;
}else{
posNext=matchPos+1;
posPrev=matchPos-1;
}
} else {
// dont update index
}
});
});
Finally also within document.ready I have binds to catch clicks on the buttons I have on screen all the time. These use a jQuery animate call to scroll to the div id value specified via the array index values in posNext/posPrev.
$(".down-button").click(function(e){
event.preventDefault();
$('html, body').stop().animate({
scrollTop: $("#"+pageItems[posNext]).offset().top
}, 500);
});
$(".up-button").click(function(e){
event.preventDefault();
$('html, body').stop().animate({
scrollTop: $("#"+pageItems[posPrev]).offset().top
}, 500);
});

Keep clicked link in viewport when calling jQuery's slideUp function

I have the following html structure repeated multiple times on a page:
<div class="item">
<div class="header">
...
Close All Expanded
</div>
<div class="expanded">
...
</div>
</div>
And some jQuery to close all the divs with class expanded when the link is clicked:
$('.closeExpanded').click(function(e){
e.preventDefault();
$('.expanded').slideUp('slow');
});
However I want to ensure that the link you've just clicked remains in view and moves as little as possible. Currently clicking on a link halfway down the page causes the link to move up out of the viewport as divs above it are closed.
Is there a nice graceful way I can keep the link that's been clicked in the viewport?
Update:
I've tried the answers suggested so far but so far none completely work (e.g. clicking link number 30 in each of these leads to link number 30 ending up outside of the viewport)
mrtsherman's solution: http://jsfiddle.net/Qan5p/38/
Mohsen's solution: http://jsfiddle.net/Qan5p/39/
roXon's solution: http://jsfiddle.net/Qan5p/40/
You will need to modify the scrollTop property of the page to keep things in place. Fortunately, as elements are shrunk they will be triggering scroll events you can hook into.
//untested, but should look something like this
var linkPosition = null;
$('.closeExpanded').click(function(e){
e.preventDefault();
linkPosition = $(this).offset().top - $(document).scrollTop();
//in callback to slideUp clear linkPosition so that we know to stop tracking scroll events
$('.expanded').slideUp('slow', function() {
linkPosition = null;
});
});
$(document).scroll( function(){
//check to see if we should be keeping link on screen
if (linkPosition != null) {
//keep the link in position
//I'm not so sure about this bit of the code, but I think you get the idea. All you have to do
//is properly calculate the new offset to keep the link looking like it is in the same position
var newPos = $(document).scrollTop() + linkPosition;
$(document).scrollTop(newPos);
}
});
$('.closeExpanded').click(function(e){
e.preventDefault();
$('.expanded').css({
'position' : 'absolute', // make it position absolute to prevent moving
'left' : $(this).offset().left,
'top' : $(this).offset().top
}).slideUp('slow', function(){
$('.expanded').css('position', 'static');
});
});
Fiddle: http://jsfiddle.net/mohsen/Qan5p/10/
WORKING DEMO
The easiest way:
Wrap contents into dynamically generated divs.
First animate the contents,
Than animate the wrapper elements
$('.expanded').wrapInner('<div class="wrapper" />');
$('.expanded').each(function() {
$(this).height($(this).children('.wrapper').height());
});
$('.closeExpanded').click(function(e) {
e.preventDefault();
$('.wrapper').animate({height: '0px'}, 800, function() {
$('.expanded').slideUp(800);
});
});

Categories