Force element to scroll when it is slightly off screen - javascript

I need an element to scroll into the screen when it is partially out of it. I already have a function that is detecting whether or not it is within the viewport, but I would like to bring the element completely into the viewport using its size. Think of it as a square element which is half way in the viewport, I would like to scroll in a way that will bring that element completely in.
This may be off to the side or above or beneath the current viewport. How do I scroll the element into the viewport when it is detected to be out?
Here is the current code:
const $target = $(evt.target) // this is the current target which will be tested whether or not is outside of the viewport
if (isOutsideOfViewport($target)) {
$target.scrollToBringTargetCompletelyToViewport() // how to make something like this work?
}
Edit: to show in more details what I am trying to do, I have drawn the following diagram.
As you can see, the target is slightly outside of the viewport. The objective is to bring the target completely in the viewport.
Before:
After:
This would happen no matter where the target is on the screen, I just want to scroll just enough for it to be completely within the viewport.

Related

Can Intersection observer be used to calculate/trigger at specific offset top of target?

TL,DR:
I don't care how much of the target container is visible, I just want to know when the target container reaches a specific offset from top of the viewport (window). Should I stick with the good old scroll event or can this be done with Intersection observer?
Long story:
For a project I need to create a vertical scrolling parallax effect (as seen on this page, when viewed on large screens).
The parallax animation needs to detect when the target container reaches a specific offset from top of the viewport. And it needs to know the scroll direction.
I've found this question that explains how the visibilty percentage can be used to determine the scoll direction, which solves my 2nd problem.
So my question is: Can I use Intersection observer to trigger a callback when my target container reaches a specific offset from top of the viewport?
In pseudo-code, I'd need something like this:
var observer = new IntersectionObserver(offsetReached, {root: null});
function offsetReached(entries, observer) {
entries.forEach(entry => {
if (entry.offsetFromTop == '200px') {
entry.target.classList.add('container--fixed');
}
});
}
observer.observe('.container');
Intersectionobserver's purpose is to detect when a portion of element becomes visible, if you want to watch for offSetthe best option is to use the old fashioned scroll event and getBoundingClientRect() on the element you need to watch on.
Use the rootMargin option on the IntersectionObserver:
var observer = new IntersectionObserver(offsetReached, {rootMargin: '-200px'});
Each side of the rectangle represented by rootMargin is added to the corresponding side in the root element's bounding box before the intersection test is performed. (MDN Web Docs: Intersection)Observer.rootMargin)

Parallax effect on an elements position only when in view

Similar to this unresolved question (jQuery - parallax - update background position correctly)
I am animating the transform property of an element on page scroll to achieve a parallax-like effect. I want this element to only begin animating up when it is in view. The problem now is that if the element appears further down the page, it has already moved up a lot and loses the effect.
Here is my code currently
function parallax() {
var scrolled = $(window).scrollTop();
$('[data-scroll]').css('transform', 'translateY('+-(scrolled*0.02)+'px)');
}
$(window).scroll(function(e){
parallax();
});
In answer to your question how to separate "parallax'ed" divs, so they shift their position independently from each other upon scrolling, one should rely on their unique coordinates - each one has it's own $(elem).offset().top - a general vertical offset from the top of the page (it's stays the same all the time unless you meddle with the TOP property manually).
so all calculation could be based against this property.
$('.parallax').each(function(){
if ($(this).is_on_screen()) {
var firstTop = $(this).offset().top;
var winScrollTop = $(window).scrollTop();
var shiftDistance = (firstTop - winScrollTop)*0.02;
$(this).css("transform":"translateY("+shiftDistance+"px)");
}
});
plus you check if the element is in the viewport. Thus, you assure it moves the same delta distance in its own time no matter where it's on the page - further down or up.
Another thing is that how to put "borders" of visibility of the element on the screen. If you are moving an element when it's in viewport, i would suggest making a wrapping div within which the movement occurs (like a bg moving within a div wrapper).
<div class="parallax-section slide1">
<span class="moving-block"></span>
</div>
div has a bigger height and we check when this div is on the screen, not the moving element.
demo
Also other modifications can be applied if one needs different speed, offset for each element. I found this plugin a good beginner stuff to learn parallax.
P.S. btw, all initial properties should be cached in variables instead of retrieving them each time in a callback, like firstTop for instance

Inability to scroll after turning div from absolute to fixed positioning using jquery

I have a div that gets a 'fixed' class added to it once the user scrolls past a certain point in the parent div. The fixed class simply changes the child div from absolute positioning to fixed positioning.
However, a problem occurs when the user scrolls to a certain point when the 'fixed' class is added (as specified by the 'begin variable' in the js). The user loses the ability to scroll up or down for a number of seconds. And to make matters more complicated, this problem only occurs on the first of six parent divs that uses this code.
Here's the jquery code that adds the 'fixed' class:
var begin = 164;
$("#portfolio_window").scroll(function () {
var y = $(this).scrollTop();
if (y >= begin) {
$('.details').addClass('fixed');
} else {
$('.details').removeClass('fixed');
}
});
If I change the 'begin' variable to something like 600, the user loses the ability to scroll around 600px from the top of the div.
You can try to reproduce the problem at http://dev.zachboth.com/
Here's the easiest way that I've been able to reproduce the problem:
Use Safari
Clicking 'Various Logos' in the 'Work' section
Scrolling down quickly once the 'Various Logos' section appears
It may take several attempts to actually have the problem occur
I can explain your problem:
The problem is that on the "page" you mention being broken has you scrolling in div#portfolio_window. The position:fixed element you mentioned is positioned relative to the window. When you scroll on that element, it's trying to scroll the window (not the parent div).
http://jsfiddle.net/NThY7/
The solution is a bit more involved. I'll hop back on later with a solution.

jQuery offset, position element under another, where the right borders touch of the aligned elements

Ok, the subject is not super specific to the overall need I am looking to address. So I have this function that is called on a given element, which is a hidden submenu next to a triggering element. The way the page renders, and to keep the styling optimized I can't just style the position in via css. So I need javascript/jquerys help.
With that I have come up with a function that I can reuse as needed, and works fine all around. However my key problem is, that I have a couple cases where the submenu will overlap the edge of the <section> element it resides in. Which that elements overflow is set to hidden, that and its also about 30 pixels from the bottom of the page anyway. All in all the submenu element gets hidden a bit by either falling completely out of the pages view half way through the element, or it gets hidden by the section tags overflow state.
With that. In a case where this happens I am wanting to instead of have the element align to the bottom of the trigger element, have it align to the top instead so that way the menu in that case is above the trigger element and not below.
Problem is Im not sure how to compensate for that.
Here is the function I came up with to do what I need, now I just need some help in a sense catching when the menu element falls off the page so to speak, so I can adjust for it when it does.
function openSubOrgMenu(triggerID, elem)
{
orgSubOpenID = triggerID;
orgSubShowing = true;
elemOffset = elem.offset(); //trigger element
elemWidth = elem.width();
elemHeight = elem.height();
elemWrap = elem.siblings('.org_group_wrapper');//menu element
elemWrapWidth = elemWrap.width();
elemWrapHeight = elemWrap.height();
moveTop = elemHeight + elemOffset.top + 4;
moveLeft = elemOffset.left - (elemWrapWidth-elemWidth-15);
elemWrap.show().offset({top:moveTop, left:moveLeft});
}
Well here is a JS Fiddle, not necessarily showing a working logic of what I want, but demonstrating the desired effect when its an element that at the bottom of the page/section:
http://jsfiddle.net/4zwEr/

How to see if an element in offscreen

I have a list of divs, and everytime I want to go to the next div I press a key. I need to check if that div is offscreen, and if so, I need to move the screen to show that div either using anchors or another method.
What is my best option for doing this?
Just to clairify, offscreen in my case means something that can't be seen right now without scrolling down. So if you are on the StackOverflow Home Page at the top, the last question on the entire page is offscreen.
Best option is to scroll your page to the element by getting its y-offset, and checking window height and calculating where to scroll page and then you can animate your page to that point.
//height of your div
var scroll = 250;
//animate from actual position to 250 px lower in 200 miliseconds
$(window).animate({"scrollTop": "+="+scroll+"px"}, 200);
so this is not the complete code but it might give you the idea.
check out jquery scrollTop
hope it helps,
Sinan.

Categories

Resources