Switch tabs based on mouse scroll - javascript

I would like to have a widget on a webpage containing a number of tabs. When the user scrolls the page and the widget comes in to view and he keeps scrolling down, the tabs should be activated one by one (without the page scrolling further down). Once the last tab is showing, the page should resume scrolling as usual. Is this doable using JS/jQuery?
UPDATE:
Since this seems too broad a question:
The problem is, I don't know how to use the scroll offset and prevent the page from scrolling down until I decide it can resume its normal behavior
UPDATE 2
I created This fiddle,
$(document).ready(function(){
$('#tabbed').mouseover(function(){
$(this).focus();
}).scroll(function(){
console.log("scrolling tabs");
});
$(window).scroll(function(evt){
var scrollPos = $(this).scrollTop()
console.log(scrollPos);
// BULLETPROOF WAY TO DETECT IF THE MOUSE IS OVER THE
// SCROLLABLE DIV AND GIVE IT FOCUS HERE?
});
});
it contains a long page and a scrollable div among its contents. The only problem is that the div starts catching scroll events only if I move my mouse. If I could find a bulletproof way to activate the scrolling div whenever the mouse is over it I'm there. Any ideas?

You can't prevent scrolling with javascript. Using iframes and divs with scroll will only work if the mouse is over them.
You can cancel the mouse wheel and keys events related to the scrolling, however the user will be able to scroll using the scrollbar (more here).
Another approach is leaving an empty area and fixing your widget inside this area, like in this working example
$(window).bind('scroll', function()
{
var scroll = $(window).scrollTop(),
innerHeight = window.innerHeight || $(window).height(),
fooScroll = $('#fooScroll'),
emptyArea = $('#emptyArea'),
offset = emptyArea.offset(),
fixedClass = 'fixed';
if(scroll > offset.top)
{
if(scroll < offset.top + emptyArea.height() - fooScroll.height())
{
fooScroll.addClass(fixedClass);
fooScroll.css("top", 0);
}
else
{
fooScroll.removeClass(fixedClass);
fooScroll.css("top", emptyArea.height() - fooScroll.height());
}
}
else
{
fooScroll.removeClass(fixedClass);
fooScroll.css("top", 0);
}
});
Then you can change the tabs while the page is scrolling.

You should be able to do this. You can use the jQuery scroll event to run your own code whenever the user scrolls up or down. Also, so long as you call e.preventDefault() whenever the scroll event is fired, you can prevent the whole window from scrolling up or down.

Related

Setting an element's focus only if user has tabbed to it

I am trying to make some collapsible accordion containers on my website accessible, but I am running into an issue.
The accordions are controlled by link elements on the page - this way, a keyboard-only user can tab to them and access them. The first issue I ran into was that if a user tabbed to one of the links, the page wouldn't always scroll up to show them which one they had tabbed to. I fixed this issue setting the focus using the following code, which scrolls the link to the top of the viewport:
$(".accordion .accordion-item .accordion-heading a").focus(
function()
{
$('html:not(:animated), body:not(:animated)').animate({
scrollTop: $(this).offset().top
}, 250);
}
);
The problem I am encountering now is that when a mouse-user clicks on the link, it jumps to the top of the page and does not open the container unless the mouse-user clicks the link again.
Is there a way I can set the focus code above to only fire if the link has been tabbed to? Or, is there a better way of handling the focus issue so that it works for both keyboard-only and mouse users?
Thanks!
Firstly a quick apology, having now seen your accordion is built correctly, links with in-page anchors are actually preferable if the accordion is constructed using javascript on page load and falls back to just a list of in page anchor links and content between them.
I am that used to seeing <a href="#"> on accordion openers and weird accordion implementations I jumped to conclusions, change it back from <buttons>!
Fixing your problem
Probably not the answer you are looking for but remove the .focus() function entirely.
It produces strange behaviour where if I have one accordion item open and i tab back with Alt + Tab quickly scrolling can be really confusing as it jumps around if you tab quicker than the scroll.
One of the golden rules of accessibility is to only adjusted the scroll position on a page if it is expected (i.e. a return to top button or using in-page anchors).
In the example and on your website once I disabled the 'scroll to top on focus' the site actually behaved as expected.
I understand why you did it as occasionally a link that is focused appears off the page, however this remedies itself when you tab again or by scrolling down (your site is logical so that if I tab and my focus is not visible I know it is off the page.)
This tends to happen (items not scrolling into view) when the item is just out of sight, by a px or two, it is common and ironically now falls into 'expected' behaviour (another rule, follow accepted and expected behaviour when designing components and pages).
If you really want to fix it
In your focus function instead of just scrolling to the top of the page whenever an item is focused, check if it is off the page.
Below is an example function I found (not tested) that you can use to check if the item is in the viewport, if it is then don't do anything, if it isn't then do your scroll function.
var isInViewport = function (elem) {
var bounding = elem.getBoundingClientRect();
return (
bounding.top >= 0 &&
bounding.left >= 0 &&
bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
bounding.right <= (window.innerWidth || document.documentElement.clientWidth)
);
};
So roughly (yet again haven't tested that the correct items are passed in, this is just to give you an idea).
$(".accordion .accordion-item .accordion-heading a").focus(
function()
{
if(isInViewport(this) === false){
//item is not in the viewport so scroll it into view
$('html:not(:animated), body:not(:animated)').animate({
scrollTop: $(this).offset().top //I would perhaps add a couple of hundred pixels here to make the item appear in a more natural area.
}, 250); //remove the animation as a further accessibility improvement, animations can be off putting to people with motion or anxiety disorders.
}
}
);
This fixes your problem as no mouse user will ever be able to click an item that is off the page so they won't ever trigger the scroll event that causes the focus issue.
You can change the event setting: Instead focus() event you will do a click() event: When you click a link, you'll scroll up. This will solve the problem of both keyboard navigation and mouse clicking;And this is also more true in terms of accessibility.
$(".accordion .accordion-item .accordion-heading a").click(
function(e)
{
e.preventDefault();
$('html:not(:animated), body:not(:animated)').animate({
scrollTop: $(this).offset().top
}, 250);
}
);
Don't forget to change the link setting to a button by adding role=button attribute.
and add aria-expanded attribute.

Scroll duration when scrolled

I am using Jquery to create an effect that will change things as the user scrolls
$(function() {
var headerPosition = $(".home-header");
$(window)
.scroll(function() {
var scroll = $(window)
.scrollTop();
if (scroll >= 200) {
headerPosition.addClass("home-header-color");
} else if (scroll <= 600) {
headerPosition.removeClass("home-header-color");
}
});
});
This is what i'm using a simple add remove class function that gets triggered on a certain scroll amount.
What I want to do is to make it as a user scrolls once no matter how fast.
This is what I came up with but dose not work well scrolling up.
Codepen
I want it to only appear when you reach the top of the screen when scrolling up. Not on just one scroll up.
I tried combining the two but it didn't work out well.

Scroll to element when user scrolls from top down

I am trying to do a effect like on the App Builder Website.
When the user is at the header with the background image/video and scrolls down, the site scrolls down to the next div/section/etc. .
If the user scrolls back up and the image/video part is reached, the page scrolls to the top of it. I have tried the following code but there is bug i can't find:
function scrollto(where){
$('html,body').animate({ scrollTop: $(where).offset().top - 65}, 800);
console.log('Scrolled to ' + where);
closeMenue();
}
var lastScrollTop = 0;
var scroll = $(window).scrollTop();
$(window).scroll(function(event){
var st = $(this).scrollTop();
if (st > lastScrollTop){
if (scroll == 0){
scrollto('.about');
}
else{
}
} else {
if (scroll == 530){
scrollto('.parallax');
}
else{
}
}
lastScrollTop = st;
});
It is working fine, but only once. Is there a Plugin I can use?
Sorry for my bad english :(
The site you posted is making use of fullPage.js plugin.
It works using CSS3 transitions with a fallback to jQuery when needed.
If you don't want to use jQuery, there's even a pure javascript version for it in development but functional.
dont use jquery for smooth transitions.
is better do that things with css methods.
check this if want use any library
So, here's what I believe I'm seeing on their site if you want to do something similar:
No scroll bar; you'll need to make your top-most container have overflow: hidden. It might be best to capture scroll wheel events. See here for more details: Get mouse wheel events in jQuery?
The active viewport gets a class "active". They're presumably using it to keep track of which viewport to scroll to next and maybe to determine
So, in your scroll wheel event handler, you'll need to:
Determine first if you're going up or down. (Outlined in the SO link above)
You'll need to find the next sibling div/viewport/container/whatever that's not active.
You'll want to move the active class to that appropriate sibling (previous/next depending on up/down) and scroll it into view using scrollTop.

force stop scrolling on reaching the end of a scrollspy section

here is a fiddle to know where I am starting from
The problem I am looking to solve involves "paginating" content of a single html file, in such a way that locks them into a single section at a time. I want it so that when users scroll to the bottom of a section, it will slide up a prompt to move to the next page, which will fire a transition, such as different easing/from bottom and put them "in" the next section.
This would be repeated in the next section; when they scroll to the top, they will get a "previous" button but be unable to move unless they click "previous". If they hit the bottom, they will be unable to move to the next page without clicking "next". If they click a section tab, it would do the transition and bring them to that page from their current
I know that this will stop scrolling, but how do I modify it such that it will prevent scrolling in this way?
$('body').on({
'mousewheel': function(e) {
if (e.target.id == 'el') return;
e.preventDefault();
e.stopPropagation();
}
})
You can just have the window continue to scroll back to the element by using window.scrollTo.
I get the top bottom position and the height of the element, and then when the element is in view of the window I scollTo the difference between the window innerHeight and the elements position.
var el = document.querySelector('.stop');
window.addEventListener('scroll', function (e) {
var elementPos = el.getBoundingClientRect(),
elBot = elementPos.bottom,
elHeight = elementPos.height,
curTop = window.pageYOffset || document.documentElement.scrollTop;
if(elBot <= window.innerHeight-elHeight){
window.scrollTo(0,curTop-(window.innerHeight - elBot));
}
});
Live Demo
And a more complete example with clicking to move on, just to illustrate further.

Stop page from scrolling if hovering div [duplicate]

This question already has answers here:
Prevent scrolling of parent element when inner element scroll position reaches top/bottom?
(32 answers)
Closed 9 years ago.
I have a div that is scrollable, but whenever you reach the bottom/top of it, it begins to scroll the entire page. That could be annoying for users who scroll fast, and then the entire page starts scrolling unexpectedly.
I need something where if you are hovering over the div, the page is not scrollable.
I have tried this by adding CSS when I hover the div...
body {
overflow:hidden;
}
...It works but there is one problem. The scrollbar disappears and that looks kind of stupid to have it disappearing/reappearing. Any way to achieve the same effect but keep the scrollbar visible? I have seen it done with Facebook chat.
Here is a very simple way to stop the propagation with no plugins, just jQuery.
Update: The code has been updated to work correctly in IE9+. Have not tested in previous versions.
First, create a class on your <div> to mark it as having this behavior. In my example, I use the class .Scrollable.
<div class="Scrollable">
<!-- A bunch of HTML here which will create scrolling -->
</div>
The jQuery to disable is:
$('.Scrollable').on('DOMMouseScroll mousewheel', function(ev) {
var $this = $(this),
scrollTop = this.scrollTop,
scrollHeight = this.scrollHeight,
height = $this.height(),
delta = (ev.type == 'DOMMouseScroll' ?
ev.originalEvent.detail * -40 :
ev.originalEvent.wheelDelta),
up = delta > 0;
var prevent = function() {
ev.stopPropagation();
ev.preventDefault();
ev.returnValue = false;
return false;
}
if (!up && -delta > scrollHeight - height - scrollTop) {
// Scrolling down, but this will take us past the bottom.
$this.scrollTop(scrollHeight);
return prevent();
} else if (up && delta > scrollTop) {
// Scrolling up, but this will take us past the top.
$this.scrollTop(0);
return prevent();
}
});
In essence, what this does is to detect which direction the scrolling is being requested in (based on the originalEvent.wheelDelta: positive = up, negative = down). If the requested delta of the mousewheel event would move scrolling past the top or bottom of the <div>, cancel the event.
In IE, especially, scrolling events which go past a child element's scrollable area then roll up to parent elements, and the scrolling continues regardless of the event being canceled. Because we cancel the event in any case, and then control the scrolling on the child through jQuery, this is prevented.
This is loosely based on the way that this question solves the problem, but does not require the plugin, and is cross-browser compliant with IE9+.
Here is a working jsFiddle demonstrating the code in-action.
Here is a working jsFiddle demonstrating the code in-action, and updated to work with IE.
Here is a working jsFiddle demonstrating the code in-action, and updated to work with IE and FireFox. See this post for more details about the necessity of the changes.
maybe have a look to
How to disable scrolling temporarily?
This is a sample to stop and activate scroll

Categories