Webpage parallax background jitters when scrolling - javascript

I coded my first website and I wanted a parallax effect on my background when scrolling. It works, but on some computers &/or on some browsers &/or on some window sizes, the background jitters up and down when scrolling, while still sort of maintaining the parallax effect. I cannot figure out exactly what combination leads to the issue, it seems inconsistent.
In css I have a vertically repeating background image on the body of my page (the hexagon pattern):
body {
background: #fff9ed;
background-image: url("hexagon-side.png"), url("hexagon-side.png");
background-position: 0px 0px, 100% 0px;
background-repeat: repeat-y, repeat-y;
}
Then I used the following javascript that creates the parallax effect, making the hexagons move slower than other elements when you scroll:
window.addEventListener('scroll', function() {
let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
var currentOffset = '0px ' + scrollTop / 1.2 + 'px, 100% ' + scrollTop / 1.2 + 'px';
document.getElementById("parallax").style.backgroundPosition = currentOffset;
});
Finally my body in the html file has the id parallax:
<body id="parallax">
Is there a way to fix this issue? Is there a better way to achieve this same effect? What might be causing this?

Adding
background-attachment: fixed;
to the css body, and changing the currentOffset to be
var currentOffset = '0px ' + scrollTop / -3 + 'px, 100% ' + scrollTop / -3 + 'px';
Fixed the jittering issues.

Related

Creating masked overlay spotlight effect to reveal image

I am trying to create an awesome "reveal" effect on my portfolio page.
Here is an example of what I am trying to visually accomplish with JS and CSS. My example was made using Photoshop.
Here is a JS FIDDLE I found and modified where I get sort of close.. But the spot light is too "hard" and not nearly as elegant as what I had in mind. I want it to feel more like a "glow" instead of a circle.
Does anyone know how to fix it? Any help would be much appreciated. I am open to any suggestions for achieving the effect.
// Create the spotlight
function createSpotlight() {
$('.spotlight').width(spotlightDiameter + 'px')
.height(spotlightDiameter + 'px');
for (var i = 0; i < numSpotlightLayers; i++) {
var layerDiameter = spotlightDiameter + (i * spotlightLayerThickness * 2);
var opacity = 1 - (i / numSpotlightLayers);
$('.spotlight').append('<div class="layer' + i + '"></div>');
$('.spotlight .layer' + i)
.width(layerDiameter + 'px')
.height(layerDiameter + 'px')
.css({borderRadius: (layerDiameter >> 1) + 'px',
opacity: opacity,
zIndex: (numSpotlightLayers - i)});
}
}
So I am going to answer my own question. Shout out and thanks to #Skyline3000 for suggesting the solution in the comment section.
The solution is to create a large div with a radial gradient containing a transparent center. Than you script that div to follow the mouse cursor. Set both the radial gradient div element and the content box "body" to a negative z-index value as to not obstruct page content. You also need to set the div to "Fixed" in the JS as to not create scroll bars when the mouse is near view port edges.
Here is a working fiddle.
https://jsfiddle.net/d4em31n2/16/
Required CSS:
position:fixed;
background: -webkit-radial-gradient(center center, circle cover, rgba(117, 245, 71, 0), rgba(0, 20, 42,1) 4%);
background: radial-gradient(center center, circle cover, rgba(117, 245, 71, 0), rgba(0, 20, 42,1) 100%) 4%);
Required JS:
var img=$('div');
$(document).ready(function(e) {
$(document).mousemove(function(e) {
var positionLeft = e.clientX - img.width()/2;
var positionTop = e.clientY - img.height()/2;
img.css({'position': 'fixed', 'left': positionLeft, 'top': positionTop});
mousePositionValueDiv.text(e.clientX+', '+e.clientY);
});
});

Keep aware of transform and transform-origin anchor point on rotated container

I'm trying to rotate a container with javascript and css property transform and transform-origin, the idea is to rotate it around certain coordinates (For example a pinch gesture center between the two fingers), I'm using this simple code (snippet attached) right now to rotate the container and using the onclick event to capture the anchor point. It is working properly as long as you keep clicking without moving the cursor to a different position on the container. There's an issue when you change the click position once the container has been rotated, the expected behavior is to keep track of the transformation and start rotating for that new point, however right now the container is doing an odd jump. I think that some x,y translation need to be added to the container, but i can figure out what's the correct factor to add to the container.
I'm not sure if I've illustrated well the expected behavior, to make sure here's and example: Imagine you pin a note to a surface at certain position, then, you start rotating the note, having the pin as anchor point. Now, after rotating the note a little, you put out the pin (Keeping the note at the same place), then you place the pin on a different position on the note and rotate again with that new anchor point. That's the expected behavior, hope i have explained myself well.
Here's a snippet to show it better, also available on codepen, cheers.
http://codepen.io/vasilycrespo/pen/GZeYpB
var angle = 15,
scale = 1,
origin = { x: 0, y: 0};
var transform = function (e) {
var map = document.getElementById("map");
angle += 15;
map.style.transformOrigin = e.pageX + "px " + e.pageY + "px";
map.style.transform = "rotate("+angle+"deg) scale("+ scale +")";
};
.content{
position: fixed;
top: 0px;
left: 0px;
margin-top:0;
margin-left:0;
background-color: #ccc;
width: 100%;
height: 100%;
}
.square{
position: absolute;
width: 400px;
height: 400px;
background-image: url(http://www.pnas.org/site/misc/images/15-02545.500.jpg);
background-size: cover;
}
<div class="content" onclick="transform(event)">
<div class="square" id="map"></div>
</div>
The problem is that every time you click, the div changes position based on where you click. After the first click, you should save e.pageX and e.pageY, and in the next clicks you should use the saved values. You can change your transform function to this:
var transform = (function () {
var pageX, pageY;
return function(e) {
if (typeof pageX === "undefined") {
pageX = e.pageX
pageY = e.pageY
}
var map = document.getElementById("map"), xr;
angle += 15;
map.style.transformOrigin = pageX + "px " + pageY + "px";
map.style.transform = "rotate("+angle+"deg) scale("+ scale +")";
}
}())
See updated Code Pen.

Keep element within parents view when the browser resizes

Edit
The thing that was bothering me, was that if you drag the div all the way to the bottom right, then you make the browsers size larger, the div isn't within its parents view, until you actually drag it. Once you drag it, it snaps back within its parents view.
How can I make the div stay in its parent view even after you resize the browser?
JSFiddle
See code snippet bellow.
Older
I have a div which I made draggable through JQuery UI. I want it to be positioned with a percentage value. This way, when you resize the browser, the div will be relatively, or proportionally at the same position.
I checked out this answer, and followed what it said. When I output the left and top position, the numbers were not accurate. When I drag the div all the way to the bottom right, it gives me the following output:
66.55518394648828%
92.71255060728744%
Actually, it does depend on the window size, but the point is, the numbers aren't 100% for left and right.
How can I keep the div at the same position proportionally, when the browser resizes?
Relevant Code:
stop: function () {
console.log(parseInt($(this).css("left")) / (wrapper.width() / 100) + "%");
console.log(parseInt($(this).css("top")) / (wrapper.height() / 100) + "%");
}
JSFiddle
Code Snippet
var wrapper = $('#fixed');
var dragDiv = $('#draggable');
dragDiv.css({
'top': ($(window).height() / 2) - (dragDiv.outerHeight() / 2),
'left': ($(window).width() / 2) - (dragDiv.outerWidth() / 2)
});
dragDiv.draggable({
containment: "parent", // <- keep draggable within fixed overlay
stop: function() {
$(this).css("left", parseInt($(this).css("left")) / (wrapper.width() / 100) + "%");
$(this).css("top", parseInt($(this).css("top")) / (wrapper.height() / 100) + "%");
console.log(parseInt($(this).css("left")) / (wrapper.width() / 100) + "%");
console.log(parseInt($(this).css("top")) / (wrapper.height() / 100) + "%");
}
});
body {
/*width: 2000px;
height: 2000px;*/
background-image: url("http://www.freevector.com/site_media/preview_images/FreeVector-Square-Patterns-Set.jpg");
}
#fixed {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.25)
}
#draggable {
color: lightblue;
background-color: red;
width: 200px;
position: absolute;
}
<script type="text/javascript" src="//code.jquery.com/jquery-2.1.4.js"></script>
<script type="text/javascript" src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<div id="fixed">
<div id="draggable">Drag Me!</div>
</div>
The problem is the the parent container to the dragable element has the fixed position.
You can't position items relative to a fixed element.
$(this).css("left") // this refers to $('#draggable')
This is not giving you a left position relative to the fixed container, but rather the body element which has padding on it. So either set the html, body, and #fixed container to have a height and width of 100% and make them position relative.
OR
Remove the padding and margin from your body and html element
body, html{ margin: 0px; padding: 0px;}
Fiddle with body, html, and #fixed at 100%
Fiddle with 0 padding and margin
EDIT
I created a new event to fire every time the window is resized. The event checks to see if the dragable div is outside the bounds of the window. Adjusting as necessary to keep the element in view. I used the code WITHOUT the fixed element because it is not necessary. Let me know if you have any questions.
JS
$(window).resize(function () {
if ($(window).innerWidth() > $(dragDiv).width()) {
var oLeft = parseInt($(window).innerWidth() - $(dragDiv).width());
var posLeft = parseInt($(dragDiv).css("left"));
if (posLeft > oLeft) {
$(dragDiv).css("left", oLeft);
toPercent();
}
}
if ($(window).innerHeight() > $(dragDiv).height()) {
var oTop = parseInt($(window).innerHeight() - $(dragDiv).height());
var posTop = parseInt($(dragDiv).css("top"));
if (posTop > oTop) {
$(dragDiv).css("top", oTop);
toPercent();
}
}
});
function toPercent() {
$(dragDiv).css("left", parseInt($(dragDiv).css("left")) / (wrapper.innerWidth() / 100) + "%");
$(dragDiv).css("top", parseInt($(dragDiv).css("top")) / (wrapper.innerHeight() / 100) + "%");
}
Updated Fiddle for question part 2

<html> wider than screen

Got a strange issue, my tag has a greater width than my monitor, which it shouldn't. I have some JavaScript which gets the scroll offset and adjusts my background, to give it a parallax effect, but as you can see, once the background gets given an 100% width, it snaps and stretches out. You can see this by zooming out of the page, the background is larger.
Here is the website
Any idea what is going wrong with it? Here is my JavaScript, and view the CSS by inspecting the element. It has also gone a bit slow as well to be honest, was working nice and smooth.
var ismobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
if (!ismobile){
window.onresize = function(event) {
//Detect window size and make new padding
if (window.innerWidth > 835) {
var newPadding = parseInt(window.innerHeight)/2.8;
newPadding = newPadding.toFixed(0);
var limitPadding = 221;
//Apply new padding value to header
if (newPadding > limitPadding) {
doc("header").style.padding = newPadding + "px 0px";
}
}
}
window.onscroll = function() {
var speed = 0.7;
var newPos = "100% " + (window.pageYOffset * speed) + "px";
document.body.style.backgroundPosition = newPos;
}
}
Add the overflow property to your body tag...
body {overflow-X: hidden;}

CSS3 radial gradient rendering in Google Chrome

I was animating radial gradients with jQuery when I suddenly noticed something strange (check out this JSFiddle). When the mouse pointer is moved over the left side of the element the position animation is smooth, but when far to the right it isn't smooth at all (notice the jumps in position if you move your mouse slowly enough).
This feels like some kind of rounding error, but I'm not sure as to why it happens. Any ideas? I have only tested it on Google Chrome for the time being and it only happens in the horizontal direction.
CSS
html { background: #fff; }
html, body {
width: 100%;
height: 100%;
}
body { background: #000; }
JavaScript
$('body').on('mousemove', function(event) {
var x = event.pageX;
var y = event.pageY;
$(this).css('background', '-webkit-radial-gradient(' + x + 'px ' + y + 'px, transparent 10%, #000 5%)');
});
Can you replicate this or does it only happen to me?
EDIT: Works fine in Safari.
I could replicate it: like it's is said in this answer, it's not smooth because it's relying on the mousemove event only. Try to use a ticker, that's relying on time intervals. I modified your fiddle to use the ticker found in the already linked thread, here it is: http://jsfiddle.net/rh4Ljro4/
Here is the relevant javascript:
var container = $('body');
var contWidth = container.width();
var intervalId;
var mouseX, mouseY;
//this function is called 60 times per second.
function ticker(){
$(container).css('background', '-webkit-radial-gradient(' + mouseX + 'px ' + mouseY + 'px, transparent 10%, #000 5%)');
}
//this interval calls the ticker function every 16 milliseconds
intervalId = setInterval(ticker, 16); //33 millisecond is about 30 fps while 16 would be roughly 60fps
container.mousemove(function(e){
mouseX = e.offsetX; //store the current mouse position so we can reference it during the interval
mouseY = e.offsetY;
});

Categories

Resources