I was quite happy with my jQuery-solution until I noticed that scrolling is not working properly on chrome, on some cell phones and tablets. That is, scrolling is jumpy and the hashes occur in an ambiguous and irritating way. I am using wordpress + Slider Revolution 6.
So these are my functions:
when an id is in the viewport, its button gets a class (underline).
when an id is in the viewport, the url gets extended with the id's name (#id)
additionally, not shown here and part of the Slider Revolution 6, I use "menu-link+scroll to id"
So, the code below looks comprehensible and simple to me. But I cannot figure out why chrome on some phones and tablets makes the above mentioned problems. I have tried to clear caches everywhere.
function isScrolledIntoView(elem) {
var docViewTop = jQuery(window).scrollTop();
var docViewBottom = docViewTop + jQuery(window).height();
var elemTop = jQuery(elem).offset().top;
var elemBottom = elemTop + jQuery(elem).height();
return (docViewBottom >= elemTop && docViewTop <= elemBottom);
}
jQuery(window).scroll(function() {
element = jQuery('#first');
if (isScrolledIntoView(element) === true) {
jQuery('#first-btn').addClass('underline');
history.replaceState(null,null,'#first');//or pushState?
} else {
jQuery('#first-btn').removeClass('underline');
}
element = jQuery('#second');
if (isScrolledIntoView(element) === true) {
jQuery('#second-btn').addClass('underline');
history.replaceState(null,null,'#second');//or pushState?
} else {
jQuery('#second-btn').removeClass('underline');
}
});
Any help very much appreciated!
Best regards,
Skt
Related
I have 3 blocks about halfway down the page that the client wants to appear in an upward transition when the user scrolls down to it. I've been looking into transition on scroll effects all morning and most of what I've found are parallax pages and headers.
<ul class="testimoniallist">
<li>
stuff
</li>
<li>
more stuff
</li>
<li>
Other stuff
</li>
User goes to the website
User scrolls down to the section with that UL and the three list items
The three list items then appear to transition up
Just for testing purposes, I created a jsfiddle here: http://jsfiddle.net/odyq4rc7/
I gave the ul class a margin top of 1600px so when the user scrolls down to it, how could I bump that up 100px when it comes into viewport view?
On scroll, you could check if the element has come into view, and set its properties accordingly, using something like this to check if its in the viewport:
function isScrolledIntoView( element ) {
var elementTop = element.getBoundingClientRect().top,
elementBottom = element.getBoundingClientRect().bottom;
return elementTop >= 0 && elementBottom <= window.innerHeight;
}
I solved it with the following: (I found this courtesy of this jsfiddle: http://jsfiddle.net/vVaat/76/)
function isScrolledIntoView(elem) {
var $window = $(window),
docViewTop = $window.scrollTop(),
docViewBottom = docViewTop + $window.height(),
elemTop = $(elem).offset().top,
elemBottom = elemTop + $(elem).outerHeight();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
$(window).on("scroll", function() {
$('.testimoniallist').each(function() {
if (isScrolledIntoView(this)) {
$(this).addClass('yes');
} else {
$(this).removeClass('yes');
}
});
});
I got a scrollable page containing a lot of divs. I want to fade out the elements at the top and bottom of the page while the user is scrolling; so only the divs which are currently in the center of the viewport will have an opacity of 100%.
I am currently achieving this by observing the window.scroll event and calculating each divs opacity by their position in relation to the scroll offsets. This works, but has an huge impact on the clients performance (specially when there are a lot of divs) - which leads to a "non fluid" scrolling experience.
Are there other approaches available? Maybe even a solution without going through every single div?
Edit:
I setup a quick preview on jsFiddle, which illustrates my current approach (not optimized)
Thanks for you comments! I really like the idea of using a background gradient to fake the elements opacity - but in my case this won't work, because I got an background image.
Example on jsFiddle
// http://stackoverflow.com/a/488073/340760
function isScrolledIntoView(elem)
{
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
// when you scroll the div
$(".list").scroll(function(e) {
var $list = $(this);
// apply logic only to visible elements
$list.find("div")
.filter(function(i, d) {
return isScrolledIntoView(d);
})
.each(function() {
var eTop = $(this).offset().top;
var center = $list.height() / 2;
// if the element is in the center it is 100%
// otherwise it will fade
var dif = center - eTop;
if (dif < 0) dif *= -1;
var pc = 1 - (dif / center);
// set the opacity for the elements
$(this).css("opacity", pc);
});
});
I have some divs, I need to trigger an action (float another div or fire an alert for example) when a certain div is viewed or scrolled to.. What is the best approach to do so?
What you mean by "viewed" I have no idea - but here is how you would do it when the user puts their mouse over the div:
function isScrolledIntoView(elem) {
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
$(window).scroll(function() {
if(isScrolledIntoView(myelement)) {
// in view
} else {
// not in view
}
});
Credit to Is there a way to detect when an HTML element is hidden from view?
You can probably use the Bullseye jQuery plugin which adds adds enterviewport and leaveviewport events to elements.
The following code works ok on IE and Firefox, but Chrome hates it (it runs but is really laggy). I am sure it could be made more browser friendly, but how? itemPlaceholder is hundreds of 100x100 floated divs (eg image placeholders). I'm using jquery 1.4.4 and Chrome v10.0.648.127.
$(function () {
ReplaceVisible();
$(this).scroll(function () {
ReplaceVisible();
});
});
function ReplaceVisible() {
$('.itemPlaceholder').each(function (index) {
if (HasBeenScrolledTo(this)) {
$itemPlaceholder = $(this);
$itemPlaceholder.replaceWith('<img src="bicycle.jpg" />');
}
else {
return false;
}
});
}
function HasBeenScrolledTo(elem) {
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
return elemTop < docViewBottom;
}
Edit: Replaced append with replaceWith otherwise we get lots of images appended to the same element.
This runs slowly in chrome because chrome fires the onscroll event continuously as the page is scrolled (IE and firefox only fire onscroll when scrolling stops).
You could improve chrome's performance in this case by queuing up the invocations of ReplaceVisible and only allowing it to be fired once in a given time period. An example of queuing invocations is available here (https://github.com/tilleryj/rio/blob/master/public/javascripts/lib/delayed_task.js)
I had a similar problem where I had to detect resize events, which as you'd expect fired an awful lot of them and locked up the browser. I haven't tested it though, so please report back if it works. :)
$(function () {
replaceVisible();
$(this).scroll( replaceVisible );
});
var replaceVisible = (function(){
var last_scroll = null; // Last time we scrolled
var paused = false; // We've paused scrolling
var delay = 1000; // Delay in between acting on the scroll (ms).
return function(){
if( paused ) return;
if( new Date() - last_scroll < delay ){
setTimeout( function(){ paused = false; replaceVisible(); }, delay )
paused = true;
}
$('.itemPlaceholder').filter(HasBeenScrolledTo)
.replaceWith('<img src="bicycle.jpg" />');
last_scroll = new Date();
}
})();
function HasBeenScrolledTo(index) {
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(this).offset().top;
return elemTop < docViewBottom;
}
I'm trying to create a messagebox that is fixed to the bottom of a webpage, so when a user scrolls, it stays put (simple css).
However, I'd like the messagebox to disappear when the user scrolls to a certain point in the webpage.
For example, if you have a signup form on the bottom of your site, I'd like to create a messagebox that reads "scroll down to signup", and when the user scrolled down to the top of the sign up form, the message would disappear, or get covered up by the form.
So when they scrolled up, the message would reappear.
This isn't my implementation, but an accurate illustration of the concept.
I haven't any experience developing with Javascript, but was hoping there was an existing method for this. I'm willing to learn though, this is something I'd like to use.
Any thoughts? Or concepts to start learning?
Thanks guys! (I think this could be a really clever method of highlighting certain content that perhaps users would miss if they didn't scroll through the entire page.)
This should do the trick (tested in IE7, Firefox, Chrome, Safari).
It uses jQuery and shows the element as soon as it is visible. This is the code:
$(document).ready(function() {
function isScrolledIntoView(elem) {
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom));
}
// the element to look for
var myelement = $('#formcontainer');
// the element to hide when the above is visible
var mymessage = $('#mymessage');
$(window).scroll(function() {
if(isScrolledIntoView(myelement)) {
mymessage.hide();
} else {
mymessage.show();
}
});
});
If you want the whole element to be visible before the message is hidden, replace the isScrolledIntoView above with this:
function isScrolledIntoView(elem) {
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom)
&& (elemBottom <= docViewBottom) && (elemTop >= docViewTop) );
}
Credit for both of these functions go to this question.