I have this common pattern of parallax scrolling with plain javascript that uses custom data attributes and scrolls the background image in the oposite direction.
HTML:
<header id="home" class="section" data-type="background" data-speed="3"></header>
<section id="portfolio" class="section"></section>
<section id="about" class="section"></section>
<section id="contact" class="section"></section>
CSS:
#home {
background-color: grey;
height: 100%;
width: 100%;
background-image: linear-gradient(to bottom, rgba(#000, 0.5), rgba(#000, 0.5)), url("../bg.jpg");
background-attachment: fixed;
background-repeat: repeat;
background-position: 50%;
background-size: cover;
position: relative;
}
JAVASCRIPT:
{
function parallax() {
Array.from(document.querySelectorAll('*[data-type="background"]')).forEach(e => {
let yPos = -(window.pageYOffset / e.dataset.speed);
var coords = `50% ${yPos}px`;
e.style.backgroundPosition = coords;
});
}
document.addEventListener('scroll', function () {
parallax();
});
}
The issue is that this code calculates the Ypos variable and assigns it to the background position-y property. Actually it overrides the css which is set to 50% before you start scrolling. As a result the image goes from the center to the bottom once you start scrolling. I have included a codepen to see the problem.
https://codepen.io/anon/pen/pLvjqR
Is there any way to add the yPos variable to the initialized background position 50% 50%, which means make it 50% 50%+ypos instead of 50% ypos.
Thanks.
I changed the speed of 3 -> .02 and javascript, you have to start at 50% and reduce this percentage rather than applying values in pixels.
// let yPos = -(window.pageYOffset / e.dataset.speed);
let yPos = (e.getBoundingClientRect().top - window.pageYOffset) * e.dataset.speed + 50;
// var coords = `50% ${yPos}px`;
var coords = `50% ${yPos}%`;
You can view changes here :
https://codepen.io/anon/pen/mxyVBV
Related
So what I was looking for is a subtle radial gradient background effect which will move from left to right when the page is scrolled, like this site - https://hellonesh.io/ . So when I inspected the code of that site, I found the responsible HTML and CSS for that effect -
HTML
<body>
<main>
<div class="bg" style="background-image: radial-gradient(88.33% 60.62% at 100.87% 48.33%, rgb(86, 53, 173) 0%, rgb(20, 9, 78) 100%);"></div>
<section id="sec-1">
...
</section>
<section id="sec-2">
...
</section>
<section id="sec-3">
...
</section>
</main>
<script>
// Need help here
</script>
</body>
CSS
.bg {
position: fixed;
display: block;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
}
section {
height: 100vh;
}
jQuery/js
$(window).on('scroll', function () {
//When a new section(100Vh) comes into view move the radial gradient left to right or right to left
// completely lost here
// $('.bg').css({background-image: "radial-gradient()"});
});
But I've no idea how to make the radial gradient move in the viewport when scrolled. If it's a plugin please let me know the name. If not then how can I achieve that effect using JavaScript or jQuery? Thanks!
There are two parts to this question: how to sense when another section comes into view and when it does how to move the background image depending on which section is now in view.
For the first we can use InterSectionObserver. If we attach the observer to each section, it will get fired when that section comes into (or goes out of, but we aren't interested in that) the viewport.
For the second, this snippet uses a CSS variable --x to say where the background image radial gradient is to have its 'at' x coord set. I don't know what values you want for each section, so this snippet just looks at the id of the section that is in view and calculates the offset just for the demo.
function callback(entries) {
entries.forEach( entry => {
if (entry.isIntersecting) {
let x = 50 * Number(entry.target.id.replace('sec-', '') - 1); //change to whatever you want the x to be for sec-n
bg.style.setProperty('--x', x + '%');
}
});
}
const bg = document.querySelector('.bg');
const sections = document.querySelectorAll('section');
const observer = new IntersectionObserver(callback);
sections.forEach( section => {
observer.observe(section);
});
.bg {
--x: 0;
--y: 48.33%;
position: fixed;
display: block;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-image: radial-gradient(88.33% 60.62% at var(--x) var(--y), rgb(86, 53, 173) 0%, rgb(20, 9, 78) 100%);
}
section {
height: 100vh;
}
<main>
<div class="bg"></div>
<section id="sec-1">
...
</section>
<section id="sec-2">
...
</section>
<section id="sec-3">
...
</section>
</main>
I want my image to be clipped in the centre and be able to move around left right up down while being on cover to fit the whole screen
The user should be able to see only a certain portion of the image and be able to move around just like the link below but his viewpoint is the little rectangle in a fit to screen perspective
What i get so far is just the clipped upleft of my image
In case i am not clear what I am trying to achieve this effect but the user can't see move than the square
https://www.w3schools.com/howto/howto_js_image_zoom.asp
I will soon close this ticket if you happen to stumble on this check out this q I believe I am as as clear as I can here
How to clip your image freely
<style>
img {
background-position: cover;
position: absolute;
clip:rect(0px,500px,500px,0px);
}
.image1 {
background: url(images/bg.jpg) no-repeat center center;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
</style>
</head>
<body>
<div class='clipper-div'>
<img class='image1' src='office.gif'/>
</div>
The kind you were looking for is an inset clipping:
clip-path: inset(top bottom left right);
You can listen to the mouse move event to update the clipping. In the example below, I used CSS custom properties I added to the clipper-element style definition.
These custom properties are used as CSS variables for the clipping definition.
// Globals variables (we could store them into an object,
// which would be a cleaner way
var clipperDiv = document.getElementById("clipper-div");
var hoveringClippedImg = document.getElementById("hovering-clipped");
var imgBoundingRect = hoveringClippedImg.getBoundingClientRect();
var clippingSize = 40;
// Surrouding DIV element mouse move event callback
clipperDiv.onmousemove = clipHoveredArea;
// Update image clipping
function clipHoveredArea(e) {
// First step: getting clipping coordinates from mouse position
var pos = getMousePos(e);
var top = (pos.y - clippingSize / 2);
var bottom = (imgBoundingRect.height - pos.y - (clippingSize / 2));
var left = (pos.x - clippingSize / 2);
var right = (imgBoundingRect.width - pos.x - clippingSize / 2);
// Second step: CSS custom properties
hoveringClippedImg.style.setProperty("--top", top + "px");
hoveringClippedImg.style.setProperty("--bottom", bottom + "px");
hoveringClippedImg.style.setProperty("--left", left + "px");
hoveringClippedImg.style.setProperty("--right", right + "px");
};
// Get mouse position relative to an element
// Source: //stackoverflow.com/a/42111623/4375327
function getMousePos(e) {
// e = Mouse click event.
var rect = e.currentTarget.getBoundingClientRect();
var x = e.clientX - Math.round(rect.left);
var y = e.clientY - Math.round(rect.top);
return {
x: x,
y: y
};
}
#clipper-div {
border: 2px solid black;
width: 200px;
height: 200px;
}
#hovering-clipped {
padding: 0;
margin: 0;
width: 200px;
height: 200px;
clip-path: inset(var(--top) var(--right) var(--bottom) var(--left));
--top: 0px;
--right: 0px;
--bottom: 0px;
--left: 0px;
cursor: crosshair;
}
<div id='clipper-div'>
<img id="hovering-clipped"
src="//placehold.it/200x200/d0d8f8/000000" />
</div>
Note: I used Clippy. It's a handy tool to design the clipping you want.
I have a parent div. I want it to moves to left smoothly while scrolling down and moves to right while scrolling up. it has a p tag inside itself and I want the p tag stay fixed while the parent moves.
I wrote some codes but its not working at all. the sample codes are on fiddle
var p1 = document.getElementById('parallax1')
function parallaxbubbles() {
var scrolltop = window.pageYOffset
var scrollamount = (scrolltop / (scrollheight - windowheight)) * 100
p1.style.left = 35 + (scrollamount / 3) - 35 + '%'
}
window.addEventListener('scroll', function() {
requestAnimationFrame(parallaxbubbles)
}, false)
#parallax1 {
height: 100px;
width: 2539px;
top: 300px;
position: relative;
background: -webkit-linear-gradient(left top, red, yellow);
background: -o-linear-gradient(bottom right, red, yellow);
background: -moz-linear-gradient(bottom right, red, yellow);
background: linear-gradient(to bottom right, red, yellow);
}
#no1 {
height: 1000px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="no1">
<div id="parallax1">
<h3>This is some text</h3>
<p>This is some text .</p>
</div>
</div>
You were missing some variables. I guess scrollheight is the window.scrollY . So i have declared the variable like that and the div moves to left when scroll down and to right when scroll up.
The amount of pixels it moves and other custom styling is up to you.
One weird thing in your calculation is that you have 35 + something - 35 . That's useless :) . I removed that.
I wrapped the text inside a container paraContent , which on scroll moves from left equal to the distance the parallax1 div moves to left. So it stays in the same initial position
See below
( i suggest you don't copy code from other sources before you understand how it works and how it can be edited )
var p1 = document.getElementById('parallax1')
var p1text = document.querySelector('.paraContent')
function parallaxbubbles() {
var scrolltop = window.pageYOffset,
scrollheight = window.scrollY,
windowheight = window.innerHeight,
scrollamount = (scrolltop / (scrollheight - windowheight)) * 100
p1.style.left = (scrollamount / 3) + '%'
p1text.style.left = -(scrollamount / 3) + '%'
}
window.addEventListener('scroll', function() {
requestAnimationFrame(parallaxbubbles)
}, false)
#parallax1 {
height: 100px;
width: 2539px;
top: 300px;
position: relative;
background: -webkit-linear-gradient(left top, red, yellow);
background: -o-linear-gradient(bottom right, red, yellow);
background: -moz-linear-gradient(bottom right, red, yellow);
background: linear-gradient(to bottom right, red, yellow);
}
#parallax1 .paraContent {
position: relative;
width: 100%;
}
#no1 {
height: 1000px;
}
<div id="no1">
<div id="parallax1">
<div class="paraContent">
<h3>This is some text</h3>
<p>This is some text .</p>
</div>
</div>
</div>
var p1 = $("#parallax1")
function parallaxbubbles() {
var scrolltop = window.pageYOffset;
var scrollheight = 100;
var windowheight = window.innerHeight;
var scrollamount = (scrolltop / (scrollheight - windowheight)) * 100;
p1.css("background-position", scrollamount + "px");
}
window.addEventListener('scroll', function() {
requestAnimationFrame(parallaxbubbles)
}, false)
#parallax1 {
height: 100px;
width: 100%;
top: 300px;
position: relative;
background: -webkit-linear-gradient(left top, red, yellow);
background: -o-linear-gradient(bottom right, red, yellow);
background: -moz-linear-gradient(bottom right, red, yellow);
background: linear-gradient(to bottom right, red, yellow);
}
#no1 {
height: 1000px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="no1">
<div id="parallax1">
<h3>This is some text</h3>
<p>This is some text .</p>
</div>
</div>
You had some variables that were not defined. I couldn't really figure out what scrollheightis supposed to be based upon, but when you define the variables that are missing ( scrollheight and windowheight) you get the desired result.
I am following this parallax tutorial that uses only jQuery. I slightly modified the HTML:
<section id="home" data-type="background" data-speed="10">
<article data-speed="1">One</article>
<article data-speed="20">Two</article>
</section>
<section id="about" data-type="background" data-speed="10">
</section>
css
#home {
background: url(home-bg.jpg) 50% 0 repeat fixed; min-height: 1000px;
height: 1000px;
margin: 0 auto;
width: 100%;
max-width: 1920px;
position: relative;
}
#home article {
height: 458px;
position: absolute;
text-align: center;
top: 150px;
width: 100%;
}
#about {
background: url(about-bg.jpg) 50% 0 repeat fixed; min-height: 1000px;
height: 1000px;
margin: 0 auto;
width: 100%;
max-width: 1920px;
position: relative;
-webkit-box-shadow: 0 0 50px rgba(0,0,0,0.8);
box-shadow: 0 0 50px rgba(0,0,0,0.8);
}
#about article {
height: 458px;
position: absolute;
text-align: center;
top: 150px;
width: 100%;
}
And the jQuery:
$(document).ready(function(){
// Cache the Window object
$window = $(window);
$('section[data-type="background"]').each(function(){
var $bgobj = $(this); // assigning the object
$(window).scroll(function() {
// Scroll the background at var speed
// the yPos is a negative value because we're scrolling it UP!
var yPos = -($window.scrollTop() / $bgobj.data('speed'));
// Put together our final background position
var coords = '50% '+ yPos + 'px';
// Move the background
$bgobj.css({ backgroundPosition: coords });
}); // window scroll Ends
});
});
This code moves everything in a section at the same speed, but I would like to have the <article> text move at a variable speed different (defined in the <article data-speed>) from the background image.
I wasn't sure how to move the text because background-position is for images, and I tried adjusting top but that didn't have any effect. I also tried setting transform: translateZ(); on the article css, but this also did not work.
How can I add different speeds to the <article> texts? I'd also like to stick to jQuery in the spirit of the example.
try modifying markup always wrapping the article with a section, for ex.:
<section id="about" data-speed="4" data-type="background">
<article>One</article>
</section>
<section id="home" data-speed="20" data-type="background" >
<article >Two</article>
</section>
edit--explanation
this is the source of your parallax jquery script:
$(document).ready(function(){
// Cache the Window object
$window = $(window);
$('section[data-type="background"]').each(function(){
var $bgobj = $(this); // assigning the object
$(window).scroll(function() {
// Scroll the background at var speed
// the yPos is a negative value because we're scrolling it UP!
var yPos = -($window.scrollTop() / $bgobj.data('speed'));
// Put together our final background position
var coords = '50% '+ yPos + 'px';
// Move the background
$bgobj.css({ backgroundPosition: coords });
}); // window scroll Ends
});
});
as you can tell what it's doing is slowing down the scroll of the section[data-type="background"] with a factor of data('speed');
This kind of script is built in a way to have one layer of parallax, if you want more parallax layers check wagersfield's parallax script
I have the following JavaScript companied with basic CSS to create a parallax background image, live preview of what I already have in a demonstration here: http://loai.directory
Here is the Javascript:
//Parallax background image
var velocity = 0.5;
function update() {
if ($(window).width() <= 1024) {
return;
}
var pos = $(window).scrollTop();
$('.parallax').each(function () {
var $element = $(this);
var height = $element.height();
$(this).css('background-position', '50%' + Math.round((height - pos) * velocity) + 'px');
});
};
$(window).on('scroll', update);
update();
CSS:
/*Backgruond Parallax*/
.parallax {
background-attachment: fixed;
background-repeat: no-repeat;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
#gallery .parallax {
background-image: url('../images/image.jpg');
padding: 100px 0;
}
#gallery .parallax.A {
background-image: url('../images/backgruond.jpg');
padding: 100px 0;
}
And finally the HTML:
<div class="topSection parallax">
<div class="content"></div>
</div>
The problem I am having is with the background images being cropped from the bottom, and the far you scroll down, the worse they get! I believe this is because the parallax function move the background image position to the top as you scroll... but how can I fix this? Please help.
The blue sections suppose to be filled with the background image.