How to make "scroll to top" JS function go slower in JQuery - javascript

How can I edit this code from W3 schools to make it scroll slower by only using JQuery? It currently just jumps to the top. Is there a way to slow it down so the user can see that they are actually going back up to the top of the page? Ideally the entire thing should be in JQuery if possible.
https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_scroll_to_top
//Get the button
var mybutton = document.getElementById("myBtn");
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
mybutton.style.display = "block";
} else {
mybutton.style.display = "none";
}
}
// When the user clicks on the button, scroll to the top of the document
function topFunction() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}
body {
font-family: Arial, Helvetica, sans-serif;
font-size: 20px;
}
#myBtn {
display: none;
position: fixed;
bottom: 20px;
right: 30px;
z-index: 99;
font-size: 18px;
border: none;
outline: none;
background-color: red;
color: white;
cursor: pointer;
padding: 15px;
border-radius: 4px;
}
#myBtn:hover {
background-color: #555;
}
<body>
<button onclick="topFunction()" id="myBtn" title="Go to top">Top</button>
<div style="background-color:black;color:white;padding:30px">Scroll Down</div>
<div style="background-color:lightgrey;padding:30px 30px 2500px">This example demonstrates how to create a "scroll to top" button that becomes visible
<strong>when the user starts to scroll the page</strong>.</div>

Edit for Pure jQuery
You're looking for the jQuery .animate() method. Check out:
https://www.w3schools.com/howto/howto_css_smooth_scroll.asp#section2
They're using this.hash to find the destination of the smooth scroll. You can omit it, and replace with '0' for scroll-to-top. If you're new to this.hash, look at:
How does $(this.hash) work?
Add jQuery to your html head with:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
and replace your topFunction with:
function topFunction() {
$('html, body').animate({
scrollTop: 0
}, 500);
}
'500' is the duration of the scroll animation in milliseconds.

You can try using scrollTo with the smooth behavior https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTo#examples
Though it doesn't work on Safari (I see it works only from Safari 14 and on now), for safari you need to add a polyfill https://github.com/iamdustan/smoothscroll

Just expand your scrollTop call like that:
window.scrollTo({top: 0, behavior: 'smooth'});

Related

The page is shaking when scrolling down if use document.documentElement.scrollTop

First of all, I can only use vanilla javascript for the current project.
Run my codes below, there are 3 sections, I want to fix the second black section when it reached the top of the screen, but now the issue is if you use mouse wheel or touchpad scroll down the page, you will see the page is shaking.
I tried many ideas but can't fix this issue, hope anyone can give a solution or correct direction. Thanks!
window.addEventListener('wheel', function(e) {
var nextSection = document.querySelector('#next-section');
var fixedSection = document.querySelector('#fixed-section');
var doc = document.documentElement;
//When scroll down
if (doc.scrollTop >= nextSection.offsetTop - window.innerHeight) {
doc.scrollTop = nextSection.offsetTop - window.innerHeight;
}
});
.section {
width: 100%;
height: 400px;
line-height: 400px;
background: #ccc;
text-align: center;
padding-top: 20px;
}
#fixed-section {
background: #000;
color: #fff;
}
<div id="previous-section" class="section">Just scroll down</div>
<div id="fixed-section" class="section">Fix this section when it reached the top of the viewport.</div>
<div id="next-section" class="section"></div>

Transition to a scroll back to top button

I created a button on my site to scroll back to the top of my page by following this tutorial: W3Schools
The problem is that when you click on the button, there is no transition to the top, you are just "teleport" to the top of the page. So if someone will know how to improve the transition or how to make a button otherwise.
HTML code :
<button onclick="topFunction()" id="myBtn" title="Go to top">Top</button>
CSS code :
#myBtn {
display: none; /* Hidden by default */
position: fixed; /* Fixed/sticky position */
bottom: 20px; /* Place the button at the bottom of the page */
right: 30px; /* Place the button 30px from the right */
z-index: 99; /* Make sure it does not overlap */
border: none; /* Remove borders */
outline: none; /* Remove outline */
background-color: red; /* Set a background color */
color: white; /* Text color */
cursor: pointer; /* Add a mouse pointer on hover */
padding: 15px; /* Some padding */
border-radius: 10px; /* Rounded corners */
font-size: 18px; /* Increase font size */
}
#myBtn:hover {
background-color: #555; /* Add a dark-grey background on hover */
}
JavaScript code :
//Get the button:
mybutton = document.getElementById("myBtn");
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
mybutton.style.display = "block";
} else {
mybutton.style.display = "none";
}
}
// When the user clicks on the button, scroll to the top of the document
function topFunction() {
document.body.scrollTop = 0; // For Safari
document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
}
You can do this either by adding scroll-behavior: smooth; to your html styles or by using the window scrollTo method with the option behavior: 'smooth' in your Javascript:
window.scrollTo({
top: 0,
left: 0,
behavior: 'smooth'
});
try this in your topFunction(), it should work definitely. You can set a callback function for the animate command.
I have tested in my localhost and it works like a charm.
Hope that will help you.
function topFunction() {
var body = $("html, body");
body.stop().animate({scrollTop:0}, 500, 'swing', function() {
console.log("Animation has finished");
});
}
Follow the structure that I given below.
<!Doctype html>
<html>
<head>
<!--Add the CSS Code here-->
<style>
</style>
</head>
<body>
<!--Add more text here-->
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum....</p>
<button onclick="topFunction()" id="myBtn" title="Go to top">Top</button>
</body>
<script>
<!--Add the JavaScript Code here-->
</script>
</html>```
Then just run the code.

Make hidden div appear on scroll in WordPress

there are several posts about this, but for some reason, I can't seem to get it to work. I have a floating button that I would like to appear while scrolling. I've added the script to my header and css. Not sure what I'm doing wrong here.
Some posts I've tried to work with:
Show div on scrollDown after 800px
Make div appear on scroll in wordpress
Make <div> appear upon scrolling
--PHP--
add_action('wp_header', 'subscribe_float');
function subscribe_float() {
?>
<script type="text/javascript">
jQuery(function($) {
$(document).scroll(function () {
var y = $(this).scrollTop();
if (y > 50) {
$('#custom_html-12').slideDown();
} else {
$('#custom_html-12').slideUp();
}
});
});
</script>
<?php } ?>
--CSS--
#custom_html-12 {
background: #fbbd14;
position: fixed;
bottom: 55px;
z-index: 999;
right: 20px;
padding: 5px;
color: #fff;
border-radius: 4px;
display: none;
}
The hook is wp_head, not wp_header. Thus, your code should be:
add_action('wp_head', 'subscribe_float');

Javascript causing mobile navigation to require a 'double tap for links to work

I've noticed on the mobile version (iOS) of my website that the main navigation requires links to be tapped twice for the page to redirect. After removing various styles/bits of code I found the cause of the problem, it's my Javascript for a 'sliding line' hover effect.
My basic understanding would be that as the script is still running on mobile, when it's not really needed, it means the navigation is running/expecting a hover effect and once that's run you can then click a link as you intend?
The script works perfect on desktop, so I don't want to change any of the functionality but is there something I can add to prevent this bug on mobile devices? Alternatively, would a javascript 'media query' type thing, stopping the script from running below 1000px be a better solution? If so what would be the best way to implement that?
Thank in advance!
CodePen: https://codepen.io/moy/pen/pZdjMX
$(function() {
var $el,
leftPos,
newWidth,
$mainNav = $(".site-nav__list");
$mainNav.append("<div class='site-nav__line'></div>");
var $magicLine = $(".site-nav__line"),
$currentMenu = $(".current-menu-item");
$magicLine
.width($currentMenu.length ? $currentMenu.width() : 0)
.css("left", $currentMenu.length ? $currentMenu.find("a").position().left : 0)
.data("origLeft", $magicLine.position().left)
.data("origWidth", $magicLine.width());
var hoverOut;
$(".site-nav__list li a").hover(function() {
clearTimeout(hoverOut);
$el = $(this);
leftPos = $el.position().left;
newWidth = $el.parent().width();
if (!$magicLine.width()) {
$magicLine.stop().hide().css({
left: leftPos,
width: newWidth
}).fadeIn(100);
} else {
$magicLine.stop().animate({
opacity: 1,
left: leftPos,
width: newWidth
});
}
},
function() {
hoverOut = setTimeout(function() {
if (!$currentMenu.length) {
$magicLine.fadeOut(100, function() {
$magicLine.css({
left: $magicLine.data("origLeft"),
width: $magicLine.data("origWidth")
});
});
} else {
$magicLine.stop().animate({
left: $magicLine.data("origLeft"),
width: $magicLine.data("origWidth")
});
}
}, 100);
}
);
});
/* Header */
.page-head {
background: white;
border-top: 2px solid #ddd;
box-sizing: border-box;
overflow: hidden;
padding: 0 30px;
position: relative;
width: 100%;
}
.page-head__logo {
background-image: none;
float: left;
padding: 0;
text-shadow: none;
width: 200px;
}
/* Nav */
.site-nav {
display: block;
float: right;
text-align: center;
width: auto;
}
.site-nav__list {
list-style: none;
margin: 0;
padding: 0;
position: relative;
top: auto;
left: auto;
width: auto;
}
.site-nav__list li {
background: none;
display: block;
float: left;
margin: 0;
padding-left: 0;
text-transform: uppercase;
}
.site-nav__list a {
box-sizing: border-box;
display: block;
font-weight: 900;
padding: 30px 15px;
transition: color .15s;
text-shadow: none;
}
.site-nav__list a {
color: red;
}
/* Underline */
.site-nav__line {
background: red;
content: "";
display: block;
height: 2px;
position: absolute;
top: -2px;
left: 0;
width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<header class="page-head">
Logo Here
<nav class="site-nav ">
<ul class="site-nav__list">
<li class="site-nav__item ">About</li>
<li class="site-nav__item">Looooonger Title</li>
<li class="site-nav__item">Company</li>
<li class="site-nav__item">About</li>
<li class="site-nav__item">Login</li>
<li class="site-nav__item">Apply</li>
</ul>
</nav>
</header>
</body>
if your problem is you to double click it before redirecting to its page, Try thi
$('.site-nav__list a').click(function(){
$(this).click();
});
the function is when you click the navigation the script will click it again,
If you're sure that the cause of the problem is running that script on mobile screens, you can call sliding script only on desktops with this code:
if ( $(window).width() > 739) {
//Desktop scripts
}
else {
//mobile scripts
}
You can change the screen width of devices you want to script work on them by changing 739. After that your script will run only on screens larger that 739px or what you've choose.
Update
If you want to everything works correct after resizing, You should do a little trick.
Personally, I use this method because it's the only way that makes you sure about bugs and problems. The trick is reloading the page after resizing.
It's not costly in many cases because most of the things cashed and don't need to redownloading. There are lots of methods to do that, but I use the below one because it works good and is simple and short:
window.onresize = function () {
location = location;
}
You just need to add this lines at the end of your script file. After resizing, everything will work well again.
How it works?
When you resize the window, a javascript event will emit. What we done in the last code is overriding the event listener of that event. So when the user resize the window, the location = location; code will execute.
What this line means? the location object is a property of window object and keeping information about current window url. When you change the location of a window, browser page will reload to getting the new window of the new location (more info about location).
What we done here is assigning current location to the location. So browser thinks we had a redirect request and reloads the page. But because the new location is the same object as previous one, the page will reload instead of redirecting to somewhere else.

Forcing mobile devices to activate :hover CSS properties on first touch and activate link on second touch

: )
So, I'm trying to solve a hover effect issue. I have tooltips on some of my links. Code looks like this:
<a href="https://wikipedia.org/wiki/Space_Shuttle_Atlantis">
<h6 class="has-tip">Space Shuttle
<p class="tip">The space shuttle was invented by Santa Claus</p>
</h6>
</a>
And the CSS is a bit more involved:
.tip {
display: block;
position: absolute;
bottom: 100%;
left: 0;
width: 100%;
pointer-events: none;
padding: 20px;
margin-bottom: 15px;
color: #fff;
opacity: 0;
background: rgba(255,255,255,.8);
color: coal;
font-family: 'Ubuntu Light';
font-size: 1em;
font-weight: normal;
text-align: left;
text-shadow: none;
border-radius: .2em;
transform: translateY(10px);
transition: all .25s ease-out;
box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.28);
}
.tip::before {
content: " ";
display: block;
position: absolute;
bottom: -20px;
left: 0;
height: 20px;
width: 100%;
}
.tip::after { /* the lil triangle */
content: " ";
position: absolute;
bottom: -10px;
left: 50%;
height: 0;
width: 0;
margin-left: -13px;
border-left: solid transparent 10px;
border-right: solid transparent 10px;
border-top: solid rgba(255,255,255,.8) 10px;
}
.has-tip:hover .tip {
opacity 1;
pointer-events auto;
transform translateY(0px);
}
Now, on desktop this works wonderfully. You hover over the tiny title and you get a pretty looking tooltip, then if you click anywhere on the title or tooltip (unless you decide to put yet another link in the paragraph which works separately and nicely) you activate the link. Yay : )
Now on mobile, the whole thing gets funky. Touching just activates the link. If you have slow internet, or iOS, you might glimpse the tooltip just as the next page loads.
I would like the following behavior:
User taps on tiny title (h6) which has class (has-tip)
If this is the first tap, the tooltip shows, and nothing else happens. 3)
If the tooltip is already showing when they tap (as in a subsequent
tap) then the link is activate and the new page loads.
Any ideas how I might implement this? No jQuery if possible.
One way to do it is to save a reference to the last clicked has-tip link and to apply a class to it which forces the tip to show. When you click on a link and it matches the the last one clicked, you let the event pass.
EDIT: oh, I forgot to mention you might need a classList shim for old IE.
JSFiddle link.
HTML
<a href="http://jsfiddle.net/1tc52muq/5/" class="has-tip">
JSFiddle<span class="tip">Click for some fun recursion</span>
</a><br />
<a href="http://google.com" class="has-tip">
Google<span class="tip">Click to look for answers</span>
</a>
JS
lastTip = null;
if(mobile) {
var withtip = document.querySelectorAll(".has-tip");
for(var i=0; i<withtip.length; ++i) {
withtip[i].addEventListener("click", function(e) {
if(lastTip != e.target) {
e.preventDefault();
if(lastTip) lastTip.classList.remove("force-tip");
lastTip = e.target;
lastTip.classList.add("force-tip");
}
});
}
}
CSS
.has-tip {
position: abolute;
}
.tip {
display: none;
position: relative;
left: 20px;
background: black;
color: white;
}
.has-tip:hover .tip, .force-tip .tip {
display: inline-block;
}
Edit: Just wanted to say that Jacques' approach is similar, but much more elegant.
On touch devices, you'll need to make a click/tap counter:
1) On first tap of any link, store the link and display the hover state.
2) On another tap, check to see if it's the same as the first, and then perform the normal tap action if it is. Otherwise, clear any existing hovers, and set the new tap target as the one to count.
3) Reset / clear any hovers if you tap on non-links.
I've made a rudimentary JSFiddle that console.logs these actions. Since we're not using jQuery, I didn't bother with adding/removing CSS classes on the elements.
Also, sorry about not writing taps instead of clicks.
var clickTarget;
var touchDevice = true;
if(touchDevice) {
var links = document.getElementsByTagName('a');
for(var i=0; i<links.length; i++) {
links[i].onclick = function(event) {
event.stopPropagation();
event.preventDefault(); // this is key to ignore the first tap
checkClick(event);
};
};
document.onclick = function() {
clearClicks();
};
}
var checkClick = function(event) {
if(clickTarget === event.target) {
// since we're prevent default, we need to manually trigger an action here.
console.log("Show click state and also perform normal click action.");
clearClicks();
} else {
console.log("New link clicked / Show hover");
clickTarget = event.target;
}
}
var clearClicks = function() {
console.log("Clearing clicks");
clickTarget = undefined;
};
http://jsfiddle.net/doydLt6v/1/

Categories

Resources