Div following cursor paints pixels on screen in Safari (bug?) - javascript

I've used the following code to make a div that follows the cursor with easing applied to the movement:
CSS
#cursor {
position: absolute;
width: auto;
height: auto;
white-space: nowrap;
pointer-events: none;
transition: opacity 200ms;
cursor:none!important;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index:99999999;
color:white;
backface-visibility: hidden;
}
JavaScript/jQuery:
$(document).on("mouseover mousemove", function (event) {
mouseX = event.pageX;
mouseY = event.pageY - $(window).scrollTop();
cursorWidth = $cursor.width();
cursorHeight = $cursor.height();
});
requestAnimationFrame(performAnimation);
var performAnimation = function() {
var distX = mouseX - cursorX;
var distY = mouseY - cursorY;
cursorX = cursorX + (distX * speed);
cursorY = cursorY + (distY * speed);
$cursor.css({
left: cursorX + "px",
top: cursorY + "px"
});
request = requestAnimationFrame(performAnimation)
}
It works as intended in Chrome, but on Safari it leaves traces of the text in the div on top of the screen, i. e. the elements underneath the cursor z-index wise. Here's a video showing the behaviour.
Is this a known bug with Safari and can it be avoided somehow? I'm not sure if this has to do with the requestAnimationFrame() function or if it's something else. I tried applying backface-visiblity:none; to the #cursor itself through CSS, as this sometimes solves these type of issues, but in this case it's not doing anything.

The problem had to do with the #cursor being a child of a container that was fixed on top of the whole page. Removing this container and placing #cursor without a container on it's own fixed the issue.
For some reason I thought it was practical to have the cursor wrapped in this container so that I could add classes through JS to the container instead of the cursor itself to manipulate it's style. But I ended up adding the styling classes to a <span> inside #cursor instead.

Related

CSS-HTML: Put an image above another one with html and css

I'm very newbie to webdev, but I need to draft a landingpage with some trick effects.
I need to put a "stencil image" (png with transp) over a moving (mouse hover) background.
Basically, I managed to do that, but I having a big issue: If I resize browser, the background shows behind first plane image, (because I can't rezise background to browser size).
So, the main codes are:
html code:
<div id="bkg-image" class="blur"></div>
<div>
<img src="./imgs/stencil.png" class="firstPlane" />
</div>
CSS code:
#bkg-image {
background: url('./imgs/background.jpg') no-repeat center center fixed;
position: absolute;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
width: 75%;
height: 75%;
z-index: 0;
-webkit-filter: brightness(1.7);
}
.firstPlane {
display: block;
position: absolute;
top: 0px;
left: 0px;
max-width: 100%;
height: auto;
width: auto;
z-index: 2;
}
JS code:
$(document).ready(function() {
var movementStrength = 75;
var height = movementStrength / $(window).height();
var width = movementStrength / $(window).width();
$(".firstPlane").mousemove(function(e) {
var pageX = e.pageX - ($(window).width() / 2);
var pageY = e.pageY - ($(window).height() / 2);
var newvalueX = width * pageX * -1;
var newvalueY = height * pageY * -1;
$('#bkg-image').css("background-position", newvalueX + "px " + newvalueY + "px");
});
});
Any idea how to crop the excess background or how to rescale it to fit behind firstplane image?
note: blur class is just for an animated blur effect, not relevant to this.
I took the java script from a net tutorial.
My first aproach was using webkit mask-image, but seens it don't works, now I'm trying this method.
Thanks a lot for any help
You are doing it upside down. This is how it should be.
$(document).ready(function() {
$("#bkg-image").mousemove(function(e) {
$('.firstPlane').css({left: e.pageX + "px", top: e.pageY + "px"});
});
});
I need invert the selection: I need read the mouse position on first plane and apply movement to the bkg image. (your script only works if I switch #bkg-image and .firstPlane). My issue isn't read the movement, but crop bkg-image to not show it bellow 1st plane when I have a small and tall browser window.
The solution would be a mask/clip image, but its not working for svg graphics or PNG for me, so I give up and tried with a big black PNG with transp on it to show background.
Something like this: (https://codepen.io/caraujo/pen/rVOZKJ) but with a logo (vector or png), but mask/image clip is not working for me :/

Why element getBoundingClientRect() values condition is not working properly?

I have .square element when I move my mouse it should be moved with the mouse. Almost everything is good when I move my mouse normally but when I move my mouse fastly on the right and bottom side, Then the .square box goes to the down or right side and makes the scrollbar.
How can I make my code better than now OR How to fix the problem?
[NOTE]: Transition should have
let square = document.querySelector(".square");
document.addEventListener("mousemove", function (e) {
if (square !== null) {
let x = e.pageX;
let y = e.pageY;
square.setAttribute("style", `top: ${y}px; left: ${x}px`);
let getBottom = square.getBoundingClientRect().bottom;
let getRight = square.getBoundingClientRect().right;
if (getBottom > window.innerHeight) {
square.setAttribute("style", `bottom: 0; left: ${x}px`);
}
if (getRight > window.innerWidth) {
square.setAttribute("style", `top: ${y}px; right: 0`);
}
if (getRight > window.innerWidth && getBottom > window.innerHeight) {
square.setAttribute("style", `bottom: 0; right: 0`);
}
}
});
*,
*::before,
*::after{
box-sizing: border-box;
}
body{
margin: 0;
border: 1px solid blue;
}
.square {
position: absolute;
height: 50px;
width: 50px;
border: 5px solid red;
transition: .01s ease-in-out;
}
<div class="square"></div>
The problem is caused by defining a transition on the square element's position in CSS, combined with setting the position of the square before reading its current position:
Setting the position immediately to the mouse move position:
square.setAttribute("style", `top: ${y}px; left: ${x}px`);
can move the square out of the viewport and create scroll bars if the mouse is less than the length of the square's side away from the bottom or right of the browser window.
Reading the position of the square next:
let getBottom = square.getBoundingClientRect().bottom;
let getRight = square.getBoundingClientRect().right;
returns the updated position of the square if there is no transition, but with the transition returns where the square is now, before the transition starts. Since the square is not outside the window yet, none of the conditional statements using its old position detect that it will end up outside the window.
The easiest solution is to remove the CSS transition - keeping it at 0.01 second is less than monitor update refresh time and not particularly useful.
Getting the square's position once, before updating its position is another solution.
In either case it may be smoother to update the position of the square at most once, with the position where it transition to.
In this code used to find an answer, the html element's clientWidth and clientHeight properties are a special case of these properties and reflect the size of the view port excluding scroll bars. The transition timing is set to 0.05 seconds to avoid stroboscopic effect from screen refresh:
let square = document.querySelector(".square");
const HTML = document.firstElementChild;
document.addEventListener("mousemove", function (e) {
if (square !== null) {
let domRect = square.getBoundingClientRect()
let x = e.pageX;
let y = e.pageY;
x = Math.min( HTML.clientWidth - domRect.width, x);
y = Math.min( HTML.clientHeight - domRect.height, y);
square.style.top = `${y}px`;
square.style.left = `${x}px`;
//square.setAttribute("style", `top: ${y}px; left: ${x}px`);
}
});
*,
*::before,
*::after{
box-sizing: border-box;
}
body{
margin: 0;
border: 1px solid blue;
}
.square {
position: absolute;
height: 50px;
width: 50px;
border: 5px solid red;
transition: .05s ease-in-out;
}
<div class="square"></div>

How to adjust the mouse position after rotating an object?

I am trying to create an eye that follows cursor movement.
I got the horizontal and vertical coordinate of the mouse and the browser width and height.
Everything works perfectly. Except that I used rotate(45 deg) on the design of the eye so now the ball is not moving in the right position.
I was thinking about a math equation that finds the distance between the old and new coords, but I am not sure how to implement it.
Here is the full code:
https://jsfiddle.net/Mr_MeS/3ym6kuec/3/
so this is the .eye where its rotated
.eye {
width: 37.5px;
height: 37.5px;
background: white;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(45deg);
border-radius: 75% 0;
overflow: hidden;
cursor: pointer;
}
.ball {
width: 7.5px;
height: 7.5px;
background: #222f3e;
border-radius: 50%;
border: 5px solid #576574;
position: relative;
top: 50%;
left: 50%;
}
and here is the JS that does the work and needs to be edited.
var balls = document.getElementsByClassName("ball");
document.onmousemove = function () {
var x = event.clientX * 100 / window.innerWidth + "%";
var y = event.clientY * 100 / window.innerHeight + "%";
//event.clientX => get the horizontal coordinate of the mouse
//event.clientY => get the Vertical coordinate of the mouse
//window.innerWidth => get the browser width
//window.innerHeight => get the browser height
for (var i = 0; i < 2; i++) {
balls[0].style.left = x;
balls[0].style.top = y;
balls[0].style.transform = "translate(-" + x + ",-" + y + ")";
}
}
Now, if I remove the rotation from the .eye, it works perfectly, expect that the whole shape doesn't look to be in position.
If I keep the 45deg rotation, the shape is good, but the ball moves wrongly.
You could try to put the eye-background (the white part that needs to rotate 45 degrees) into a div (or pseudo-element) that's inside the .eye element. In that way you don't need to rotate the container element, so the coordination of the ball element stays the same.
Another point, why are you using that for-loop? I think running the code once will be sufficient :)
EDIT: I've been playing around with your example a bit and fixed it. What happens is that if you rotate an element, the direction in which things will transform (and top/left positioning) will also change. So moving the element 10px to the left, will go 10px to the left, under a 45 degree angle, because it's rotated 45 degrees.
What I did now was to put an element (.inner) inside the eye div, which I gave a counter-rotation of -45 degrees. In this way, the container element of the ball has the correct orientation again, which fixes the problem: https://jsfiddle.net/bxprjvgL/
HTML:
<div class="eye">
<div class="inner">
<div class="shut"><span></span></div>
<div class="ball"></div>
</div>
</div>
CSS:
.inner {
width: 100%;
height: 100%;
transform: rotate(-45deg);
}

Updating position of fixed element on scroll event on unresponsive page

I have a large page running a lot of javascript which also contains a fixed position floating element. The floating element updates its position based on the user's current scroll position, via a function which fires on the scroll event.
The issue I am having is that due to the size and complexity of the page, there is a delay before the code in the scroll event is executed, and this causes the fixed element to noticeably jump when scrolling quickly or using the mouse wheel.
See jsfiddle: http://jsfiddle.net/jorsgj2b/1/ (The use of setTimeout simulates the delay in executing the function on the real page.)
<div class="header"></div>
<div class="main"></div>
<div class="float"></div>
.header {
width: 100%;
height: 200px;
background-color: #787878;
}
.main {
width: 100%;
height: 1400px;
background-color: lightblue;
}
.float {
position: fixed;
width: 100px;
height: 50px;
top: 233px;
right: 25px;
background-color: red;
z-index: 2;
}
$(function() {
$(window).scroll(function() {
setTimeout(updateFloat, 50);
});
});
var updateFloat = function() {
var mainTop = $('.main').offset().top;
var scrollPos = $(window).scrollTop();
var floatOffset = 25;
var newTop = (scrollPos > mainTop)
? floatOffset + 'px'
: mainTop + floatOffset - scrollPos + 'px';
$('.float').css('top', newTop);;
}
I am at a bit of a loss as to how to resolve this. I have tried updating the margin instead of top position, as well as switching between absolute and fixed positioning. Perhaps there is a way to use css transitions to help, however I haven't managed to get them to work here.
You might add position: sticky to your css to that the stickiness is done by browsers that support it (only Firefox and Safari according to caniuse.com).
You'll always be limited to the fidelity of the scroll events so you may always see a bit of a delay, but you could improve things a little by caching values instead of looking them up each time updateFloat() is called. For example
var mainElement = $('.main');
var windowElement = $(window);
var floatElement = $('.float');
var updateFloat = function() {
var mainTop = mainElement.offset().top;
var scrollPos = windowElement.scrollTop();
var floatOffset = 25;
var newTop = (scrollPos > mainTop)
? floatOffset + 'px'
: mainTop + floatOffset - scrollPos + 'px';
floatElement.css('top', newTop);
}
The problem might also be related to browser trying to re-layout the page because the .float element is in the same render layer as the other divs. You can fix that by adding a style that tells the browser to put the .float element in its own render layer (resulting in much faster rendering due to GPU compositing). The most common trick is to add transform: translateZ(0); to your style, but there's also a proposed style will-change that is supported by several browsers. So you should update your css like this
.float {
will-change: scroll-position;
transform: translateZ(0);
position: fixed;
width: 100px;
height: 50px;
top: 233px;
right: 25px;
background-color: red;
z-index: 2;
}
Note that adding render layers increases memory usage so don't go overboard with it. It also sometimes impacts other features, like anti-aliasing of text.

How to user controlled overlap images in JS

I'm desperately searching for solution for my client. I have graphic - something like that:
And I want to be able to take the line with circle in the center and drag it to right or left. And it will be hiding and unhiding my two full images. It's basically two images on the same place, just with another z-index I think.
I think it's possible to do it with JavaScript, but I don't know of any functions or methods for this option.
Here is my solution:
The HTML is pretty simple, just two divs for the images and one for the drag:
<div class="img" id="img1"></div>
<div class="img" id="img2"></div>
<div id="drag"></div>
For the CSS, the important part is to absolute position all the divs and give a background image.
As for the Javascript, with a little help from jQuery, we listen for the mouse events, make some calculations and adjust the CSS of the second image:
$('#drag').on('mousedown', function(e){
var $self = $(this),
dragPos = $self.position().left + $self.width()/2,
imgWidth = $('#img1').width();
$(document).on('mouseup', function(e){
$(document).off('mouseup').off('mousemove');
});
$(document).on('mousemove', function(me){
var mx = me.pageX - e.pageX + dragPos
$self.css({ left: mx });
$('#img2').css({
width: imgWidth - mx,
left: mx,
backgroundPosition: -mx + 'px 0px',
});
});
});
From there, I believe it's pretty easy to customize it and give it a unique look.
Hope this helps!
JsFiddle Demo
Something like this alphamask plugin may do the trick, though I'm not sure how simple it would be for you to implement in the manner of your slider example.
Actually quite simple. The first step is to make it work manually. I'd set it up as follows:
<div class="wrap" id="wrap1">
<div class="img-wrap img1"></div>
<div class="img-wrap img2"></div>
<div>
With CSS as follows:
.wrap {
position: relative;
width: 300px;
height: 300px;
}
.img-wrap {
width: 100%;
height: 100%;
position: absolute;
top: 0px;
left: 0px;
}
.img1 {
z-index: 1;
background: url(bg1.png) no-repeat 0px 0px;
}
.img2 {
z-index: 2;
background: url(bg1.png) no-repeat 0px 0px;
}
Now some JavaScript (with jQuery) to set a position (you can call this when you move a slider over the top later):
function setPosition(percentage){
// get the width of the container
var w = $('#wrap1').width();
// work out the width of left panel
var w1 = Math.floor(w * percentage);
// and the right panel
var w2 = w - w1;
// set the width of the right panel
// move it right by the width of the left panel
// and move the background back by the width of the left panel
$('#wrap1 .img2').css({
width: w2,
left: w1,
backgroundPosition: -w1 + 'px 0px',
});
}
You now just have to decide how to do the dragging. You could even just do it on mouseOver. Easy!

Categories

Resources