Enlarge custom cursor pointer on hovering links using JS - javascript

I've been working on a custom cursor that I want to grow when it hovers over objects with a certain property. I started with css, found that unreliable, and now am trying to use js- pure js that is, not jquery.
The cursor movement seems to work well enough, and the bit for transforming the outer circle also seems to throw up no errors at all, which leaves me confused as to whats going on here. Any help would be appreciated.
/*kinda laggy cursor control js */
const cursor = document.querySelector('.cursor');
document.addEventListener('mousemove', e => {
cursor.setAttribute("style", "top: " + e.pageY + "px; left: " + e.pageX + "px;")
})
const cursor2 = document.querySelector('.cursor2');
document.addEventListener('mousemove', e => {
cursor2.setAttribute("style", "top: " + e.pageY + "px; left: " + e.pageX + "px;")
})
const all = document.querySelectorAll(".use");
document.addEventListener('mouseOver', function() {
cursor.style.transform = scale(2)
})
.cursor {
width: 25px;
height: 25px;
position: absolute;
border: 2px solid rgb(41, 41, 41);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: 50ms;
transition-timing-function: ;
mix-blend-mode: difference;
z-index: 200;
pointer-events: none;
}
.cursor2 {
z-index: 200;
transition: 10ms;
width: 5px;
height: 5px;
border-radius: 50%;
background-color: black;
pointer-events: none;
mix-blend-mode: difference;
position: absolute;
transition-timing-function: ;
}
.style {
font-family: 'Helvetica';
font-size: calc(2em + 8vw);
font-weight: 700;
-webkit-text-fill-color: rgba(0, 0, 0, 0);
-webkit-text-stroke: 1px;
-webkit-text-stroke-color: rgb(0, 0, 0);
letter-spacing: -.6vw;
line-height: calc(.7em + 1vw);
animation: marquee 30s linear infinite;
display: inline-block;
user-select: none;
}
a {
text-decoration: none;
cursor: none;
}
a:hover+.cursor {
transform: scale(1.5);
!important transition-duration: 500ms;
}
<div id="style use">hello</div>
<!-- outer cursor div-->
<div class="cursor">
</div>
<!-- inner cursor div-->
<div class="cursor2">
</div>

element.style.transform needs to have a string value (in your case, it should have been 'scale(2)' [a string]). I have added a class enlarged to add the increased width and height styles to your cursor upon mouseenter and mouseout of every link in your document.
Here's a working example.
const cursor = document.querySelector('.cursor');
const cursor2 = document.querySelector('.cursor2');
const links = document.querySelectorAll('a')
links.forEach(link => {
link.addEventListener('mouseenter', e => {
cursor.classList.add('enlarged')
})
link.addEventListener('mouseout', e => {
cursor.classList.remove('enlarged')
})
})
document.addEventListener('mousemove', e => {
cursor.setAttribute("style", "top: " + e.pageY + "px; left: " + e.pageX + "px;")
cursor2.setAttribute("style", "top: " + e.pageY + "px; left: " + e.pageX + "px;")
})
html,
body {
width: 100%;
height: 100%;
margin: 0;
cursor: none;
}
.cursor {
width: 25px;
height: 25px;
position: absolute;
border: 2px solid rgb(41, 41, 41);
border-radius: 50%;
transform: translate(-50%, -50%);
transition:
top 50ms linear,
left 50ms linear,
width 500ms ease,
height 500ms ease;
z-index: 1;
pointer-events: none;
}
.cursor.enlarged {
width: 50px;
height: 50px;
}
.cursor2 {
transition: 10ms;
z-index: 1;
width: 5px;
height: 5px;
border-radius: 50%;
background-color: black;
pointer-events: none;
position: absolute;
transform: translate(-50%, -50%);
}
a {
text-decoration: none;
cursor: none;
font-family: Helvetica;
font-size: 4em;
padding: 15px;
}
<div id="style use">Hello</div>
<!-- outer cursor div-->
<div class="cursor">
</div>
<!-- inner cursor div-->
<div class="cursor2">
</div>

Related

Why "div" with "position: absolute" overflows screen

I watched a tutorial on how to make custom cursor in CSS and JavaScript. I did it, but when I move it down to the bottom of the screen, it overflows and expands unnecessarily website like this:
(this dark circle is the cursor)
I don't know what to do. It works, when I change overflow-y to hidden, but this is not what I want because then every other element on the website is also hidden.
CSS:
html {
font-size: 10px;
overflow-x: hidden;
cursor: none;
}
.cursor {
display: none;
z-index: 10;
position: absolute;
width: 5rem;
height: 5rem;
border-radius: 5rem;
background-color: #000000;
opacity: .4;
transform: translate(-50%, -50%);
pointer-events: none;
transition: all .3s ease;
transition-property: opacity, transform;
transform-origin: 100% 100%;
}
JS:
window.onload = () => {
cursor.style.display = 'inline';
}
const changeCursorPosition = e => {
cursor.style.left = e.pageX + 'px';
cursor.style.top = e.pageY + 'px';
}
window.addEventListener('mouseover', changeCursorPosition);
window.addEventListener('mousemove', changeCursorPosition);
You can always just use an image as the cursor.
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Basic_User_Interface/Using_URL_values_for_the_cursor_property
* {
cursor: url(data:image/png;base64,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) -10 -10, auto;
}

Modified Cursor 'lags'

I am currently building a modified cursor for my portfolio-website. Unfortunately, my cursor lags when I try to scroll and move the cursor. However, it works when I remove all the other elements from HTML, CSS, and JavaScript and ONLY have the code concerning my cursor (https://codepen.io/djaisdjasidj/pen/RwNvePZ).
// Cursor modified
var cursor = document.getElementById('cursor');
document.addEventListener('mousemove', function(e) {
e.stopPropagation();
var x = e.clientX;
var y = e.clientY;
cursor.style.left = x + 'px';
cursor.style.top = y + 'px';
});
// Cursor HOVER modified - When hovering an element
var cursor = document.getElementById('cursor');
var clickableCursor = document.getElementsByClassName('clickableCursor');
for (var i = 0; i < clickableCursor.length; i++) {
clickableCursor[i].addEventListener('mouseover', () => {
cursor.style.height = "80px";
cursor.style.width = "80px";
cursor.style.animation = "cursorAnimation 5s linear infinite";
cursor.style.background = "white";
});
clickableCursor[i].addEventListener('mouseout', () => {
cursor.style.height = "40px";
cursor.style.width = "40px";
cursor.style.animation = "none";
cursor.style.border = "2px solid white";
cursor.style.background = "none";
});
}
body {
cursor: none;
}
.container {
height: 3000px;
width: 100%;
position: relative;
background: orange;
}
#cursor {
backface-visibility: hidden;
z-index: 1000000000;
position: fixed;
width: 40px;
height: 40px;
border: 2px solid white;
transition: .1s;
border-radius: 50%;
pointer-events: none;
transform: translate(-50%, -50%);
display: flex;
align-items: center;
justify-content: center;
transition-duration: 100ms;
transition-timing-function: ease-out;
}
#cursor::before {
content: '';
position: absolute;
height: 7px;
width: 7px;
border-radius: 100%;
background-color: white;
}
.clickableCursor {
font-size: 50px;
color: white;
position: fixed;
background: black;
padding: 50px
}
.one {
top: 50px;
left: 50px;
}
.two {
top: 50px;
right: 50px;
}
<div class="container">
<div id="cursor"></div>
<p class="clickableCursor one"> Hello </p>
</div>
CSS for my Cursor:
#cursor {
backface-visibility: hidden;
z-index: 1000000000;
position: fixed;
width: 40px;
height: 40px;
border: 2px solid white;
transition: .1s;
border-radius: 50%;
pointer-events: none;
transform: translate(-50%, -50%);
display: flex;
align-items: center;
justify-content: center;
transition-duration: 100ms;
transition-timing-function: ease-out;
}
My question is - how do I prevent this cursor 'lag' when I have a bigger HTML, CSS, and JavaScript file?
I had the same problem and i solved it with this code :
(hope it can help you or other developers)
$(window).ready(function(){
let mouseX = 0;
let mouseY = 0;
let xp = 0;
let yp = 0;
$(document).mousemove(function(e){
$(".custom__cursor__inner").css({
transform: 'translate(' + (e.clientX - 3.25) + 'px, ' + (e.clientY - 3.25) + 'px)'
});
mouseX = e.clientX - 10;
mouseY = e.clientY - 10;
});
setInterval(function(){
xp += ((mouseX - xp)/6);
yp += ((mouseY - yp)/6);
$(".custom__cursor__outer").css({transform: 'translateX('+ (xp - 15) +'px) translateY('+ (yp - 15) +'px)'} );
}, 10);
})
*{
cursor: none;
}
.custom__cursor__inner{
height: 7.5px;
width: 7.5px;
position: fixed;
transform: translate(0px, 0px);
background-color: #F7D883;
border-radius: 50%;
transition: height .3s cubic-bezier(0.46,0.03,0.52,0.96), width .3s cubic-bezier(0.46,0.03,0.52,0.96);
z-index: 5000;
pointer-events: none;
}
.custom__cursor__outer{
height: 50px;
width: 50px;
border-radius: 50%;
border: 1px solid #0F1928;
background-color: transparent;
position: fixed;
z-index: 5000;
transform: translate(0px, 0px);
pointer-events: none;
opacity: 0.4;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="custom__cursor__outer">
</div>
<div class="custom__cursor__inner">
</div>
The lag happens because you are using a transition to move the cursor to the current mouse location, explicitly stating that it should be lagging behind 100ms.
You should only apply the CSS transition on the elements and attributes that you want to animate, but not the location of the cursor.
Use the transition-property rule to define which attributes should be "transitioned" or use the transition shorthand syntax to explicitly specify the attribute names like #Tyler Roper does in his comment.

Mouse hover moving image position

I am trying to move an image when my mouse is over it.
Here's an exemple. When moving hover pictures, the text is smoothly following your mouse and this is what I'm looking for.
Do you have any idea ?
The problem with what I tried is that the image keeps moving when I get out of the violet box. (I would prefer to avoid having to create a box and recognize when I am over the image).
$("#containerScaled").on('mousemove', '.box', function (e) {
$("#followC").css("top", e.clientY)
.css("left", e.clientX);
});
<style>
#containerScaled, #followC {
transition: all 0.9s ease-out;
transform-origin: center;
transform: scale(1, 1);
}
.box {
height:50px;
width:50px;
left: 500px;
top: 50px;
background-color: blueviolet;
position: absolute;
}
.mouseFollow {
position: fixed;
width:70px;
height:20px;
font-size:12px;
pointer-events:none;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="containerScaled" class="container">
<div class="box">test</div>
</div>
<div id="followC" class="mouseFollow"><img src=" image "/></div>
I think you should begin with altering your position based on where your mose is positioned inside your rectangel like so:
if (e.clientX > width/2){
addX = 20;
}
if(e.clientX < width/2){
addX = -20;
}
if(e.clientY > height/2){
addY = 20;
}
if(e.clientY < height/2){
addY = -20;
}
This is the first step, that actually makes something "follow" your mouse.
I think you could do some optimization, so that the animation is more crispy, but basically thats the way to go.
I also added
$("#containerScaled").on('mouseleave', '.box', function(e) {
$("#followC").css("top", "50%").css("left", "50%");
});
so that your element will get back to its original position once you leave the :hover area
Because of this I also made you hover area transparent, any lay over the moving element, so that when you hover over the moving element, you wont leave the hover area, and trigger mouseleave
.box{
background-color: transparent;
}
.boxcolored{
position: absolute;
height: 100px;
width: 100px;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
background-color: green;
}
$("#containerScaled").on('mousemove', '.box', function(e) {
var left = parseFloat($(".box").css("left"));
var right = parseFloat($(".box").css("top"));
var width = parseFloat($(".box").css("widht"));
var height = parseFloat($(".box").css("height"));
var addX = 0;
var addY = 0;
if (e.clientX > width/2){
addX = 20;
}
if(e.clientX < width/2){
addX = -20;
}
if(e.clientY > height/2){
addY = 20;
}
if(e.clientY < height/2){
addY = -20;
}
$("#followC").css("top", e.clientY + addY)
.css("left", e.clientX + addX);
});
$("#containerScaled").on('mouseleave', '.box', function(e) {
$("#followC").css("top", "50%").css("left", "50%");
});
#containerScaled {
position: absolute;
top: 0;
left: 0;
width: 200px;
height: 200px;
background-color: red;
}
#followC {
transition: all 0.9s ease-out;
transform-origin: center;
}
.box {
position: absolute;
height: 100px;
width: 100px;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
background-color: transparent;
}
.boxcolored{
position: absolute;
height: 100px;
width: 100px;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
background-color: green;
}
.mouseFollow {
position: relative;
height: 20px;
width: 75px;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="containerScaled" class="container">
<div class="boxcolored"></div>
<div id="followC" class="mouseFollow">HALLO</div>
<div class="box">mouse me</div>
</div>
The box outlined in a red dashed line is the hover area. The yellow box is the visual area which is the approximation of the limits to which the letters can move within.
There is a lag and an offset. The lag is due to transition: 0.9s and the offset is left and top. The lag can be decreased but at the cost of the smooth movement, There are four letters at varying transition times for comparison. Notice that they all stop at the same position (when the mouse is no longer moving within the dashed box), it just that the slower the transition the more movement occurs after the mouse has left the dashed box.
The offset is tougher since there is only two positions that will work: x: right or left and y: top or bottom. If keeping the letters within a box is a concern, then keep the hover area border and background to none and show the offset (visual area) instead.
Note: Do not review this demo in compact mode, view it in full page mode (normal dimensions)
$(".target").on('mousemove', function(e) {
$(".text").css({
"top": e.clientY,
"left": e.clientX
});
});
main {
position:relative;
font: 400 16px/1.2 Arial;
}
.zone {
position: absolute;
z-index: 1;
height: 120px;
width: 110px;
margin: 90px 0 0 90px;
background: gold;
color:white;
text-align:right;
}
.target {
position: absolute;
z-index: 2;
height: 100px;
width: 100px;
margin: 75px;
outline: 3px dashed red;
color:red
}
.text {
position: absolute;
z-index: 3;
top: 90px;
left: 90px;
font-size: 32px;
color:black
}
.A {
transition: all 0.9s ease-out;
}
.B {
transition: all 0.6s ease-out;
}
.C {
transition: all 0.3s ease-out;
}
<main>
<section class="target">Hover Area</section>
<aside class="text A">A</aside>
<aside class="text B">B</aside>
<aside class="text C">C</aside>
<aside class="text D">D</aside>
<section class='zone'><b>Visual Area</b></section>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Js mouseClick event seems to fire on the wrong emelent

I have a simple div to which I'm adding a child. I'm trying to calculate the child's location with evt.clientX and clientY. Instead i seem to be getting the coordinates of the containing element even tho the function is on the divs.
How could i get the click event for the divs instead of the parent? I don't know much about event inheritance if that is even what it's called.
Here is the code:
function initRipple() {
//qck define
let rcont;
rcont = Array.from(document.getElementsByClassName('ripple'));
rcont.forEach(function(el) {
el.addEventListener('click', function(evt) {
ripple(el, evt);
});
});
}
function ripple(el, evt) {
// qck def
let cir, x, y;
// assign values
cir = document.createElement('div');
x = evt.clientX;
y = evt.clientY;
// modify circle attributes / position
cir.classList.add('ripple-bubble');
cir.style.left = `${ x - 12 }px`;
cir.style.top = `${ y - 12 }px`;
cir.addEventListener('animationend', function() {
let oldChild = el.removeChild(cir);
});
el.appendChild(cir);
}
initRipple();
body {background-color: #555}
#tablinks {
display: inline-block;
list-style-type: none;
position: absolute;
top: 0;
height: 100%;
display: flex;
}
#tablinks #tablinks-line {
height: 3px;
position: absolute;
bottom: 0;
left: 0;
min-width: 24px;
background-color: #6DADFF;
transition: all 0.3s ease;
pointer-events: none;
transform: translateZ(0);
}
#tablinks .tablink {
height: 56px;
line-height: 56px;
color: rgba(255, 255, 255, 0.7);
}
#tablinks .tablink.active {
color: #fff;
}
#tablinks .tablink a {
display: inline-block;
height: 56px;
line-height: 56px;
text-decoration: none;
padding: 0 24px;
font-size: 13px;
color: inherit;
outline: none;
font-family: robotomedium;
font-weight: 100;
}
.ripple {
position: relative;
overflow: hidden;
}
.ripple .ripple-bubble {
animation: ripple-effect 1s ease forwards;
width: 24px;
height: 24px;
position: absolute;
transform: translateZ(0);
background-color: rgba(255, 255, 255, 0.2);
border-radius: 50%;
pointer-events: none;
opacity: 0.7;
}
#keyframes ripple-effect {
from {
transform: scale(1);
opacity: 0.7;
}
to {
transform: scale(12);
opacity: 0;
}
}
<ul id="tablinks">
<li class="tablink ripple">TAB 1</li>
<!--
-->
<li class="tablink ripple">TAB 2</li>
<!--
-->
<li class="tablink ripple">TAB 3</li>
</ul>
The problem with your code is that clientX is relative to the whole page, not to the event.
A quick solution would be to change the computation of x to susbtract the x position of your element.
x = evt.clientX;
y = evt.clientY;
const rect = evt.target.getBoundingClientRect()
x -= rect.x;
y -= rect.y;
Here is a working pen: https://codepen.io/anon/pen/WMWZWd

How to morph a plus sign to a minus sign using CSS transition?

I want to create a toggle button that morphs its shape from a plus sign to a minus sign.
Using CSS only, without the use of pseudo-elements.
My desired effect is to have the vertical line in the "+" sign to shrink into the horizontal line.
I know it's possible but I'm not sure which is the best route to take. I was thinking of doing something with the height but I'm worried about the line-height of browsers changing its position in the element.
$('button').on("click", function(){
$(this).toggleClass('active');
});
button {
color: #ecf0f1;
background: #e74c3c;
width: 50px;
height: 50px;
border: 0;
font-size: 1.5em;
}
button span {
transition: all .75s ease-in-out;
}
button.active span {
/* Code to morph + to - */
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button><span>+</span></button>
Because of the simplicity of the shapes, the easiest way is just to make the + and - with elements. Using pseudo elements would be the cleanest solution, but you can also just use a DOM element and have a slightly messier document structure.
With that in mind, the actual solution is straightforward. We use CSS to position elements to resemble the desired characters, and then "morph" between them by animating that position.
Take a look over the following code, and try to understand what each rule is accomplishing.
button {
color: #ecf0f1;
background: #e74c3c;
width: 50px;
height: 50px;
border: 0;
font-size: 1.5em;
position: relative;
}
button span {
position: absolute;
transition: 300ms;
background: white;
border-radius: 2px;
}
/* Create the "+" shape by positioning the spans absolutely */
button span:first-child {
top: 25%;
bottom: 25%;
width: 10%;
left: 45%;
}
button span:last-child {
left: 25%;
right: 25%;
height: 10%;
top: 45%;
}
/* Morph the shape when the button is hovered over */
button:hover span {
transform: rotate(90deg);
}
button:hover span:last-child {
left: 50%;
right: 50%;
}
<button>
<span></span>
<span></span>
</button>
Note : please stop editing the question making the answers incorrect
CSS solution
$('button').on("click", function(){
$(this).toggleClass('active');
});
button {
color: #ecf0f1;
background: #e74c3c;
width: 70px;
height: 70px;
position: relative;
font-size: 50px;
cursor: pointer;
border: 0;
outline: 0;
padding: 0
}
.plus,
.minus {
color: #fff;
padding: 10px;
width: 70px;
height: 70px;
line-height: 50px;
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
text-align: center;
box-sizing: border-box;
transition: .5s all ease-out;
}
.plus {
opacity: 1;
transform: rotate(0deg);
}
button.active .plus {
opacity: 0;
transform: rotate(90deg);
}
.minus {
opacity: 0;
transform: rotate(-90deg);
}
button.active .minus {
opacity: 1;
transform: rotate(0deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" />
<button>
<span class="plus"><i class="fa fa-plus"></i></span>
<span class="minus"><i class="fa fa-minus"></i></span>
</button>
A (old) CSS solution:
Using pseudo element ::before with content property
$('button').on("click", function() {
$(this).toggleClass('active');
});
button {
color: #ecf0f1;
background: #e74c3c;
width: 50px;
height: 50px;
border: 0;
font-size: 1.5em;
}
button span {
transition: all .75s ease-in-out;
position:relative
}
button span::before {
content:"+"
}
button.active span::before {
content:"-"
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button><span></span></button>
A (old) jquery Solution:
no need for span, you can do this using text() with a if statement in jquery
$('button').on("click", function() {
$(this).toggleClass('active');
$(this).text() == "+" ? $(this).text("-") : $(this).text("+");
});
button {
color: #ecf0f1;
background: #e74c3c;
width: 50px;
height: 50px;
border: 0;
font-size: 1.5em;
transition: all .75s ease-in-out;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button>+</button>
Ah my bad I've overlooked that OP doesn't want to use any pseudo
elements. But the big advantage with pseudo elements would be that you have less HTML Code and a cleaner structure.
It's also a different morphing animation as OP wants but maybe someone else can use this.
So if you don't mind I'll let my suggestion there.
Maybe something like this?
HTML
<div class="button"></div>
CSS
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
}
body {
margin: 0;
background: #343838;
}
.button {
position: absolute;
width: 55px;
height: 55px;
background: #70975B;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(0deg);
border-radius: 50%;
cursor: pointer;
z-index: 100;
transition: 0.4s cubic-bezier(0.2, 0.6, 0.3, 1.1);
}
.button:after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 2px;
width: 50%;
background: white;
}
.button:before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 50%;
width: 2px;
background: white;
}
.button.clicked {
transform: translate(-50%, -50%) rotate(360deg);
background: #CC2A41;
}
.button.clicked:before {
width: 0;
}
jQuery
$(".button").click(function() {
$(this).toggleClass("clicked");
});
And here a working example
http://codepen.io/svelts/pen/LkyZoZ
try this
$('button').on("click", function() {
var $this = $(this);
$this.toggleClass('toggle');
if ($this.hasClass('toggle')) {
$this.text('+');
} else {
$this.text('-');
}
});
button {
color: #ecf0f1;
background: #e74c3c;
width: 50px;
height: 50px;
border: 0;
font-size: 1.5em;
transition: all .75s ease-in-out;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button class="toggle">+</button>

Categories