I'm trying to recreate this simple jquery image zoom scroll effect in vanilla javascript with no success:
I'm looking online and all tutorials seems to use jquery or skrollr library which is not being supported since 2014.
This is a tutorial of this effect on youtube:
https://www.youtube.com/watch?v=hjeS8HxH3k0
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Image Zoom Scroll Effect</title>
<style>
body {
margin: 0;
padding: 0;
}
div {
width: 100%;
height: 100vh;
overflow: hidden;
position: relative;
}
div img {
width: 100%;
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%);
}
/* BLANK SPACE, JUST TO TRY OUT THE SCROLL EFFECT */
.whitespace {
width: 100%;
height: 100vh;
}
</style>
<!-- JQUERY CDN -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<div class="img-area">
<img
src="https://images.pexels.com/photos/775201/pexels-photo-775201.jpeg"
/>
</div>
<!-- BLANK SPACE, JUST TO TRY OUT THE SCROLL EFFECT -->
<div class="whitespace"></div>
<script>
// JQUERY
$(window).scroll(() => {
let scroll = $(window).scrollTop();
$('.img-area img').css({
width: 100 + scroll / 5 + '%',
});
});
// VANILLA JS
// window.addEventListener('scroll', () => {
// let scroll = window.scrollTop;
// document.querySelector('.img-area img').style.width =
// 100 + scroll / 5 + '%';
// });
</script>
</body>
</html>
I've commented out my vanilla javascript code.
There is no property scrollTop for the window object. Use document.documentElement:
window.addEventListener('scroll', () => {
let scrollTop = document.documentElement.scrollTop;
document.getElementById('test').style.width = 100 + scrollTop / 5 + '%';
});
See working fiddle: https://jsfiddle.net/z3hux1ra/5/
I'm incredibly new to JavaScript, and honestly thought I had a solid plan-of-attack to make my logo smaller after scrolling from the top by 10px. The goal is to make the logo (normally 400px in width) get smaller (to 100px) upon scrolling down from the top.
Can anyone help me understand why this code isn't returning any visual response?
Here is the HTML markup:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<meta name="author" content="">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="normalize.css" rel="stylesheet">
<link href="style.css" rel="stylesheet">
</head>
<body>
<!--<div id="header">Header</div>-->
<div id="header">
<img id="header-image" src="logo-mockup.png">
</div>
<p>THIS IS ALL JUST FILLER TEXT RIGHT NOW.</p>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="script.js"></script>
</body>
</html>
The CSS:
#header {
background-color: #f1f1f1; /* Grey background */
padding: 30px 0px; /* Some padding */
color: black;
text-align: center; /* Centered text */
font-size: 90px; /* Big font size */
font-weight: bold;
position: fixed; /* Fixed position - sit on top of the page */
top: 0;
width: 100%; /* Full width */
height:90px;
transition: 0.2s; /* Add a transition effect (when scrolling - and font size is decreased) */
}
#header-image {
padding: 0px 10px; /* Some padding */
text-align: center;
top: 0;
transition: 0.2s; /* Add a transition effect (when scrolling - and font size is decreased) */
}
p {
margin:300px;
}
And the JS:
function scrollFunction() {
if (document.body.scrollTop > 10 || document.documentElement.scrollTop > 10) {
document.getElementById("header-image").style.width = "100";
} else {
document.getElementById("header-image").style.width = "400";
}
}
You need to set up an eventListener that calls scrollFunction whenever the user scrolls the wheel.
A shortcut would be to just change <body> to <body onscroll="scrollFunction()">.
You could also set up an event listener in the javascript:
window.addEventListener("scroll", function(e) {
scrollFunction();
}
Your scrollFunction() in never called. You should add event listener for window scroll and remember to add the unit at the end for setting the width- in your case 'px'.
window.onscroll = function() {
if (document.body.scrollTop > 10 || document.documentElement.scrollTop > 10) {
document.getElementById("header").style.width = "100px";
} else {
document.getElementById("header").style.width = "400px";
}
}
The Problem:
I know this question has been asked a dozen of times, but none of the solutions on those questions worked for me.
I want the body element on iOS 13 safari to not scroll. This means no scrolling, and no elastic bounce (overflow-scrolling) effect.
I have two elements next to each other on which I have set overflow: scroll;, those should scroll, just the body around them shouldn't.
All the solutions I've tried just don't work in progressive webapps that have the following tag inside their head and are saved to the homescreen.
<meta name="apple-mobile-web-app-capable" content="yes">
Solutions I've tried:
try 1: setting overflow hidden on body and/or html. Didn't work for iOS 13 safari.
https://stackoverflow.com/a/18037511/10551293
html {
position: relative;
overflow: hidden;
height: 100%;
}
body {
position: relative;
overflow: hidden;
height: 100%;
}
does nothing in iOS 13 safari but works in macOS safari and Firefox.
try 2: setting position fixed on the body. Doesn't work for me because when the user scrolls, the body doesn't but the scrolling still prevents my two inner elements from scrolling while the overflow-bounce is animating.
https://stackoverflow.com/a/47874599/10551293
body {
position: fixed;
}
only puts the body over the scrolling of the page. The scrolling (overflow-scrolling) happens through the fixed body...
try 3: preventing the default on touch moved. Didn't work (is an older solution...).
https://stackoverflow.com/a/49853392/10551293
document.addEventListener("touchmove", function (e) {
e.preventDefault();
}, { passive: false });
does nothing as I can tell. Not in safari nor in Firefox.
try 4: preventing the default on scrolling of the window and setting the scroll position back to 0. Is not viable because of buggy animations.
window.addEventListener("scroll", (e) => {
e.preventDefault();
window.scrollTo(0, 0);
});
sets the scroll position back to 0 but the overflow-scrolling still applies which ends up in a buggy behaviour.
A snippet that demonstrates it:
To test it yourself, save the snippet below as an html file, and save it to the homescreen on an iPad (or iPad simulator). The body suddenly becomes scrollable when saved to the homescreen.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<meta name="apple-mobile-web-app-capable" content="yes">
</head>
<body>
<style>
body, html {
position: relative;
overflow: hidden;
height: 100%;
width: 100%;
}
body {
margin: 0;
display: flex;
flex-direction: column;
}
nav, footer {
width: 100%;
height: 5rem;
background: blue;
flex-shrink: 0;
}
main {
display: flex;
height: 0;
flex-grow: 1;
padding: 2rem;
}
section {
width: 50%;
overflow: scroll;
display: flex;
flex-direction: column;
align-items: center;
}
div {
flex-shrink: 0;
width: 25%;
height: 18rem;
margin: 1rem;
background: red;
}
</style>
<nav></nav>
<main>
<section>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
<section>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
</main>
<footer></footer>
</body>
</html>
None of them worked in an acceptable way for me, now how do I do this so it works properly in iOS 13 safari (when saved as a PWA to the home screen)?
I combined try 2 and try 4 from the question. The fixed body shows no overflow scrolling and the scroll reset prevents the long animation of the overflow scrolling in the background. It's really ugly but it kinda works.
body {
position: fixed;
}
window.addEventListener("scroll", (e) => {
e.preventDefault();
window.scrollTo(0, 0);
});
function unlockScroll () {
const scrollY = this.body.style.top;
document.body.style.position = '';
document.body.style.top = '';
document.body.style.left = '';
document.body.style.right = '';
window.scrollTo(0, parseInt(scrollY || '0') * -1);
};
function lockScroll () {
document.body.style.position = 'fixed';
document.body.style.top = `-${window.scrollY}px`;
document.body.style.left = '0';
document.body.style.right = '0';
};
In my case (app requires dragging to arrange elements) setting touch-action to none worked to prevent scrolling when dragging certain elements.
e.g.
draggableElement.css('touch-action', 'none') // disable actions
draggableElement.css('touch-action', 'auto') // restore actions
Just add a touch-action:none to the body in CSS:
body{
touch-action:none;
}
https://github.com/willmcpo/body-scroll-lock
I am unable to test at the moment, but this seems worth a try.
I had a similar issue before and so far using the below approach has worked best:
first, enable scrolling on your content container by applying -webkit-overflow-scrolling: touch
second, apply the following rules:
/* this part makes sure there is nowhere left to scroll */
html {
position: static;
overflow-y: hidden;
height: 100%;
max-height: 100%;
}
/* all properties don't necessarily need to be applied on both elements,
this is only used to override any existing code */
body {
overflow: hidden;
height: 100%;
max-height: 100%;
}
window.addEventListener('touchend', _ => {
window.scrollTo(0,0)
});
This will snap the body back to 0,0 after the user lets go of the body, allowing the user to immediately scroll down without any weird animations besides snapping back right away. I tried it with a smooth scroll animation but it doesn't always animate fast enough. This will prevent the screen lock that occurs when the body scrolls from the bounce elastic scroll on that iPhone and is only triggered when the user lets go of the pull.
This worked for me https://stackoverflow.com/a/41601290/10763156
please, add -webkit-overflow-scrolling: touch; to the #overlay element.
And add please this javascript code at the end of the body tag:
(function () {
var _overlay = document.getElementById('overlay');
var _clientY = null; // remember Y position on touch start
_overlay.addEventListener('touchstart', function (event) {
if (event.targetTouches.length === 1) {
// detect single touch
_clientY = event.targetTouches[0].clientY;
}
}, false);
_overlay.addEventListener('touchmove', function (event) {
if (event.targetTouches.length === 1) {
// detect single touch
disableRubberBand(event);
}
}, false);
function disableRubberBand(event) {
var clientY = event.targetTouches[0].clientY - _clientY;
if (_overlay.scrollTop === 0 && clientY > 0) {
// element is at the top of its scroll
event.preventDefault();
}
if (isOverlayTotallyScrolled() && clientY < 0) {
//element is at the top of its scroll
event.preventDefault();
}
}
function isOverlayTotallyScrolled() {
// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions
return _overlay.scrollHeight - _overlay.scrollTop <= _overlay.clientHeight;
}
}())
For me worked:
import { useEffect } from "react";
export const useOverscrollHandler = () => {
useEffect(() => {
const onScroll = (e: any) => {
e.preventDefault();
window.scrollTo(0, 0);
};
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, []);
};
i try to set a margin bottom to the body element, but it wont work as expected...
document.addEventListener('DOMContentLoaded', (event) => {
if(window.outerWidth > 768) {
let footerHeight = document.querySelector('footer').offsetHeight;
document.querySelector('body').style.marginBottom = footerHeight + "px";
}
/* .... */
});
its just doing nothing.
the weird part i dont understand: it works as expected when i try to set it as a paddingBottom, but when i change it to margin...
my current solution for now is to wrap it in a setTimeout() like:
document.addEventListener('DOMContentLoaded', (event) => {
if(window.outerWidth > 768) {
setTimeout(function(){
let footerHeight = document.querySelector('footer').offsetHeight;
document.querySelector('body').style.marginBottom = footerHeight + "px";
}, 1);
}
/* .... */
});
let footerHeight gets the correct value in any cases.
no other scripts are loaded which i can think of could affect this...
The simplified CSS & HTML:
body {
margin: 0;
padding-top: 48px;
}
.content-wrapper {
background: #fff;
padding-bottom: 40px;
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.08), 0 4px 4px rgba(0, 0, 0, 0.16);
}
footer {
position: fixed;
bottom: 0;
z-index: -1;
background-size: cover;
background-position: center;
display: flex;
width: 100%;
}
<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
</head>
<body class="start">
...
<div class="content-wrapper">
...
</div>
<footer style="background-image: url('/images/polygon.jpg');">
<div class="container">
<div class="row">
...
</div>
</div>
</footer>
<script src="/js/script.js"></script>
</body>
</html>
creates this type of footer reveal effect: https://codepen.io/hkdc/pen/BLJAVL
but to make sure that the whole footer is always visible i add a margin-bottom of the footers height to the body element.
Anyone has an idea what is happening here or am i getting wrong and can explain it?
I'm not sure you understand body tag correctly. You footer is in that body too adding margin to body cant have any effect in this case cause there is no element (at least visible) after body. Padding works cause padding is for the elements inside the body. If you want to add margin before your footer you can use previousSibling property and set its margin.
<head>
<title>Overlay test</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<style type="text/css">
#overlay {
position: absolute;
background-color: #ccffcc;
display: none;
height: 200px;
margin: 0 auto;
width: 200px;
}
</style>
<script type="text/javascript">
//<![CDATA[
function hide() {
document.getElementById("overlay").style.display = "none";
}
function show() {
document.getElementById("overlay").style.display = "block";
}
//]]>
</script>
so when the user clicks it runs show() which places the css box on top. However i want it to be centered in the browser. I've set the margin: 0 auto; which should be doing the trick shouldnt it?
I'm just trying to create an overlay function without using jquery because it seems to be incompatible with my schools cms templates.
Thanks
Margin: 0 auto won't work on position absolute elements, they exist in their own little world, outside of normal flow. So in order to pull this off, you need to do an extra step. The CSS dead centre technique will work here.
Try setting the top and left attributes on your overlay.
Use % to set top and left position. Set css attribute top:10%; Left 40%;