CSS click animation with opacity and particles - javascript

I want to make a custom click animation for my website, I want to do something like this:
Here's a capture from that gif
My first aproach was something like this:
It has some problems, for example when I click the animation is triggered but the animation follows the mouse instead of stay in the clicks coords, it lacks of many things like those shiny particles that spread across the click zone and that blurred halo, I dont know how to do this thing, someone know what should I do to accomplish this? like, what should I study or search to get what I want? I lack of expertise so I would really like some little guidance or anything
I dont know if this helps even a little bit but still I'll paste the code of my first approach
const cursor = document.querySelector('.cursor');
document.addEventListener('mousemove', e => {
cursor.setAttribute("style", "top: " + (e.pageY - 10) + "px; left: " + (e.pageX - 10) + "px;");
})
document.addEventListener('click', () => {
cursor.classList.add("expand");
setTimeout(() => {
cursor.classList.remove("expand");
}, 500);
})
body {
margin: 0;
height: 100vh;
background-color: black;
}
.cursor {
width: 20px;
height: 20px;
border-radius: 50%;
position: absolute;
}
#keyframes cursorAnim3 {
0% {
transform: scale(1);
}
50% {
transform: scale(1.5);
opacity: 0.5;
}
100% {
transform: scale(1);
opacity: 0;
}
}
.expand {
animation: cursorAnim3 .3s forwards;
border: 2px solid rgba(255, 255, 255, 0.7);
}
<div class="cursor"></div>
Any suggestion is welcome :c

What I added to your code is an if statement inside of your mousemove event. I don't know how to explain, I just added it and it works... Hope that's what you wanted! :) PS: I also added overflow-x: hidden and overflow-y: hidden since the body size was increasing. It is located inside of
body {
}
const cursor = document.querySelector('.cursor');
document.addEventListener('mousemove', e => {
if (cursor.classList.length === 1) {
cursor.setAttribute("style", "top: " + (e.pageY - 10) + "px; left: " + (e.pageX - 10) + "px;");
}
})
document.addEventListener('click', () => {
cursor.classList.add("expand");
setTimeout(() => {
cursor.classList.remove("expand");
}, 500);
})
body {
margin: 0;
height: 100vh;
overflow-x: hidden;
overflow-y: hidden;
background-color: black;
}
.cursor {
width: 20px;
height: 20px;
border-radius: 50%;
position: absolute;
}
#keyframes cursorAnim3 {
0% {
transform: scale(1);
}
50% {
transform: scale(1.5);
opacity: 0.5;
}
100% {
transform: scale(1);
opacity: 0;
}
}
.expand {
animation: cursorAnim3 .3s forwards;
border: 2px solid rgba(255, 255, 255, 0.7);
}
<div class="cursor"></div>

Related

stacked cards carousel: looping z-index with jquery

I'm trying to create a carousel of stacked cards using CSS animations and Jquery.
The DOM elements are the following:
<div class="container">
<div class="card active" style="background:orange;z-index:4">
1
</div>
<div class="card" style="background:tan;z-index:3">
2
</div>
<div class="card" style="background:pink;z-index:2">
3
</div>
<div class="card" style="background:blue;z-index:1">
4
</div>
</div>
what i need to to is having
the z-index:4 card to become z-index:1
the z-index:3 card to become z-index: 4
the z-index:2 card to become z-index: 3
the z-index:1 card to become z-index: 2
you get the point: the first card needs to be pushed back in the stack, the others should move "up" one level.
Here's a semi-working fiddle: https://jsfiddle.net/p34yzmhv/
I'm no JS expert, i really don't know how to loop the zindex value. I've been reading similar questions here on stackoverflow but couldn't find something exactly similar to my problem.
thanks any hint or help is greatly appreciated.
You can put the z-index within a class and then change the class.
This also allows you to update the positions currently set with .card+.card+.card(etc) without which, your card1 would go to the back, but be position to be unseeable.
The alternative would be to move the elements in the DOM, which may or may not be simpler depending on what else you do with the cards.
Keeping with z4 = z-index=4 => positioned at the front (rather than more logical 1=at the front), add classes:
.z4 {
z-index: 4;
}
.z3 {
transform: rotate(2deg) translate3d(-50%, -50%, 0);
z-index: 3;
}
etc
Then, each iteration, remove all classes and add them back starting with the now current .active. .nextAll gives the following siblings while .prevAll gives the preceding siblings. Only .prevAll gives them in the reverse order so you also need to reverse that.
$(".card").removeClass("z1 z2 z3 z4");
let z=4;
$(".card.active").addClass("z"+z);
$(".card.active").nextAll(".card").each((i, e) => { z--; $(e).addClass("z"+z); });
$($(".card.active").prevAll(".card").get().reverse()).each((i, e) => { z--; $(e).addClass("z"+z); });
// console.log to confirm they're in the correct order
$(".card").each((i, e) => console.log(i, $(e).text(), e.className));
Updated snippet:
$(".btn2").click(function () {
setTimeout(function () {
var $next = $(".card.active").removeClass("active").next(".card");
if ($next.length) {
$next.addClass("active");
} else {
$(".card:first").addClass("active");
}
$(".card").removeClass("z1 z2 z3 z4");
var z=4;
$(".card.active").addClass("z"+z);
$(".card.active").nextAll(".card").each((i, e) => { z--; $(e).addClass("z"+z); });
$($(".card.active").prevAll(".card").get().reverse()).each((i, e) => { z--; $(e).addClass("z"+z); });
$(".card").each((i, e) => console.log(i, $(e).text(), e.className));
}, 1);
$(".card.active")
.addClass("animation")
.one(
"animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd",
function () {
$(".card").removeClass("animation");
}
);
});
#keyframes animation {
0% {
transform: rotate(0) translate3d(-50%, -50%, 0) scale(1);
opacity: 1;
z-index: 10;
}
15% {
opacity: 1;
z-index: 10;
transform: rotate(2deg) translate3d(-50%, -50%, 0) scale(1.1);
}
50% {
transform: rotate(-40deg) translate3d(-320%, -50%, 0) scale(0.1);
opacity: 0;
z-index: 0;
}
75% {
opacity: 1;
}
100% {
transform: rotate(0) translate3d(-50%, -50%, 0) scale(1);
opacity: 1;
z-index: 0;
}
}
.animation {
animation: animation 1s forwards cubic-bezier(0.83, 0, 0.17, 1);
}
.card {
transform-origin: center;
transform: rotate(0) translate3d(-50%, -50%, 0);
transition: all 1s cubic-bezier(0.22, 1, 0.36, 1);
&.active {
transform: rotate(0) translate3d(-50%, -50%, 0)!important;
}
}
// --------------------------------------------
// --------------- DEMO STYLES ----------------
// --------------------------------------------
html {
height: 100%;
}
body {
box-sizing: border-box;
margin: 0;
padding: 0;
* {
box-sizing: inherit;
}
}
.btn2 {
position: fixed;
left: 50%;
bottom: 10%;
transform: translateX(-50%) translateY(-50%);
background: coral;
cursor: pointer;
color: white;
padding: 24px;
text-transform: uppercase;
z-index: 50;
zoom: 1.2;
}
.container {
width: 420px;
height: 480px;
background: #eee;
overflow: hidden;
margin: 0 auto;
position: relative;
padding: 20px;
}
.card {
border-radius: 24px;
display: flex;
align-items: center;
justify-content: center;
min-height: 400px;
max-width: 320px;
position: absolute;
top: 50%;
left: 50%;
width: 100%;
&.active {
box-shadow: 0 0 20px rgba(black, 0.25);
border: 1px solid black;
}
}
.z4 {
z-index: 4;
}
.z3 {
transform: rotate(2deg) translate3d(-50%, -50%, 0);
z-index: 3;
}
.z2 {
transform: rotate(4deg) translate3d(-50%, -50%, 0);
z-index: 2;
}
.z1 {
transform: rotate(6deg) translate3d(-50%, -50%, 0);
z-index: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="card active z4" style="background:orange">1</div>
<div class="card z3" style="background:tan">2</div>
<div class="card z2" style="background:pink">3</div>
<div class="card z1" style="background:blue">4</div>
</div>
<div class="btn2">
animate
</div>
Updated fiddle: https://jsfiddle.net/7z39mqdt/

Custom cursor is reset to top left of page every time a new page is loaded

I have a custom cursor on my site that is working perfectly apart from one thing. When clicking through to a new page, when the page loads the cursor resets itself to the top left of the page regardless of where you leave the mouse on the page, then once you moved the mouse the cursor moves back to where the mouse is. I have tried removing "top" & "left" from the CSS but the problem remains. I cant see what is causing this to happen, and I just need the cursor to stay where the mouse is positioned on the page and not reset every time you navigate to a new page.
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 {
display: none;
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>
Use ordinary CSS cursor as shown in the other answer and replace it with you fancy cursor in the first mouse event:
jQuery(document).ready(function($) {
let cursor = document.querySelector('#custom-cursor');
document.addEventListener('mousemove', evt => {
document.body.classList.add('custom-cursor-moved')
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i.test(navigator.userAgent)) {
$('#custom-cursor').remove();
} else {
cursor.style.display = 'block';
}
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})`;
});
});
body {
height: 100vh;
}
html,
body {
margin: 0;
padding: 0;
}
* {
cursor: url(https://i.stack.imgur.com/7pmmV.png) 0 0, auto;
}
.custom-cursor-moved,
.custom-cursor-moved * {
cursor: none !important;
}
#custom-cursor {
display: none;
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>
Try me.<br> Try me.
It needs a bit of modifications (better cursor image, fix it hotspot etc.) but it works.
Be very, very careful when doing such thing. Try to not break any accessibility tools and please do not assume that Android/some specific user-agent HAS touchscreen, etc.. Use proper APIs.
Use CSS cursor property instead:
html {
cursor: url(https://cdn.sstatic.net/Sites/stackoverflow/Img/favicon.ico?v=ec617d715196) 0 0, auto;
height: 100%;
}
Try me.

Execute a function when mouse is over any button

So I have a page where I have replaced my cursor with a div.
The cursor is simply a part of the page that I can animate using CSS.
The main thing I want to achieve is to make this cursor change size when I hover over any button.
I cannot get it to work...
Cursor positioning is handled by a JQuery script but the vanilla one doesn't seem like it wants to work with me...
I can can't fix the error...
// Jquery code that moves the cursor (div element)
$(document).on('mousemove', function(e){
$('#cursor').css({
left: e.pageX - 7,
top: e.pageY - 7
});
});
// Function to be executed when mouse is over a button
document.querySelectorAll('button').addEventListener("mouseover", cursorHovering);
function cursorHovering() {
document.getElementById('object').style = "transform: scale(2);";
}
body {
height: 300px;
width: 300px;
background-color: #ccc;
}
*, body { cursor: none !important; }
#cursor {
position: fixed;
z-index: 20000;
height: 15px;
width: 15px;
background-color: #ffffff;
mix-blend-mode: difference;
border-radius: 50%;
opacity: 0;
transition: 0.3s;
transition-property: transform, opacity;
pointer-events: none;
}
body:hover #cursor {
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<div id="cursor"></div>
<button class="button1">Hover over me (1)</button>
<button class="button2">Hover over me (2)</button>
<button class="button3">Hover over me (3)</button>
</body>
You mean something like this?
// Jquery code that moves the cursor (div element)
var c = document.getElementById('cursor');
document.addEventListener('mousemove', (e) => {
c.style.left = e.pageX - 7 + 'px';
c.style.top = e.pageY - 7 + 'px';
});
// Function to be executed when mouse is over a button
document
.querySelectorAll('button')
.forEach(b => {
b.addEventListener("mouseover", () => c.style.transform='scale(2)');
b.addEventListener("mouseout", () => c.style.transform='scale(1)');
});
body {
height: 300px;
width: 300px;
background-color: #ccc;
}
*, body { cursor: none !important; }
#cursor {
position: fixed;
z-index: 20000;
height: 15px;
width: 15px;
background-color: #ffffff;
mix-blend-mode: difference;
border-radius: 50%;
opacity: 0;
transition: 0.3s;
transition-property: transform, opacity;
pointer-events: none;
}
body:hover #cursor {
opacity: 1;
}
<body>
<div id="cursor"></div>
<button class="button1">Hover over me (1)</button>
<button class="button2">Hover over me (2)</button>
<button class="button3">Hover over me (3)</button>
</body>
Here's a vanilla JS solution.
document.addEventListener('mousemove', handleMouseMove, false);
// Cache the elements
const cursor = document.getElementById('cursor');
const buttons = document.querySelectorAll('button');
// For each button add the two event listeners
[...buttons].forEach(button => {
button.addEventListener('mouseover', handleMouseOver, false);
button.addEventListener('mouseout', handleMouseOut, false)
});
function handleMouseMove(e) {
// You need to ensure that you add "px" to the
// end of the value. jQuery does this automatically.
cursor.style.left = `${e.pageX - 7}px`;
cursor.style.top = `${e.pageY - 7}px`;
}
function handleMouseOver() {
cursor.style.transform = 'scale(2)';
}
function handleMouseOut() {
cursor.style.transform = 'scale(1)';
}
body {
height: 300px;
width: 300px;
background-color: #ccc;
}
*,
body {
cursor: none !important;
}
#cursor {
position: fixed;
z-index: 20000;
height: 15px;
width: 15px;
background-color: #ffffff;
mix-blend-mode: difference;
border-radius: 50%;
opacity: 0;
transition: 0.3s;
transition-property: transform, opacity;
pointer-events: none;
}
body:hover #cursor {
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<div id="cursor"></div>
<button class="button1">Hover over me (1)</button>
<button class="button2">Hover over me (2)</button>
<button class="button3">Hover over me (3)</button>
</body>

CSS Transition Triggered by JavaScript

I want to have the following JavaScript function to transition function between from have none display to block when generate_loading_screen() is called to to when it finishes transition between display block to none. How do I do this?
function generate_loading_screen() {
window.setInterval(function(){
if (progress_percent < 75) {
document.getElementById("loading_screen").style.display = "block";
document.getElementById("body_of").style.filter = "grayscale(1)";
}
else {
document.getElementById("loading_screen").style.display = "none";
document.getElementById("body_of").style.filter = "none";
stop_generating_loading();
}
}, 50);
};
function stop_generating_loading() {
clearInterval(generate_loading_screen);
};
.loading {
position: fixed;
border: 16px solid #dbdbdb;
border-radius: 50%;
border-top: 16px solid #53f442;
margin-left: 44%;
margin-top: 10%;
width: 120px;
height: 120px;
animation: spin 2s linear infinite;
}
#keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
<div class="loading" id="loading_screen" style="display: none;"></div>
Just extra info: progress_percent is a variable that determines how much of the rest of the web-app has loaded. The grayscale filter does not affect the whole page, just the ID body_of
Thanks in advance
Probably better to use a opacity transition by adding a class when your percent reaches 100.
Codepen for working example or see below.
HTML:
<div class="loading" id="loading_screen"></div>
CSS:
.loading {
position: fixed;
border: 16px solid #dbdbdb;
border-radius: 50%;
border-top: 16px solid #53f442;
margin-left: 44%;
margin-top: 10%;
width: 120px;
height: 120px;
animation: spin 2s linear infinite;
opacity: 100%;
transition: opacity 1s ease-in-out;
}
.done_loading {
opacity: 0;
}
#keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
Javascript:
var progress_percent = 25;
var interval;
function generate_loading_screen() {
interval = window.setInterval(function(){
progress_percent += 1; //totest
if (progress_percent > 75) {
document.getElementById("loading_screen").className = "loading done_loading";
//stop_generating_loading();
}
//TESTING
if(progress_percent > 100){
console.log("Reached 100%");
document.getElementById("loading_screen").className = 'loading';
progress_percent = 0;
}
//
}, 50);
};
function stop_generating_loading() {
clearInterval(interval);
};
document.addEventListener('DOMContentLoaded', function(){
generate_loading_screen();
});
Remove all the testing code to get this to work once, you might need to add additional code for your body div. Let me know if you need me to add more to this example!
window.setInterval returns an intervalId which you need to cancel in order to stop the interval
let timer;
function generate_loading_screen() {
timer = window.setInterval(function(){
if (progress_percent < 75) {
document.getElementById("loading_screen").style.display = "block";
document.getElementById("body_of").style.filter = "grayscale(1)";
}
else {
document.getElementById("loading_screen").style.display = "none";
document.getElementById("body_of").style.filter = "none";
stop_generating_loading();
}
}, 50);
};
function stop_generating_loading() {
clearInterval(timer);
};

Bug when trying to recreate a ripple effect animation in a button (Material design)

I'm trying to emulate a ripple effect when clicking in a button, but I got weird behaviour when happy clicking. I'm coding in vanilla JS for learning purposes. Please could anybody tell me where I've got it wrong?
Here's the full code:
Html
<button class="button button--ok ripple">Button</button>
<button class="button button--cancel ripple">Button</button>
Css
body {
width: 800px;
margin: 0 auto;
padding: 30px 0 0 0;
font: "Helvetica neue", Helvetica, sans-serif;
}
.button {
position: relative;
padding: 10px 20px;
color: #fff;
border: none;
outline: none;
cursor: pointer;
box-shadow: 0 0 4px rgba(0,0,0,.4);
overflow: hidden;
font-size: 16px;
letter-spacing: 1px;
}
.button--ok {
background-color: #65DE65;
}
.button--cancel {
background-color: tomato;
}
.circle {
width: 10px;
height: 10px;
position: absolute;
transform: translate(-50%, -50%);
border-radius: 5px;
background-color: #fff;
}
.ripple.animate .circle {
animation: ripple 2s;
}
#keyframes ripple {
from {
transform: scale(1);
opacity: .4;
}
to {
transform: scale(100);
opacity: 0;
}
}
Js
var ripple = document.getElementsByClassName("ripple");
for (var i = 0; i < ripple.length; i++) {
ripple[i].addEventListener("click", function(e) {
// Store this for later
var self = this;
// Get x and y coordinates
var x = e.offsetY+"px";
var y = e.offsetX+"px";
// Create the layer effect and apply a circle class,
// then set coordinates
var circle = document.createElement("div");
circle.setAttribute("class", "circle");
circle.style.top = x;
circle.style.left = y;
// Append layer effect to parent and add animate class
// to start the animation
self.appendChild(circle);
self.className += " animate";
// Remove layer effect once is done animating (2 seconds)
setTimeout(function() {
var elements = self.getElementsByClassName("circle");
for (var i = 0; i < elements.length; i++) {
self.removeChild(elements[i]);
}
}, 2000);
}, false);
}
Mine: Codepen
Disired: Codepen
Hi I see what you are trying to do and I too tried to explain the bizzare effect. Anyway I tried to do something and it worked, made the .circle .animate to simply .animate and changed the scale(1) to scale(1,1), scale(width,height) setting.
Inside style the changes are:
.animate {
animation: ripple 2s forwards;
-webkit-animation-name:ripple;
-webkit-animation-duration: 2s;
}
#keyframes ripple {
from {
transform: scale(1,1);
opacity: 0.4;
}
to {
transform: scale(100,100);
opacity: 0;
}
}
Here is the jsfiddle. For chrome and safari support added the -webkit- property.

Categories