When I click on <a class="Navigation" id="WorldHeader" href="#WorldTitle">Go to World</a>, my window put directly the div with the id directly on top. Is there a way to offset the window position when I click on the tag? My header is hiding the content, but I want to keep it.
Solution
Assuming based on the JQuery tag that, and using the reference of #WebMarie, the following solution must help you:
$('#WorldHeader').on('click', function(event) {
event.preventDefault(); // Prevent the default <a> action.
let myOffset = 50; // Pixels.
let newScrollPosition = $("#WorldTitle").offset().top - myOffset;
$('html, body').scrollTop(newScrollPosition); // Set the current vertical position of the scroll bar.
});
With animation:
$('#WorldHeader').on('click', function(event) {
event.preventDefault();
let myOffset = 50; // Pixels.
let animationDuration = 1000; // Miliseconds.
let newScrollPosition = $("#WorldTitle").offset().top - myOffset;
$('html, body').animate({
scrollTop: newScrollPosition // Set the current vertical position of the scroll bar.
}, animationDuration);
});
Example of use
$('#WorldHeader').on('click', function(event) {
event.preventDefault();
let myOffset = 50; // Pixels.
let animationDuration = 1000; // Miliseconds.
let newScrollPosition = $("#WorldTitle").offset().top - myOffset;
$('html, body').animate({
scrollTop: newScrollPosition // Set the current vertical position of the scroll bar.
}, animationDuration);
});
#WorldTitle {
margin: 20px 0;
width: 100%;
height: 150px;
background-color: red;
}
.blue {
width: 100%;
height: 500px;
background-color: blue;
}
.green {
width: 100%;
height: 500px;
background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<a class="Navigation" id="WorldHeader" href="#WorldTitle">Go to World</a>
<div class="blue"></div>
<div id="WorldTitle"></div>
<div class="green"></div>
Related
What's wrong with my code? scrollTo() goes to the wrong position when I click and anchor with href value using hash # (div element ID).
This is my code, I just want to scroll to the comment element, but still overlap on the fixed header (bootstrap 5 fixed header).
if (document.querySelectorAll('a').length) {
document.querySelectorAll('a').forEach( anchor => {
anchor.addEventListener('click', event => {
let URL = event.target.href.split('#');
if (typeof URL[1] != undefined) {
let element = document.getElementById(URL[1]);
let offset = element.offsetTop;
let navigation = document.getElementById('main-navigation').clientHeight
let scroll = offset - navigation;
window.scrollTo(0, scroll);
}
});
});
}
Anyone can help me?
Call event.preventDefault() in the click handler, otherwise after your call to scrollTo, the page's hash will change, with an automatic scroll to the anchored element overriding yours.
document.querySelectorAll('a').forEach( anchor => {
anchor.addEventListener('click', event => {
let URL = event.target.href.split('#');
if (typeof URL[1] != undefined) {
let element = document.getElementById(URL[1]);
let offset = element.offsetTop;
let navigation = document.querySelector('.over').clientHeight
let scroll = offset - navigation;
window.scrollTo(0, scroll);
event.preventDefault(); // avoid internal scroll to anchor
}
});
});
.over {
height: 50px;
background: salmon;
position: sticky;
top: 0;
}
#foo {
margin-top: 250vh;
height: 250vh;
}
#foo
<div class="over"></div>
<div id="foo">Target element</div>
You can achieve that by using the scrollIntoView() function. see the below example. you have to target the element to scroll:
let i = 0;
function myFunction() {
if(i === 0){
const elmnt = document.getElementById("content");
elmnt.scrollIntoView();
i += 1
}
else {
const elmnt = document.getElementById("content2");
elmnt.scrollIntoView();
}
}
#myDIV {
height: 250px;
width: 250px;
overflow: auto;
background: green;
}
#content {
margin:500px;
height: 800px;
width: 2000px;
background-color: coral;
}
#content2 {
margin:500px;
height: 800px;
width: 2000px;
background-color: red;
}
<p>Click the button to scroll to section.</p>
<button onclick="myFunction()">Scroll</button>
<div id="myDIV">
<div id="content">
Some text inside an element.
</div>
<div id="content2">
Some text inside an element.
</div>
</div>
Most importantly you need to stop the default behavior. When an internal link is clicked the default action is to jump to that link. You need to override that.
Next, we can make a couple of little tweaks. First, only select internal links with an attribute selector that selects a tags where the href start with "#". Next, instead of splitting the url from the href, grab the raw value directly from the attribute.
//Get internal links
document.querySelectorAll("a[href^='#']").forEach(function(el) {
el.addEventListener("click", function(e) {
//Stops the inbuild scroll
e.preventDefault();
//Get the id straight from the attribute
let selector = this.getAttribute("href");
//Get the target element
let element = document.querySelector(selector);
//you know the rest
let offset = element.offsetTop;
let navigation = document.getElementById('main-navigation').clientHeight
let scroll = offset - navigation;
window.scrollTo(0, scroll);
});
});
/*CSS Purely for demo purposes.*/
.fixed-top {
background-color: #EEE;
padding: 15px;
}
article:first-of-type{
margin-top:90px;
}
article {
min-height: 50vh;
border-bottom: 1px solid black;
}
nav {
background-color: #ECECEC;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<div class="fixed-top" id="main-navigation">Some Top Stuff
<nav>
Article 1
Article 2
Article 3
</nav>
</div>
<article id="art1">
<h1>Article 1</h1>
</article>
<article id="art2">
<h1>Article 2</h1>
</article>
<article id="art3">
<h1>Article 3</h1>
</article>
I have written the following code to scroll an element 20 more pixels to the right.
const button = document.getElementById('slide');
button.onclick = function () {
document.getElementById('container').scrollLeft += 20;
};
How can I make the scrolling smooth? I have tried using Element#scroll like so:
const button = document.getElementById('slide');
button.onclick = function () {
document.getElementById('container').scroll({
left: += 20,
behavior: smooth
});
};
Am I able to do this?
You can use Element#scrollBy to scroll a certain amount from the current position.
button.onclick = function () {
document.getElementById('container').scrollBy({
left: 20,
behavior: 'smooth'
});
};
Is this what you are looking for?
From MDN:
scrollBy() scrolls by a particular amount, whereas scroll() scrolls to an absolute position in the document.
https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollBy
const container = document.querySelector("#container");
const button = document.querySelector("#btnScroll");
button.addEventListener('click', e => {
container.scrollBy({
left: 200,
behavior: 'smooth'
});
});
#container {
position: relative;
max-width: 200px;
overflow-x: scroll;
display: flex;
margin: 20px;
}
img {
display: inline-block
}
<div id="container">
<img src="https://dummyimage.com/200x100/000/fff">
<img src="https://dummyimage.com/200x100/0f0/000">
<img src="https://dummyimage.com/200x100/00f/fff">
<img src="https://dummyimage.com/200x100/f00/fff">
</div>
<button id="btnScroll">Scroll 200px</button>
I want the nav to hide scrolling down 60px and to show when scrolling up 60px, no matter in which part of the page.
I did this, but it's incomplete, what am I missing?
<script>
let y = 0;
</script>
<svelte:window bind:scrollY="{y}" />
<nav class:hideNav={y > 60}>
<ul>
<li>link</li>
</ul>
</nav>
<style>
nav {
position: fixed;
top: 0;
}
.hideNav {
top: -70px;
}
</style>
Your code seems to perfectly hide the navbar after you scroll the specified amount, here is a REPL of your code in action. maybe the body of your content has no scroll ?
here is another implementation REPL that further elaborates how to use scrolling position
<script>
import {onMount, onDestroy} from 'svelte'
const scrollNavBar = 60
let show = false
onMount(() => {
window.onscroll = () => {
if (window.scrollY > scrollNavBar) {
show = true
} else {
show = false
}
}
})
onDestroy(() => {
window.onscroll = () => {}
})
</script>
<style>
.scrolled {
transform: translate(0,calc(-100% - 1rem))
}
nav {
width: 100%;
position: fixed;
box-shadow: 0 -0.4rem 0.9rem 0.2rem rgb(0 0 0 / 50%);
padding: 10px;
transition: 0.5s ease
}
:global(body) {
margin: 0;
padding: 0;
height: 200vh;
}
</style>
<nav class:scrolled={show}>
elemnt
</nav>
In your REPL, it seems like the nav does not reappear on scrolling up. It does appear only at the top of the page.
I am also trying to show the nav when the user scrolls up by 30px anywhere on the page, for instance. I think that it was what OP is asking as well.
I found a REPL successfully doing it with jQuery but I am struggling to make it work in Svelte at the moment. Any clue?
I will revert back if I succeed.
// Hide Header on on scroll down
var didScroll;
var lastScrollTop = 0;
var delta = 5;
var navbarHeight = $('header').outerHeight();
$(window).scroll(function(event){
didScroll = true;
});
setInterval(function() {
if (didScroll) {
hasScrolled();
didScroll = false;
}
}, 250);
function hasScrolled() {
var st = $(this).scrollTop();
// Make sure they scroll more than delta
if(Math.abs(lastScrollTop - st) <= delta)
return;
// If they scrolled down and are past the navbar, add class .nav-up.
// This is necessary so you never see what is "behind" the navbar.
if (st > lastScrollTop && st > navbarHeight){
// Scroll Down
$('header').removeClass('nav-down').addClass('nav-up');
} else {
// Scroll Up
if(st + $(window).height() < $(document).height()) {
$('header').removeClass('nav-up').addClass('nav-down');
}
}
lastScrollTop = st;
}
The answers here couldn't help me. So here's a REPL I made for what I'm using to achieve this in svelte:window.
How I did it;
Create a variable that will store the scroll position (in px) at the end of the scroll event - [let's call it lastScrollPosition].
let lastScrollPosition = 0
At the beginning of a scroll event; inside svelte:window, get and compare the current scroll position to the last scroll position variable we created in [1.] (lastScrollPosition)
<svelte:window on:scroll={()=>{
var currentScrollposition = window.pageYOffset || document.documentElement.scrollTop; //Get current scroll position
if (currentScrollposition > lastScrollPosition) {
showNav = false
}else{
showNav = true
}
lastScrollPosition = currentScrollposition;
}}></svelte:window>
If current scroll Position is greater than lastScrollPosition, showNav is false else, true.
NB: You can use CSS or Svelte Conditional ({#if}) to achieve the hide on scroll down and show on scroll up (This example shows CSS..).
<main>
<div class="nav {showNav == true? "show": "hide" }" >
Nav bar
</div>
<div class="content">
Content
</div>
</main>
<style>
.nav{
background-color: gray;
padding: 6px;
position: fixed;
top: 0;
width: 100%;
}
.content{
background-color: green;
margin-top: 25px;
padding: 6px;
width: 100%;
height: 2300px;
}
.hide{
display: none;
}
.show{
display: unset;
}
</style>
I want to create scroll to section like nexus5 website https://www.google.com/nexus/5/
i.e. one button doing all. Click on one button it takes you down to different sections and when it reaches last ID it scrolls all the way up back.
JS
if(window.location.hash !=""){
var scrollIdPrev = "#"+$(""+ window.location.hash +"").prev(".slide").attr("id")+"";
var scrollIdNext = "#"+$(""+ window.location.hash +"").next(".slide").attr("id")+"";
$('html, body').animate({
scrollTop: $(""+window.location.hash+"").offset().top
}, 2000,function(){
window.location.href=scrollId;
$(".previous").attr("data-target",scrollIdPrev);
$(".next").attr("data-target",scrollIdNext);
});
}
$('.next').click(function(){
var scrollId = "#"+$(""+ $(this).attr("data-target") +"").next(".slide").attr("id")+"";
$('html, body').animate({
scrollTop: $(""+scrollId+"").offset().top
}, 2000,function(){
window.location.href=scrollId;
$(".previous").attr("data-target",scrollId);
$(".next").attr("data-target",window.location.hash);
});
});
$('.previous').click(function(){
var scrollId = "#"+$(""+ $(this).attr("data-target") +"").prev(".slide").attr("id")+"";
$('html, body').animate({
scrollTop: $(""+scrollId+"").offset().top
}, 2000,function(){
window.location.href=scrollId;
$(".next").attr("data-target",scrollId);
$(".previous").attr("data-target",window.location.hash);
});
});
HTML
<div class="move">
<div class="previous" data-target="#one">UP</div>
<div class="next" data-target="#one">DOWN</div>
</div>
<section class="slide" id="one">First</section>
<section class="slide" id="two">Second</section>
<section class="slide" id="three">Third</section>
<section class="slide" id="four">Fourth</section>
CSS
section{
height: 400px;
border: 1px solid black;
}
.move{
position: fixed;
bottom: 0;
right: 0;
}
.previous, .next
{
background: red;
height: 20px;
width: 70px;
margin-bottom: 5px;
cursor: pointer;
}
Fiddle
I have achieved some functionality but not all.
Just use the scrollIntoView() function everytime you want to scroll to the next element.
Just have an array of elements you want to go to and just save the pointer in a global variable.
window.scroll=0;
window.navigationpoints=['id1','id2','id3'];
$('.next').click(function(){
if(window.scroll<window.navigationpoints.length){
document.getElementById(window.navigationpoints[window.scroll]).scrollIntoView();
window.scroll++;
}else {
document.getElementById(window.navigationpoints[0]).scrollIntoView();
window.scroll=1;
}
});
how do I find out if the user scrolled up to the top or down to the bottom in a scrollable container?
Does jQuery offer any mechanisms?
css:
#container {
display: block;
width: 250px;
height: 25px;
background: green;
}
#scrolling {
width: 250px;
height: 300px;
backround: red;
overflow: auto;
}
http://jsfiddle.net/Hmaf2/2/
Thanks a lot!
Pat
$('#somediv').scrollTop()
will tell you the position from the top
-edit-
$('#somediv').scroll(function(){
if($('#somediv').scrollTop()==0){
console.log('top')
}
})
Yes you can access the current scroll top value of a scrollable container.
Here working is jsFiddle.
$('#scrolling').scroll(function() {
var scrollTop = $(this).scrollTop();
console.log(scrollTop);
});
You can test the scroll position by comparing the height, scrollable height and scroll offset of the div:
$(document).ready(function(){
$('#scrolling').scroll(function(){
var scrollTop = $(this).scrollTop();
var iheight = $(this).innerHeight();
var sheight = this.scrollHeight;
var text = '';
if (scrollTop <= 5) {
text = 'top';
}
else if (scrollTop+5 >= sheight-iheight) {
text = 'bottom';
}
else {
text = scrollTop+' middle ('+iheight+','+sheight+')';
}
$('#result').text(text);
});
});
fiddle
This example has reserved 5 pixels from the top and bottom of the div's margin.