I have built a custom cursor, but im having an issue with its position when you scroll the page. Rather than following the mouse cursor, it stays where it was on the page until you move the mouse again and then it catches up.
let mouseCursor = document.querySelector(".cursor");
window.addEventListener('DOMContentLoaded', cursor);
window.addEventListener('mousemove', cursor);
document.addEventListener('mouseenter', () => mouseCursor.style.display = 'block');
document.addEventListener('mouseleave', () => mouseCursor.style.display = 'none');
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i.test(navigator.userAgent)) {
jQuery('.cursor').remove();
} else {
mouseCursor.style.display = 'block';
}
function cursor(e){
mouseCursor.style.top = "calc(" +e.pageY + "px - 1rem)";
mouseCursor.style.left = "calc(" +e.pageX + "px - 1rem)";
}
.section{
height:200vh;
}
.cursor{
display:none;
width: 20px;
height: 20px;
border: 2px solid #f2f2f2;
outline: 2px solid #000;
border-radius: 50%;
position: absolute;
transition: all 0.3s ease;
transition-property: background, transform;
transform-origin: center center;
z-index: 20000;
pointer-events: none;
}
<div class="cursor"></div>
<div class="section"></div>
You need to work with clientX/Y property not pageX/Y.
Because clientX/Y coordinates are relative to the top left corner of the visible part of the page, while pageX/Y is relative to the top left corner of the whole page.
Also, Instead of making your circle position:absolute , you have to change it to position:fixed;
Elements with fixed positioning are fixed with respect to the viewport
CSS absolute and fixed positioning
let mouseCursor = document.querySelector(".cursor");
window.addEventListener('DOMContentLoaded', cursor);
window.addEventListener('mousemove', cursor);
document.addEventListener('mouseenter', () => mouseCursor.style.display = 'block');
document.addEventListener('mouseleave', () => mouseCursor.style.display = 'none');
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i.test(navigator.userAgent)) {
jQuery('.cursor').remove();
} else {
mouseCursor.style.display = 'block';
}
function cursor(e){
mouseCursor.style.top = "calc(" +e.clientY + "px - 1rem)";
mouseCursor.style.left = "calc(" +e.clientX + "px - 1rem)";
}
.section{
height:200vh;
}
.cursor{
display:none;
width: 20px;
height: 20px;
border: 2px solid #f2f2f2;
outline: 2px solid #000;
border-radius: 50%;
position: fixed;
transition: all 0.3s ease;
transition-property: background, transform;
transform-origin: center center;
z-index: 20000;
pointer-events: none;
}
<div class="cursor"></div>
<div class="section"></div>
I have a custom cursor on my site that I want to hide on touch devices (mobile/tablet). I have successfully done this but for a split second when you visit the website the cursor appears in the top left corner then is hidden. Is there any way to stop it displaying at all?
This is the code im using to remove the ID of the cursor on touch devices.
jQuery(document).ready(function($) {
{
if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i.test(navigator.userAgent)) {
$('#custom-cursor').remove();
}
}
});
jQuery(document).ready(function($) {
let cursor = document.querySelector('#custom-cursor');
document.addEventListener('mousemove', evt => {
let { clientX: x, clientY: y } = evt;
let scale = 1;
if (evt.target.matches('a,span,[onclick],img,video,i')) {
cursor.classList.add('active');
scale = 0.5;
} else {
cursor.classList.remove('active');
}
cursor.style.transform = `translate(${x}px, ${y}px) scale(${scale})`;
});
});
* {
cursor: none;
}
#custom-cursor {
position: fixed;
width: 20px; height: 20px;
top: -10px;
left: -10px;
border: 2px solid black;
border-radius: 50%;
opacity: 1;
background-color: #fb4d98;
pointer-events: none;
z-index: 99999999;
transition:
transform ease-out 0.15s,
border 0.5s,
opacity 0.5s,
background-color 0.5s;
}
#custom-cursor.active {
opacity: 0.5;
background-color: #000;
border: 2px solid #fb4d98;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="custom-cursor"></div>
Without seeing more of your code it's not possible to be absolutely sure, but from the info in the question it looks as though the whole page is loaded before the cursor is removed.
You could tackle this in a variety of ways, for example not having the cursor element in the initial HTML but adding it if required onload.
Alternatively you could leave your initial HTML as it is, but set the cursor to have display: none in your CSS. Then onload the JS adds setting the style.display to block if the cursor is not to be removed.
UPDATE: now having seen more of the code here is a snippet to show how the second method (cursor to have display: none until the page is loaded) might be implemented:
jQuery(document).ready(function($) {
let cursor = document.querySelector('#custom-cursor');
if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i.test(navigator.userAgent)) {
$('#custom-cursor').remove();
}
else { cursor.style.display = 'block';}
document.addEventListener('mousemove', evt => {
let { clientX: x, clientY: y } = evt;
let scale = 1;
if (evt.target.matches('a,span,[onclick],img,video,i')) {
cursor.classList.add('active');
scale = 0.5;
} else {
cursor.classList.remove('active');
}
cursor.style.transform = `translate(${x}px, ${y}px) scale(${scale})`;
});
});
* {
cursor: none;
}
#custom-cursor {
position: fixed;
width: 20px; height: 20px;
top: -10px;
left: -10px;
border: 2px solid black;
border-radius: 50%;
opacity: 1;
background-color: #fb4d98;
pointer-events: none;
z-index: 99999999;
transition:
transform ease-out 0.15s,
border 0.5s,
opacity 0.5s,
background-color 0.5s;
display: none;
}
#custom-cursor.active {
opacity: 0.5;
background-color: #000;
border: 2px solid #fb4d98;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="custom-cursor"></div>
I have a cursor element that follows the mouse X and Y position. But once it hovers a text element of the menu, I want this cursor follower to change in size and position.
Size = to the offset width and height of the text being hovered
position = to remain at offset Y and X of that text being hovered and only while being hovered.
So far I have this but I believe is not working. Any suggestions on how should I continue? thanks for your kind words!
let cursor = document.querySelector('.cursorFollower');
let button = document.querySelector('.superText');
let buttonWidth = button.offsetWidth;
let buttonHeight = button.offsetHeight;
let buttonX = button.offsetLeft;
let buttonY = button.offsetTop;
document.addEventListener('mousemove',(e)=>{
cursor.style.left = e.pageX - 10 + 'px';
cursor.style.top = e.pageY - 10 + 'px';
});
button.onmouseover = function(){
button.setAttribute("style", "color: #84C4B5;");
cursor.style.transform = 'rotate(0deg)';
cursor.style.width = buttonWidth + 'px';
cursor.style.height = buttonHeight + 'px';
cursor.style.top = buttonY + 'px';
};
button.onmouseout = function(){
button.setAttribute("style", "color: white;");
cursor.style.transform = 'rotate(45deg)';
cursor.style.width = '20px';
cursor.style.height = '20px';
};
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width:100%;
height: 100vh;
background-color: #0A193E;
color: white;
font-family: sans-serif;
font-size: 20px;
}
.superText {
padding: 10px 20px;
cursor: none;
transition: all 0.2s ease;
}
.cursorFollower {
width: 20px;
height: 20px;
position: absolute;
border: 1px solid white;
transition: all 0.2s ease-out;
pointer-events: none;
transform: rotate(45deg);
}
<div class="container">
<p class="superText">Hello World!</p>
</div>
<div class="cursorFollower"></div>
Your first problem was that you used SetAttribute that is false and you should use setAttribute. (just attend to camelcase!)
And the second thing you didn't notice is that left, top, width, height aren't element attributes. they are for the style attribute!
so please use this code:
button.onmouseover = function (e) {
cursor.setAttribute("style", `left: ${buttonX}, top: ${buttonY}, width: ${buttonWidth}, height: ${buttonHeight}`);
};
I created a custom cursor with JavaScript. – At the end of this question, I will add all the code, there is also a fiddle here: https://jsfiddle.net/8a9f2s0n/ …but what's really important is the following line of CSS: transition: all .1s ease-out;
Basically I'm deleting the actual cursor and then I'm chaining two circles to the mouse position, the second circle ("cursor2") has this CSS-property: transition: all .1s ease-out;, to make it move with some easing.
The Problem:
I tested this code in all the big browsers and it's really smooth everywhere, except for Safari, in Safari the second, larger, circle move REALLY laggy.
What's going on?
var cursor = document.querySelector(".cursor");
var cursor2 = document.querySelector(".cursor_2");
var detectIfCursorStatic = undefined;
window.addEventListener('mousemove', function(e){
// Chain "cursor" and "cursor2" to mouse-position. START
cursor.style.top = e.y + "px";
cursor.style.left = e.x + "px";
cursor2.style.top = e.y + "px";
cursor2.style.left = e.x + "px";
// Chain "cursor" and "cursor2" to mouse-position. END
cursor.style.display = "block";
cursor2.style.display = "block";
cursor2.style.transform = "translate(-50%, -50%) scale(1)";
// Change cursor2, when mouse sits still. START
clearTimeout(detectIfCursorStatic);
detectIfCursorStatic = setTimeout(function(){
cursor2.style.transform = "translate(-50%, -50%) scale(1.3)";
setTimeout(function(){
cursor2.style.transform = "translate(-50%, -50%) scale(0)";
}, 200);
}, 500);
// Change cursor2, when mouse sits still. END
});
// Make it, so that when the cursor leaves the viewport, "cursor" and "cursor2" instantly disappear, but when entering the viewport, they blend in. START
document.addEventListener('mouseout', function(){
cursor.style.opacity = "0";
cursor2.style.opacity = "0";
setTimeout(function(){
cursor.style.transition = "opacity .5s linear"
}, 500);
});
document.addEventListener('mouseover', function(){
cursor.style.opacity = "1";
cursor2.style.opacity = ".3";
setTimeout(function(){
cursor.style.transition = "opacity 0s linear"
}, 500);
});
// … END
// Make it, so that, when the cursor is hovering over an object, with the class: "cursorInteraction", "cursor" and "cursor2" change colour. START
var cursorInteractionObjects = document.querySelectorAll(".cursorInteraction");
cursorInteractionObjects.forEach(function(element){
element.addEventListener('mouseenter', function(){
cursor.style.backgroundColor = "black";
cursor2.style.backgroundColor = "black";
cursor2.style.opacity = ".2";
});
element.addEventListener('mouseleave', function(){
cursor.style.backgroundColor = "white";
cursor2.style.backgroundColor = "white";
cursor2.style.opacity = ".3";
});
});
// … END
// Example: The custom-cursor is white, it is moved over an object, with the class: "cursorInteraction" and a background-color, of: white, the custom-cursor changes to black. – Inside the object, that the cursor is currently in, there is another object, a button, with: "background-color: black", on :hover, so the custom-cursor has to change again, in this case the custom-cursor will change in such a way, that it is no longer visible. – Such buttons, are assigned the following class: "cursorInteraction_Negative".
var cursorInteractionObjects_Negative = document.querySelectorAll(".cursorInteraction_Negative");
cursorInteractionObjects_Negative.forEach(function(element){
element.addEventListener('mouseenter', function(){
cursor.style.opacity = "0";
cursor2.style.zIndex = "-1";
});
element.addEventListener('mouseleave', function(){
cursor.style.opacity = "1";
cursor2.style.zIndex = "0";
});
});
// … END
#charset "UTF-8";
/* CSS Document */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
list-style: none;
cursor: none;
}
a {
text-decoration: none;
color: black;
}
a:hover {
color: white;
}
body {
background-color: black;
}
body, html {
height: 100%; /* <- Firefox needs this. – This might not be necessary in the final website, because there will be objects spanning the whole viewport. */
}
.test_div {
background-color: white;
position: fixed;
width: 400px;
height: 200px;
margin: 15px;
display: flex;
justify-content: center;
align-items: center;
}
.test_button {
border: 1px solid black;
height: 50px;
width: 150px;
line-height: 50px;
text-align: center;
font-family: proxima-nova, sans-serif;
}
.test_button:hover {
background-color: black;
}
/* Custom Cursor START */
.cursor {
z-index: 10;
width: .5rem;
height: .5rem;
border-radius: 50%;
background-color: white;
position: fixed;
transform: translate(-50%, -50%);
pointer-events: none;
display: none;
}
.cursor_2 {
z-index: 9;
width: 2rem;
height: 2rem;
border-radius: 50%;
background-color: white;
opacity: .3;
position: fixed;
transform: translate(-50%, -50%);
pointer-events: none;
display: none;
transition: all .1s ease-out;
}
/* Custom Cursor END */
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Personal-Website Build-5</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="test_div cursorInteraction">
Test Link
</div>
<!-- Custom-Cursor START -->
<div class="cursor"></div>
<div class="cursor_2"></div>
<script src="scripts/customCursor.js"></script>
<!-- Custom-Cursor END -->
</body>
</html>
It seems like in Safari every time the transition property is updated it resets the transition effect. This is causing the lag effect. To get around this you can throttle the code that updates cursor2 position using underscore throttle function or your preferred implementation.
Example is below:
var cursor = document.querySelector(".cursor");
var cursor2 = document.querySelector(".cursor_2");
var detectIfCursorStatic = undefined;
var updateCursor2 = _(function(e) {
cursor2.style.top = e.y + "px";
cursor2.style.left = e.x + "px";
}).throttle(50);
window.addEventListener('mousemove', function(e){
// Chain "cursor" and "cursor2" to mouse-position. START
cursor.style.top = e.y + "px";
cursor.style.left = e.x + "px";
updateCursor2(e);
// Chain "cursor" and "cursor2" to mouse-position. END
cursor.style.display = "block";
cursor2.style.display = "block";
cursor2.style.transform = "translate(-50%, -50%) scale(1)";
// Change cursor2, when mouse sits still. START
clearTimeout(detectIfCursorStatic);
detectIfCursorStatic = setTimeout(function(){
cursor2.style.transform = "translate(-50%, -50%) scale(1.3)";
setTimeout(function(){
cursor2.style.transform = "translate(-50%, -50%) scale(0)";
}, 200);
}, 500);
// Change cursor2, when mouse sits still. END
});
// Make it, so that when the cursor leaves the viewport, "cursor" and "cursor2" instantly disappear, but when entering the viewport, they blend in. START
document.addEventListener('mouseout', function(){
cursor.style.opacity = "0";
cursor2.style.opacity = "0";
setTimeout(function(){
cursor.style.transition = "opacity .5s linear"
}, 500);
});
document.addEventListener('mouseover', function(){
cursor.style.opacity = "1";
cursor2.style.opacity = ".3";
setTimeout(function(){
cursor.style.transition = "opacity 0s linear"
}, 500);
});
// … END
// Make it, so that, when the cursor is hovering over an object, with the class: "cursorInteraction", "cursor" and "cursor2" change colour. START
var cursorInteractionObjects = document.querySelectorAll(".cursorInteraction");
cursorInteractionObjects.forEach(function(element){
element.addEventListener('mouseenter', function(){
cursor.style.backgroundColor = "black";
cursor2.style.backgroundColor = "black";
cursor2.style.opacity = ".2";
});
element.addEventListener('mouseleave', function(){
cursor.style.backgroundColor = "white";
cursor2.style.backgroundColor = "white";
cursor2.style.opacity = ".3";
});
});
// … END
// Example: The custom-cursor is white, it is moved over an object, with the class: "cursorInteraction" and a background-color, of: white, the custom-cursor changes to black. – Inside the object, that the cursor is currently in, there is another object, a button, with: "background-color: black", on :hover, so the custom-cursor has to change again, in this case the custom-cursor will change in such a way, that it is no longer visible. – Such buttons, are assigned the following class: "cursorInteraction_Negative".
var cursorInteractionObjects_Negative = document.querySelectorAll(".cursorInteraction_Negative");
cursorInteractionObjects_Negative.forEach(function(element){
element.addEventListener('mouseenter', function(){
cursor.style.opacity = "0";
cursor2.style.zIndex = "-1";
});
element.addEventListener('mouseleave', function(){
cursor.style.opacity = "1";
cursor2.style.zIndex = "0";
});
});
// … END
#charset "UTF-8";
/* CSS Document */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
list-style: none;
cursor: none;
}
a {
text-decoration: none;
color: black;
}
a:hover {
color: white;
}
body {
background-color: black;
}
body, html {
height: 100%; /* <- Firefox needs this. – This might not be necessary in the final website, because there will be objects spanning the whole viewport. */
}
.test_div {
background-color: white;
position: fixed;
width: 400px;
height: 200px;
margin: 15px;
display: flex;
justify-content: center;
align-items: center;
}
.test_button {
border: 1px solid black;
height: 50px;
width: 150px;
line-height: 50px;
text-align: center;
font-family: proxima-nova, sans-serif;
}
.test_button:hover {
background-color: black;
}
/* Custom Cursor START */
.cursor {
z-index: 10;
width: .5rem;
height: .5rem;
border-radius: 50%;
background-color: white;
position: fixed;
transform: translate(-50%, -50%);
pointer-events: none;
display: none;
}
.cursor_2 {
z-index: 9;
width: 2rem;
height: 2rem;
border-radius: 50%;
background-color: white;
opacity: .3;
position: fixed;
transform: translate(-50%, -50%);
pointer-events: none;
display: none;
transition: all .1s ease-out;
}
/* Custom Cursor END */
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Personal-Website Build-5</title>
<link rel="stylesheet" href="style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.12.0/underscore-min.js" integrity="sha512-BDXGXSvYeLxaldQeYJZVWXJmkisgMlECofWFXKpWwXnfcp/R708nrs/BtNLH5cb/5TE7aeYRTDBRXu6kRL4VeQ==" crossorigin="anonymous"></script>
</head>
<body>
<div class="test_div cursorInteraction">
Test Link
</div>
<!-- Custom-Cursor START -->
<div class="cursor"></div>
<div class="cursor_2"></div>
<script src="scripts/customCursor.js"></script>
<!-- Custom-Cursor END -->
</body>
</html>
I'm trying to create some very basic tooltips but I'm having trouble calculating the exact position these should go in with some JavaScript. The reason for wanting a fixed position is to make sure these work whenever there is overflow hidden and such.
This is my code so far:
var overflowTooltip = function (elem) {
let legendRow = elem.currentTarget.getBoundingClientRect();
let tooltip = elem.currentTarget.children[2];
let topPosition;
let leftPosition;
if ((elem.currentTarget.offsetWidth < elem.currentTarget.scrollWidth) && tooltip !== undefined) {
tooltip.classList.add('total-opacity');
$timeout(function () {
if (tooltip.offsetHeight > 35) {
topPosition = (legendRow.top - tooltip.offsetHeight / 4) - 65;
} else {
topPosition = legendRow.top - 65;
}
leftPosition = (legendRow.left + elem.currentTarget.offsetWidth) / 2;
tooltip.style.left = leftPosition + 'px';
tooltip.style.top = topPosition + 'px';
$timeout(function () {
tooltip.classList.remove('total-opacity');
}, 400)
}, 100);
} else {
elem.currentTarget.children[2].style.left = '-9999px';
}
}
And some SASS:
.custom-tooltip {
font-family: $brand-font-condensed;
font-size: 14px;
font-weight: 400;
position: fixed;
text-align: left;
overflow: visible !important;
background-color: rgba($dark-gray, 0.95);
color: #fff;
height: auto;
padding: 7px 10px;
z-index: 9000;
visibility: hidden;
opacity: 0;
border-radius: 2px;
box-shadow: 0 2px 5px 0 rgba(#000, 0.16), 0 2px 10px 0 rgba(#000, 0.12);
#include transition (.2s ease-in);
left: -9999px;
&:hover {
visibility: visible;
opacity: 1;
#include transition (.2s ease-out);
-webkit-transition-delay: .3s;
transition-delay: .3s;
}
}
The above works but it's not perfect. if I wanna change around the position for it to appear on the left, right, bottom. I'd have to so some refactoring. If the tooltip's height is bigger or smaller, the position changes, If I scroll up or down, the tooltip stays stuck on screen for a few seconds. etc. Lots of these little details which are pretty annoying.
Not interested in using a plugin at the moment nor jQuery. Thanks for any suggestion or feedback :)