I would like to center a div by clicking it. So if I'm clicking a div I want it to scroll to the center of the browser viewport. I don't want to use anchor points like the guides and examples I've seen. How can I achieve this?
In some way you have to identify the clickable elements. I build an example, that uses the class-attribute for that.
Step 1
This is the script, that does the work:
$('html,body').animate({
scrollTop: $(this).offset().top - ( $(window).height() - $(this).outerHeight(true) ) / 2
}, 200);
What you tried is to scroll the container to the top of the page. You also have to calculate and subtract the difference between the container height and the viewport height. Divide this by two (as you want to have the same space on top and bottom and you are ready to go.
Step 2
Then you add the click handler to all the elements:
$(document).ready(function () {
$('.image').click( function() {
$('html,body').animate({ scrollTop: $(this).offset().top - ( $(window).height() - $(this).outerHeight(true) ) / 2 }, 200);
});
});
Step 3
Set up some HTML/CSS:
<style>
div.image {
border: 1px solid red;
height: 500px;
width: 500px;
}
</style>
<div class="image">1</div>
<div class="image">2</div>
<div class="image">3</div>
<div class="image">4</div>
<div class="image">5</div>
And you're done.
Check out the demo
Try it yourself http://jsfiddle.net/insertusernamehere/3T9Py/
HTMLElement.prototype.scrollToCenter = function(){
window.scrollBy(0, this.getBoundingClientRect().top - (window.innerHeight>>1));
}
Achieved with pure JavaScript for Scrolling to Center in the vertical direction. And it's similar in the horizontal direction.
I don't take elements' height into consideration, because they maybe larger than the height of screen.
I know this question is old, but right now, you can use scrollIntoView:
For example:
document.body.scrollIntoView({
behavior: 'smooth',
inline: 'center',
block: 'center'
});
I've got one slight modification to offer.
If the "adjustment factor" i.e. ( $(window).height() - $(this).outerHeight(true) ) / 2 is < 0 you can get undesirable results whereby you overshoot that element in the viewport with your scroll.
I added a max(0,adjustment factor) to correct :
function scrollIntoView(el) {
var offsetTop = $j(el).offset().top;
var adjustment = Math.max(0,( $j(window).height() - $j(el).outerHeight(true) ) / 2);
var scrollTop = offsetTop - adjustment;
$j('html,body').animate({
scrollTop: scrollTop
}, 200);
}
Related
I have a button that scrolls to another element. This works fine on desktop but on mobile if I scroll a little bit and click the button, the function does not scroll precisely to the element I want but is a bit off, even though I didn't specify any offset.
On desktop I have a fixed menu that changes size, so that is why in below code I check for desktop or mobile using the window width:
if(window.outerWidth > 991) {
console.log('desktop');
$("body").on("click","#bestellenbtn",function(){
var scrollmenuheight = $('.scrollmenu').height();
$([document.documentElement, document.body]).animate({
scrollTop: $("#bestellen").offset().top - scrollmenuheight
}, 1000);
});
}else{
console.log('mobile');
$("body").on("click","#bestellenbtn",function(){
$([document.documentElement, document.body]).animate({
scrollTop: $("#bestellen").offset().top
}, 1000);
});
}
This is the button that starts the function:
<button class="btnstyle blue-inverse" type="button" name="button">Bestellen</button>
And the element:
<div class="separator" id="bestellen">
<div class="container">
<div class="row">
<div class="col-md-12">
<h2>Bestellen</h2>
</div>
</div>
</div>
</div>
I added a copy of the page in a codepen so you can see it for yourself (click the first of 4 blue buttons on mobile view):
https://codepen.io/twan2020/pen/RwGmaMQ You can resize to get the mobile version.
What can I do?
I've tried changing the offset but that shouldn't be necessary because on mobile there is no fixed menu that changes the height of the document.
I made a short video to show what the problem is:
https://gyazo.com/431163072afb0de9a6488ebfba895ff5
Use the if-statement inside the function that handels #bestellenbtn click.
Use window.innerWidth instead of window.outerWidth. However, For compatibility reason, it is better that you use the following code instead.
var viewportWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); .
On mobile, use Element.scrollIntoView() with smooth behaviour. Let JS rules.
Element.scrollIntoView()
The Element interface's scrollIntoView() method scrolls the element's
parent container such that the element on which scrollIntoView() is
called is visible to the user. MDN - Element.scrollIntoView()
document.querySelector("#bestellen")
.scrollIntoView({block: "start", behavior: "smooth"})
$("body").on("click","#bestellenbtn",function(){
var viewportWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
if(viewportWidth > 991) {
console.log('desktop');
var scrollmenuheight = $('.scrollmenu').height();
$([document.documentElement, document.body]).animate({
scrollTop: $("#bestellen").offset().top - scrollmenuheight
}, 1000);
}else{
console.log('mobiel');
document.querySelector("#bestellen")
.scrollIntoView({block: "start", behavior: "smooth"})
}
});
Update.
Do you have an idea why on desktop when I click, the animation is not
instant but only starts after about 1 second? Maybe the function is
too heavy?
That is probably because of animation duration. Try using 300 or 700 as timeout for the animate function.
If you need a similar behaviour as on mobile, use window.scrollTo with smooth behaviour.
Window.scrollTo() scrolls to a particular set of coordinates in the
document. - MDN - Window.scrollTo()
$("body").on("click","#bestellenbtn",function(){
var viewportWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
if(viewportWidth > 991) {
console.log('desktop');
var scrollmenuheight = $('.scrollmenu').height();
var offsetTop = $("#bestellen").offset().top - scrollmenuheight;
window.scrollTo({
top: offsetTop,
behavior: 'smooth'
});
}else{
console.log('mobiel');
document.querySelector("#bestellen")
.scrollIntoView({block: "start", behavior: "smooth"})
}
});
On mobile, it scroll faster because the distance between #bestellenbtn and #bestellen is more than the distance between those two elements on desktop.
From your question what I have understood is you want to scroll down to a particular section of your page on clicking an item in the menu. This can very easily be done with HTML. In your href of the link element replace javascript:void(0); with the id of the element where you want to scroll to i.e. #bestellen. Check my pen here. Once you click One, Two, Three or Four then you will be scrolled to that particular section.
html {
scroll-behavior: smooth;
}
I created a parallax effect, as it was described here:
Is there a way to make parallax work within a DIV
This method works pretty well, but I have a problem with it. My page is basically composed of alternating DIVs. White DIVs with text and DIVs with a picture in it, which moves with the parallax effect. This works pretty well, unless, that I have to manually adjust the position of each picture DIV. Here is the code from the header:
<script type="text/javascript">
$(window).scroll(function () {
parallax();
});
function parallax() {
var ev = {
scrollTop: document.body.scrollTop || document.documentElement.scrollTop
};
ev.ratioScrolled = ev.scrollTop / (document.body.scrollHeight - document.documentElement.clientHeight);
render(ev);
}
function render(ev) {
var t = ev.scrollTop;
var y = Math.round(t * 2/3) - 100;
$('#ff-section01').css('background-position', 'center ' + y + 'px');
$('#ff-section03').css('background-position', 'center ' + (y - 1000) + 'px');
$('#ff-section05').css('background-position', 'center ' + (y - 1700) + 'px');
$('#ff-section07').css('background-position', 'center ' + (y - 2750) + 'px');
}
</script>
As you can see, each section got another vertical position in the background-position value at the bottom. 0, 1000, 1700, 2750. This works well so far, but as soon as the intermediate Text DIVs change in height, this method doesn't work, as the value is always calculated from the top of the page. The HTML of one section looks like this:
<div class="ff-section03" id="ff-section03"></div>
So very simple, and combined with the CSS:
.ff-section03 {
width: 100%; height: 550px;
position: relative;
background: url('system/urbansolutions.jpg') center -300px no-repeat;
}
Also very simple. What can I do, that the calculations are not dependent of the page height? I basically don't want to subtract a superficial number from the background-position, so that the parallax effect works, not dependent of the location on the website.
Thanks a lot!
Sebastian
I'm working on my Tumblr blog and have the following CSS set:
img
{
max-height: calc(100% - 60px);
margin-top:30px;
}
so the margins (top and bottom) are both 30px.
I'm trying to add two buttons prev and next that will, when clicked, scroll the page up or down (100% - 60px).
This is the JS I have:
$(function() {
$("#next").on("click", function() {
$("body").animate({"scrollTop": window.scrollY+100}, 100);
return false;
});
});
$(function() {
$("#previous").on("click", function() {
$("body").animate({"scrollTop": window.scrollY-100}, 100);
return false;
});
});
And here's my fiddle: https://jsfiddle.net/cztqjwb2/1/
Any help would be greatly apreciated.
Thanks.
PS: also I don't know why it work only on Safari.
$("body").animate({"scrollTop": window.scrollY + 100}, 100);
This scrolls to current position + 100px. Assuming by 100% - 60px you mean window height - 60px (as opposed to document height), replace that 100 with (window.innerHeight - 60).
$("body").animate({"scrollTop": window.scrollY + window.innerHeight}, 100);
I updated your fiddle accordingly.
I want to scroll to a specific target in my application - something like this:
var editor = self.$el.find(".editorWrapper[data-containerid=" + containerId + "]").closest('.containerWrapper');
$('html, body').animate({
scrollTop: editor.position().top-5
}, 1000);
The problem is, that there are elements which render while scrolling down -> e.g. an image or iframe gets rendered while it scrolls down.I don't know the height of that new rendered element (would be tough to get the height - but not impossible so) the scroll stops at a wrong position. Is there an easy way to scroll smoothly to an element while the offset/height changes other then saving the height of each "new rendered" element?
I would just scroll down until it actually finds the specific point. Example:
function ScrollTo(el) {
if ($('html').scrollTop() < (el.position().top - 5)) {
$('html').animate({
scrollTop: $('html').scrollTop() + 1
}, 1, 'swing', function() {
ScrollTo(el);
});
}
}
ScrollTo($('#scrollTo'));
div {
width:400px;
}
#large {
height:400px;
background:red;
}
#scrollTo {
height:400px;
background:green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="large"></div>
<div id="scrollTo"></div>
You could play around with the settings to make it scroll at a decent speed for you, etc.
You want your page to be fully loaded you can call you script in :
$(document).load(function () {
var editor = self.$el.find(".editorWrapper[data-containerid=" + containerId + "]").closest('.containerWrapper');
$('html, body').animate({
scrollTop: editor.position().top-5
}, 1000);
});
https://api.jquery.com/load-event/
The scroll position is probably going to change everytime an image/iframe gets rendered, so the best way is binding load events to such elements (image/iframe) that updates the scrollTop position.
I have navigation nested in a div that is offscreen to the left and when the user scrolls down the page and reaches pixel 296, the left navigation slowly appears by it's width growing towards the right.
What I have now is half working. The navigation nested in the div appears when the user scrolls down the page but I want it to animate slowly to the right and that is not happening. Not sure what I am doing wrong. The specific line I am having problems with is:
$("#slidebottom").animate({ width: "100" }, 'slow');
But here is my entire code:
$(window).scroll(function(){
var wintop = $(window).scrollTop(), docheight = $(document).height(),
winheight = $(window).height();
var bottomHeight = $("#slidebottom").height();
var zeroheight = 0;
if (wintop > 296) {
bottomHeight = $('#slidebottom').height(docheight);
$("#slidebottom").animate({ width: "100" }, 'slow');
}
if( wintop < 296)
{
bottomHeight = $('#slidebottom').height(zeroheight);
//$("#slidebottom").animate({ width: "0" }, 'slow');
}
});
The jQuery docs show ints, not strings, as the arguments to width:
$("#slidebottom").animate({ width: 100 }, 'slow');
Edit: So I was wrong, that's not the problem; it handles strings just as well.
Try the following maybe?
$("#slidebottom").animate({ width: '100px' }, 'slow');
I have a feeling that the unit is important for this, since 100 can mean anything. Not very specific. And you can define this as a string just fine. In fact, in the example they give for .animate it is defined as a string.