Codepen snippet not working on local machine - javascript

I modified and copied a snippet from codepen to my local machine. I linked the css and js files with html file. But the css part is not working properly. The code was working fine in codepen.
index.html
<head>
<link src="http://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet">
<link src="https://fonts.googleapis.com/css2?family=Nunito:wght#800&display=swap" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="./styles.css" />
</head>
<body>
<menu class="menu">
<button class="menu__item active">
<div class="menu__icon" >
<i class="fa-solid fa-house"></i>
</div>
<strong class="menu__text active">home</strong>
</button>
<button class="menu__item">
<div class="menu__icon" >
<i class="fa-solid fa-user"></i>
</div>
<strong class="menu__text">About</strong>
</button>
<button class="menu__item">
<div class="menu__icon" >
<i class="fa-solid fa-briefcase"></i>
</div>
<strong class="menu__text">
Products</strong>
</button>
<button class="menu__item">
<div class="menu__icon" >
<i class="fa-solid fa-question"></i>
</div>
<strong class="menu__text">
Concerns</strong>
</button>
<button class="menu__item">
<div class="menu__icon" >
<i class="fa-solid fa-blog"></i>
</div>
<strong class="menu__text">
Blog</strong>
</button>
<button class="menu__item">
<div class="menu__icon" >
<i class="fa-solid fa-envelope"></i>
</div>
<strong class="menu__text">Contact</strong>
</button>
</menu>
<script src="./index.js"></script>
</body>
styles.css
#import url('https://fonts.googleapis.com/css2?family=Nunito:wght#800&display=swap');
html {
box-sizing: border-box ;
--duration: .45s ;
--cubic: cubic-bezier(0.4, 0, 0.2, 1) ;
--color-1: white ;
--color-2: #000 ;
--theme-bg-color:rgba(16 18 27 / 40%)
--border-color: rgba(113 119 144 / 25%);
--theme-color: #f9fafb;
}
html *,
html *::before,
html *::after {
box-sizing: inherit ;
}
body {
margin: 0 ;
height: 20vh ;
display: flex ;
overflow: hidden ;
align-items: center ;
justify-content: center ; background: #2193b0;
background: -webkit-linear-gradient(to left, #6dd5ed, #2193b0);
background: linear-gradient(to left, #6dd5ed, #2193b0);
font-family: 'Dosis', sans-serif ;
}
.menu {
margin: 0 ;
width: 45em;
display: flex ;
height: 5em ;
user-select: none ;
position: relative ;
align-items: center ;
padding: 0 1.7em ;
justify-content: center ;
/* From https://css.glass */
background: rgba(245, 245, 245, 0.4);
border-radius: 16px;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: 1em 1em 2.5em 2.5em;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
max-width: 1250px;
max-height: 860px;
-webkit-tap-highlight-color: transparent ;
}
#media (max-width: 42.625em) {
.menu {
font-size: .55em ;
}
}
.menu__item {
all: unset ;
flex-grow: 1 ;
display: flex ;
cursor: pointer ;
overflow: hidden ;
padding-top: 0.5em ;
position: relative ;
align-items: left ;
color: var(--color-1) ;
justify-content: center ;
transition: flex-grow var(--duration) var(--cubic) ;
}
.menu__icon {
font-size: 1.5em;
stroke: currentColor ;
transition: transform var(--duration) var(--cubic) ;
}
.menu__item::after {
left: -1.15em;
bottom: 0 ;
content: " " ;
height: 0.25em ;
position: absolute ;
border-radius: 2em ;
transform-origin: left center ;
background-color: currentColor ;
width: calc( var(--lineWidth) + 5px ) ;
transform: translate3d(3em , 0, 0) scaleX(0) ;
transition: transform calc( var(--duration) + .2s) var(--cubic) ;
}
.menu__text {
left: 4.3em ;
height: 1.5em;
font-size: 1.25em ;
position: absolute ;
text-transform: capitalize ;
letter-spacing: .01em ;
transform: translate3d(0, 109%, 0) ;
transition: transform calc( var(--duration) / 3.7 ) ;
}
.menu__item.active {
flex-grow: 2.3 ;
color: var(--color-2) ;
}
.menu__item.active .menu__icon {
transform: translate3d(-95% , 0, 0) ;
}
.menu__item.active::before {
transform: scale(1) ;
}
.menu__item.active::after {
transform: translate3d(6.3em , 0, 0) scaleX(1) ;
transition: transform var(--duration) var(--cubic) ;
}
.menu__text.active {
transform: translate3d(0 , 0, 0) ;
transition: transform calc(var(--duration) / 1.5) ;
}
.icon {
--duration-icon: 1s ;
fill: none ;
width: 2.5em ;
height: 2.5em ;
display: block ;
stroke-width: 15 ;
stroke-miterlimit: 10 ;
}
.active #home-anm {
animation: home var(--duration-icon) ;
}
#keyframes home {
25% {
transform: translate3d(0, -.8em , 0) ;
}
50% {
transform: translate3d(0, .5em , 0) ;
}
}
#strategy-anm {
transform: scaleX(.85) ;
transform-origin: center ;
}
.active #strategy-anm {
animation: strategy var(--duration-icon) ;
}
#keyframes strategy {
50% {
transform: scaleX(1) ;
}
100%{
transform: scaleX(.85) ;
}
}
.active #strategy-cir1 {
animation: strategy-cir1 var(--duration-icon);
}
.active #strategy-cir2 {
animation: strategy-cir2 var(--duration-icon) .1s;
}
.active #strategy-cir3 {
animation: strategy-cir3 var(--duration-icon) .2s;
}
#keyframes strategy-cir1 {
50% {
transform: translate3d(-.7em,-0.7em,0);
}
100%{
transform: translate3d(0,0,0);
}
}
#keyframes strategy-cir2 {
35% {
transform: translate3d(0,-0.7em,0);
}
100%{
transform: translate3d(0,0,0);
}
}
#keyframes strategy-cir3 {
35% {
transform: translate3d(.7em,-0.7em,0);
}
100%{
transform: translate3d(0,0,0);
}
}
.active #period-anm {
transform-origin: center 100% ;
animation: period var(--duration-icon) ;
}
.active #period-cir {
transform-origin: center ;
animation: period-cir var(--duration-icon) ;
}
.active #period-line {
stroke-dasharray: 66 ;
animation: period-line calc( var(--duration-icon) / 2.5 ) reverse ;
}
#keyframes period {
35% {
transform: scaleY(.85) ;
}
60% , 70% {
transform: scaleY(1.2) ;
}
100% {
transform: scaleY(1) ;
}
}
#keyframes period-cir {
0%{
opacity: 0 ;
}
35% {
opacity: 1 ;
transform: translate3d(15%, -55%, 0) ;
}
60%{
opacity: 0 ;
transform: translate3d(-8%, -50%, 0) ;
}
}
#keyframes period-line {
100% {
stroke-dashoffset: 66 ;
}
}
.active #security-cir {
transform-box: fill-box ;
transform-origin: center ;
animation: security-cir calc( var(--duration-icon) / 1.5 ) ;
}
#keyframes security-cir {
0% {
transform: scale(0) ;
}
100% {
transform: scale(1) ;
}
}
.active #security-strok {
stroke-dasharray: 96;
animation: security-strok calc( var(--duration-icon) / 1.2 ) ;
}
#keyframes security-strok {
0% {
stroke-dashoffset: 60 ;
}
100% {
stroke-dashoffset: 230 ;
}
}
.active #settings-anm {
transform-box: fill-box ;
transform-origin: center ;
animation: settings-anm calc( var(--duration-icon) / 1.5 ) ;
}
#keyframes settings-anm {
0% {
transform: rotate(-60deg);
}
50% {
transform: rotate(60deg);
}
}
index.js
/* Intagram: #ui.tormenta*/
const buttons = document.querySelectorAll(".menu__item");
let activeButton = document.querySelector(".menu__item.active");
buttons.forEach(item => {
const text = item.querySelector(".menu__text");
setLineWidth(text, item);
window.addEventListener("resize", () => {
setLineWidth(text, item);
})
item.addEventListener("click", function() {
if (this.classList.contains("active")) return;
this.classList.add("active");
if (activeButton) {
activeButton.classList.remove("active");
activeButton.querySelector(".menu__text").classList.remove("active");
}
handleTransition(this, text);
activeButton = this;
});
});
function setLineWidth(text, item) {
const lineWidth = text.offsetWidth + "px";
item.style.setProperty("--lineWidth", lineWidth);
}
function handleTransition(item, text) {
item.addEventListener("transitionend", (e) => {
if (e.propertyName != "flex-grow" ||
!item.classList.contains("active")) return;
text.classList.add("active");
});
}
I put those css and js files in the same folder. When I open the html file, it doesn't show any font-awesome icons or any text, but it shows the navbar layout. I am a complete beginner and any help is appreciated.

Changing the directory path of the CSS link to "folder-name/styles.css" worked for me.
Using './' means the file your looking for exists in the you current directory. I am not sure why the JavaScript worked but to target a file in a folder located in your active directory you should use 'folder/file.txt'
As for the Font Awesome it doesn't look like you have imported it. Go to the below link to see your Font Awesome kits and link one in your HTML file
https://fontawesome.com/kits

Related

Why add and remove function is not working at the same time in a function in JavaScript?

I have started learning JS recently and am stuck here. I have created a dice game where images change themselves randomly when a button is clicked.
The images just get changed from one to another. I want to give a rolling effect to them. So, I have added animation for them that they change angles in both X-axis and Y-axis. It works on the first click but later doesn't.
So I had added classList.add() to give the animation and classList.remove() to remove but the remove function doesn't work.
This is HTML code:
function roll() {
document.querySelectorAll("img")[0].classList.add("rollEffect");
document.querySelectorAll("img")[1].classList.add("rollEffect");
var randomNumber1 = Math.floor(Math.random() * 6 + 1);
var randomNumber2 = Math.floor(Math.random() * 6 + 1);
var randomImage1 = "dice" + randomNumber1 + ".png";
var randomImage2 = "dice" + randomNumber2 + ".png";
document.querySelectorAll("img")[0].setAttribute("src", randomImage1);
document.querySelectorAll("img")[1].setAttribute("src", randomImage2);
if (randomNumber1 > randomNumber2)
document.querySelector("h1").innerHTML = "Player1 wins!!!";
else
if (randomNumber2 > randomNumber1)
document.querySelector("h1").innerHTML = "Player2 wins!!!";
else
document.querySelector("h1").innerHTML = "DRAW!!!";
document.querySelectorAll("img")[0].classList.remove("rollEffect");
document.querySelectorAll("img")[1].classList.remove("rollEffect");
}
.btn {
background-color: #8843F2;
border: 0;
border-radius: 20px;
color: #ffffff;
font-family: 'Indie Flower', cursive;
margin: 0 50px;
padding: 1% 2%;
}
.container {
width: 70%;
margin: auto;
text-align: center;
}
.dice {
text-align: center;
display: inline-block;
}
#keyframes rollClick {
9% {
transform: rotateX(30deg) rotateY(30deg)
}
18% {
transform: rotateX(60deg) rotateY(60deg)
}
28% {
transform: rotateX(90deg) rotateY(90deg)
}
37% {
transform: rotateX(120deg) rotateY(120deg)
}
46% {
transform: rotateX(150deg) rotateY(150deg)
}
55% {
transform: rotateX(180deg) rotateY(180deg)
}
65% {
transform: rotateX(210deg) rotateY(210deg)
}
76% {
transform: rotateX(240deg) rotateY(240deg)
}
85% {
transform: rotateX(270deg) rotateY(270deg)
}
90% {
transform: rotateX(300deg) rotateY(300deg)
}
95% {
transform: rotateX(330deg) rotateY(330deg)
}
100% {
transform: rotateX(360deg) rotateY(360deg)
}
}
.rollEffect {
animation-name: rollClick;
animation-duration: 0.1s;
}
body {
background-color: #F9D371;
}
img {
width: 80%;
}
<div class="container">
<h1>Roll us</h1>
<div class="dice">
<p>Player 1</p>
<img class="img1" src="dice6.png">
</div>
<div class="dice">
<p>Player 2</p>
<img class="img2" src="dice6.png">
</div>
<button class="btn" onclick="roll()">Roll</button>
</div>
The javascript code that adds the rolling animation class runs separate from any animation durations.
It will run as quickly as the performance of the device allows.
In your js code it will:
add the .rollEffect class to both images.
set a new image url.
set text with the result of the game
remove the .rollEffect class from both images.
This all happens as fast as possible, we're talking micro/nano seconds.
So the animation does get applied, each time, and gets removed each time. so fast you can't even see the animation.
You have to wait a bit before removing the animation class. so the animation has time to run before it's removed.
This can be achived with setTimeout
For example:
setTimeout(() => {
document.querySelectorAll("img")[0].classList.remove("rollEffect");
document.querySelectorAll("img")[1].classList.remove("rollEffect");
}, 100); // <--- 100 here will execute the code in the callback after 100ms, the same as the animation time.
function roll() {
document.querySelectorAll("img")[0].classList.add("rollEffect");
document.querySelectorAll("img")[1].classList.add("rollEffect");
var randomNumber1 = Math.floor(Math.random() * 6 + 1);
var randomNumber2 = Math.floor(Math.random() * 6 + 1);
var randomImage1 = `http://placekitten.com/g/${50*randomNumber1}/300`;
var randomImage2 = `http://placekitten.com/g/200/${50*randomNumber2}`;
document.querySelectorAll("img")[0].setAttribute("src", randomImage1);
document.querySelectorAll("img")[1].setAttribute("src", randomImage2);
if (randomNumber1 > randomNumber2)
document.querySelector("h1").innerHTML = "Player1 wins!!!";
else
if (randomNumber2 > randomNumber1)
document.querySelector("h1").innerHTML = "Player2 wins!!!";
else
document.querySelector("h1").innerHTML = "DRAW!!!";
setTimeout(() => {
document.querySelectorAll("img")[0].classList.remove("rollEffect");
document.querySelectorAll("img")[1].classList.remove("rollEffect");
}, 100);
}
.btn {
background-color: #8843F2;
border: 0;
border-radius: 20px;
color: #ffffff;
font-family: 'Indie Flower', cursive;
margin: 0 50px;
padding: 1% 2%;
}
.container {
width: 70%;
margin: auto;
text-align: center;
}
.dice {
text-align: center;
display: inline-block;
}
#keyframes rollClick {
9% {
transform: rotateX(30deg) rotateY(30deg)
}
18% {
transform: rotateX(60deg) rotateY(60deg)
}
28% {
transform: rotateX(90deg) rotateY(90deg)
}
37% {
transform: rotateX(120deg) rotateY(120deg)
}
46% {
transform: rotateX(150deg) rotateY(150deg)
}
55% {
transform: rotateX(180deg) rotateY(180deg)
}
65% {
transform: rotateX(210deg) rotateY(210deg)
}
76% {
transform: rotateX(240deg) rotateY(240deg)
}
85% {
transform: rotateX(270deg) rotateY(270deg)
}
90% {
transform: rotateX(300deg) rotateY(300deg)
}
95% {
transform: rotateX(330deg) rotateY(330deg)
}
100% {
transform: rotateX(360deg) rotateY(360deg)
}
}
.rollEffect {
animation-name: rollClick;
animation-duration: 0.1s;
}
body {
background-color: #F9D371;
}
img {
width: 150px;
height: 150px;
}
<div class="container">
<h1>Roll us</h1>
<div class="dice">
<p>Player 1</p>
<img class="img1" src="http://placekitten.com/g/200/300">
</div>
<div class="dice">
<p>Player 2</p>
<img class="img2" src="http://placekitten.com/g/300/200">
</div>
<button class="btn" onclick="roll()">Roll</button>
</div>

Javascript onclick in 3d cube of cubes? Need to access the inner cubes and trigger a function

I've been working on this project where i need to build a cube of cubes and where, given a precise number, it generates those cubes. Problem is, i need to access prerendered cubes in order to get the new one "spawn".
To do that i require access with my cursor on one of the atomic-cube faces. I've been trying the pointer-event: none with no success and i am running low on ideas, right now i am thinking about taking the cursor position and query the very first cube on the z axis that is currently "built" (has the 3 faces, since i am going to look at the cube from 3 perspectives only).
The goal is to make every rendered fully built cube a clickable item (in other words every tags that form an atomic cube) and then to trigger someFunction().
Here is the code so far:
JS:
var cube = document.querySelector('.cube');
var radioGroup = document.querySelector('.radio-group');
var currentClass = '';
function changeSide() {
var checkedRadio = radioGroup.querySelector(':checked');
var showClass = 'show-' + checkedRadio.value;
if ( currentClass ) {
cube.classList.remove( currentClass );
}
cube.classList.add( showClass );
currentClass = showClass;
}
// set initial side
changeSide();
radioGroup.addEventListener( 'change', changeSide );
//Init Cubes
function initCubes(){
let id = 0
let atomicCube = document.createElement('div')
atomicCube.classList.add('atomic-cube')
for(let i = 0; i<5; i++){
for (let l = 0; l < 25; l++) {
atomicCube.id = id
document.getElementById('layer-'+i).appendChild(atomicCube.cloneNode(true))
id += 1
}
}
}
//Building Cubes
function buildCubes(array){
let idH1 = document.createElement('h1')
let infop = document.createElement('p')
let atomicCube = document.createElement('div')
let classes = ['front','right','top']
let info = []
let color = 0
//read every cub that is in toDraw
for (let i = 0; i < array.length; i++) {
//check if is already built (aka look for childrens)
if (!document.getElementById(array[i]).hasChildNodes()){
//look on listaMemo
for (let memoria = 0; memoria < listaMemo.length; memoria++) {
//look for corresponding id
if(listaMemo[memoria][0] == array[i]){
//take infos
info = listaMemo[memoria][3]
//prendi il colore
color = listaMemo[memoria][2]
if (color == 1){
atomicCube.setAttribute('style', 'background-color: rgb(233, 53, 53)')
}
else{
if (color == 2){
atomicCube.setAttribute('style', 'background-color: rgb(19, 90, 221)')
}
else{
atomicCube.setAttribute('style', 'background-color:black')
}
}
//Build the atomic-cube faces
for (let l = 0; l < classes.length; l++) {
idH1.innerHTML = array[i]
idH1.classList.add('uk-h2')
idH1.style.color = "white"
infop.classList.add('uk-text-small')
infop.classList.add('uk-text-center')
infop.style.color = "white"
infop.innerHTML = info[l]
atomicCube.className = 'atomic-' + classes[l]
atomicCube.appendChild(idH1)
atomicCube.appendChild(infop)
document.getElementById(array[i]).appendChild(atomicCube.cloneNode(true))
}
}
}
}
}
for (let el = 0; el < document.querySelectorAll('.atomic-cube').length; el++){
for(let k = 0; k < document.querySelectorAll('.atomic-cube')[el].childNodes.length; k++){
document.querySelectorAll('.atomic-cube')[el].childNodes[k].addEventListener('onclick', selectMemo)
}
}
}
function selectMemo(ele){
console.log(ele)
}
var todraw = [62]
initCubes()
buildCubes(todraw)
lista memo is an array like this:
listaMemo = [
[
62, //this is the id
1, //irrelevant
3, //this defines wether the cube is external (1), internal (2) or the center (3) of the cube wrapper
[
"item-name", //this are the infos
"person name and surname", //this are the infos
"place name" //this are the infos
]
],
[84,1,2,["item-name2","person name and surname2","place name2"]]
]
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- UIkit CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit#3.6.20/dist/css/uikit.min.css" />
<!-- UIkit JS -->
<script src="https://cdn.jsdelivr.net/npm/uikit#3.6.20/dist/js/uikit.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/uikit#3.6.20/dist/js/uikit-icons.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="main.js" defer></script>
<title>Document</title>
</head>
<body>
<div class="scene">
<div class="cube">
<div class="layer" id="layer-0">
</div>
<div class="layer" id="layer-1">
</div>
<div class="layer" id="layer-2">
</div>
<div class="layer" id="layer-3">
</div>
<div class="cube-face layer front" id="layer-4">
</div>
<div class="cube-face" id="bottom"></div>
<div class="cube-face" id="west"></div>
<div class="cube-face" id="north"></div>
<div class="cube-face top" id="top">
</div>
<div class="cube-face right layer">
</div>
</div>
</div>
</div>
<div class="radio-group">
<label>
<input class="uk-radio" type="radio" name="rotate-cube-side" value="iso" checked/>
Iso
</label>
<label>
<input class="uk-radio" type="radio" name="rotate-cube-side" value="front"/>
Front
</label>
<label>
<input class="uk-radio" type="radio" name="rotate-cube-side" value="right" />
Right
</label>
<label>
<input class="uk-radio" type="radio" name="rotate-cube-side" value="top" />
Top
</label>
</div>
</body>
</html>
Aaand the CSS:
:root{
--cubeWidth: 500px;
--atomicWidth: calc(var(--cubeWidth)/5)
}
body, html{
position: relative;
margin: 0;
}
.scene{
width: var(--cubeWidth);
height: var(--cubeWidth);
margin: calc(var(--cubeWidth)/2) auto;
transform-style: preserve-3d;
}
.cube-face{
position: absolute;
width: var(--cubeWidth);
height: var(--cubeWidth);
text-align: center;
line-height: var(--cubeWidth);
font-size: 40px;
transform-style: preserve-3d;
border:black 1px solid;
pointer-events: none;
}
.cube{
position: absolute;
width: var(--cubeWidth);
height: var(--cubeWidth);
transform-style: preserve-3d;
transform: translateZ(calc(var(--cubeWidth)/-2));
transition: transform 1s;
}
.cube.show-iso {
transform: translateZ(calc(var(--cubeWidth)/-2)) rotateY( -45deg) rotateX(-45deg);
}
.cube.show-front {
transform: translateZ(calc(var(--cubeWidth)/-2)) rotateY( 0deg);
}
.cube.show-right {
transform: translateZ(calc(var(--cubeWidth)/-2)) rotateY( -90deg);
}
.cube.show-north {
transform: translateZ(calc(var(--cubeWidth)/-2)) rotateY(-180deg);
}
.cube.show-west {
transform: translateZ(calc(var(--cubeWidth)/-2)) rotateY( 90deg);
}
.cube.show-top {
transform: translateZ(calc(var(--cubeWidth)/-2)) rotateX( -90deg);
}
.cube.show-bottom {
transform: translateZ(calc(var(--cubeWidth)/-2)) rotateX( 90deg);
}
#west {
transform: rotateY(-90deg) translateZ(calc(var(--cubeWidth)/2));
}
.right{
transform: rotateY(90deg) translateZ(calc(var(--cubeWidth)/2));
}
#north{
transform: rotateY(180deg) translateZ(calc(var(--cubeWidth)/2));
}
.front {
transform: translateZ(calc(var(--cubeWidth)/2));
}
#bottom{
transform: rotateX(-90deg) translateZ(calc(var(--cubeWidth)/2));
}
.top{
transform: rotateX(90deg) translateZ(calc(var(--cubeWidth)/2));
}
.radio-group{
}
.scene-background{
position:absolute;
width: inherit;
height: inherit;
border-radius: 50%;
}
.choose-player-wrapper{
position:relative;
}
.choose-player-wrapper > div{
margin: 10px;
}
.atomic-wrapper{
position: absolute;
transform-style: preserve-3d;
top: 0;
left: 0;
width: var(--cubeWidth);
height: var(--cubeWidth);
}
.atomic-cube{
width: var(--atomicWidth);
height: var(--atomicWidth);
transform-style: preserve-3d;
transform: translateZ(calc(var(--atomicWidth)/-2));
transition: transform 1s;
pointer-events: none;
}
.atomic-cube>div{
position: absolute;
width: var(--atomicWidth);
height: var(--atomicWidth);
text-align: center;
line-height: var(--atomicWidth);
font-size: 40px;
display: block;
}
.atomic-top{
transform: rotateX(90deg) translateZ(calc(var(--atomicWidth)/2));
}
.atomic-front {
transform: translateZ(calc(var(--atomicWidth)/2));
}
.atomic-right{
transform: rotateY(90deg) translateZ(calc(var(--atomicWidth)/2));
}
.atomic-left {
transform: rotateY(-90deg) translateZ(calc(var(--atomicWidth)/2));
}
.atomic-back{
transform: rotateY(180deg) translateZ(calc(var(--atomicWidth)/2));
}
.atomic-bottom{
transform: rotateX(-90deg) translateZ(calc(var(--atomicWidth)/2));
}
.layer{
position: absolute;
width: var(--cubeWidth);
height: var(--cubeWidth);
display: grid;
grid-template-columns: 20% 20% 20% 20% 20%;
grid-template-rows: 20% 20% 20% 20% 20%;
grid-auto-flow: row;
transform-style: preserve-3d;
pointer-events: none;
}
#layer-3{
/*background: lightcoral;*/
transform: rotateY(0) translateZ(calc((var(--cubeWidth)/2) - var(--atomicWidth)));
}
#layer-2{
/*background: lightcyan;*/
transform: rotateY(0) translateZ(calc((var(--cubeWidth)/2) - var(--atomicWidth)*2));
}
#layer-1{
/*background: lightgreen;*/
transform: rotateY(0) translateZ(calc((var(--cubeWidth)/-2) + var(--atomicWidth)*2));
}
#layer-0{
/*background: lightyellow;*/
transform: rotateY(0) translateZ(calc((var(--cubeWidth)/-2) + var(--atomicWidth)));
}
I tried to leave it as clean as i could possibly do but i am not an expert hence, i am sorry for the mess :D

Continue animation where ended

I have a 3D cube that completes one of 2 animations depending on what number is selected by math.random. The animation holds its end position after it has ended (due to "forwards") but if the cube is clicked, to run the animation again, it returns back to its original position. How to I make the cube complete the animation starting from the last time's ending position?
.scene {
perspective:200px;
width:100px;
height:100px;
}
.die {
position:relative;
width:100%;
height:100%;
transform-style:preserve-3d;
transform: translateZ(-50px);
transition: transform 1s;
animation:;
}
.face {
position:absolute;
width:100px;
height:100px;
color:white;
top:0;
bottom:0;
left:0;
right:0;
background-color:purple;
}
.one {
transform: rotateY(0deg) translateZ(50px);
}
.two {
transform:rotateY(90deg) translateZ(50px);
}
.three {
transform:rotateY(180deg) translateZ(50px);
}
.four {
transform:rotateY(-90deg) translateZ(50px);
}
.five {
transform:rotateX(90deg) translateZ(50px);
}
.six {
transform:rotateX(-90deg) translateZ(50px);
}
#keyframes one {
0% {transform: translateZ(-5em) rotateY(0deg) rotateX(0deg);}
100% {transform: translateZ(-5em) rotateY(0deg) rotateX(360deg);}
}
#keyframes two {
0% {transform: translateZ(-5em) rotateY(0deg) rotateX(0deg);}
100% {transform: translateZ(-5em) rotateY(-90deg) rotateX(360deg);}
}
<div class="scene">
<div class="die" id="die" onclick="spinDie()">
<div class="face one">one
</div>
<div class="face two">two
</div>
<div class="face three">three
</div>
<div class="face four">four
</div>
<div class="face five">five
</div>
<div class="face six">six
</div>
</div>
</div>
</div>
function spinDie() {
var num = Math.floor(Math.random() * 1) + 1;
if (num === 1) {
document.getElementById("die").style.animation="one 2s forwards"
}
if(num === 2) {
document.getElementById("die").style.animation="two 2s forwards"
}
}
Use transition instead of animation.
Define the transitions inside an Array faces
Get a random face {x: N, y: N}
Addup += spins to the current random face x and y valuex. I.e: x += (360 * randomBetween(n, N))
const EL_dice = document.getElementById("dice");
// https://en.wikipedia.org/wiki/Dice
const faces = [
{x:0, y:0}, // 1 front
{x:0, y:-90}, // 2 right
{x:-90, y:0}, // 3 top
{x:90, y:0}, // 4 bottom
{x:0, y:90}, // 5 left
{x:0, y:180}, // 6 back
];
function spinDice() {
const rand = ~~(Math.random() * 6); // Generate random 0 to 5
const face = faces[rand]; // Get random face
face.x += 360 * (~~(Math.random() * 4) + 1); // Addup some x spins
face.y += 360 * (~~(Math.random() * 4) + 1); // Addup some y spins
console.clear(); console.log(rand + 1);
EL_dice.style.cssText = `
transition: 3s cubic-bezier(0.2, -0.2, 0.5, 1.1);
transform: rotateX(${face.x}deg) rotateY(${face.y}deg);
`;
}
EL_dice.addEventListener("click", spinDice);
.dice-perspective {
display: inline-flex;
perspective: 500px;
margin: 20px;
user-select: none;
}
.dice {
--size: 80px; /* SET HERE THE DESIRED DICE SIZE */
--half: calc(var(--size) / 2);
width: var(--size); height: var(--size);
position: relative;
transform-style: preserve-3d;
}
.dice>div {
height: inherit; width: inherit;
position: absolute;
background: #0bf; color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: calc(var(--size) * 1.4);
line-height: 0;
}
.front {transform: rotateY(0deg) translateZ(var(--half));}
.right {transform: rotateY(90deg) translateZ(var(--half));}
.top {transform: rotateX(90deg) translateZ(var(--half));}
.bottom {transform: rotateX(-90deg) translateZ(var(--half));}
.left {transform: rotateY(-90deg) translateZ(var(--half));}
.back {transform: rotateX(180deg) translateZ(var(--half));}
Click dice to spin
<div class="dice-perspective">
<div id="dice" class="dice">
<div class="front">⚀</div>
<div class="right">⚁</div>
<div class="top">⚂</div>
<div class="bottom">⚃</div>
<div class="left">⚄</div>
<div class="back">⚅</div>
</div>
</div>

Non clickable button [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
i've been trying to figure this out by myself the entire night and i just can't make my button clickable... i would keep trying but i'm tired and i need to go to sleep really bad.
the code is mostly pasted.
i'm really bad at this kind of stuff
don't judge the the bad code...
but i need this button really bad so i can redirect to my welcome page.
the button code itself works, the problems is its conficting with the other stuff and makes it non clickable.
so... here's the full index page of my site with the button that doesn't work:
<!DOCTYPE html>
<html>
<head>
<style>
div.a {
text-align: center;
</style>
</head>
<body>
<style>
.button {
background-color: #4CAF50; /* Green */
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: block;
font-size: 16px;
margin: 0 auto;
cursor: pointer;
-webkit-transition-duration: 0.4s; /* Safari */
transition-duration: 0.4s;
}
.button2:hover {
box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24),0 17px 50px 0 rgba(0,0,0,0.19);
}
</style>
<br><br><br><br><br><br><br><br>
<div class="a">
<button onclick= "location.href='welcome'"
button class="button button2">❤
</button>
</div>
<html>
<div class="container">
<div class="text"></div>
</div>
<font face="Sarpanch" color="white" size"10" class="message">
</font>
<font face="Play">
</font>
<font face="Play" class="cn">
</font>
<div class="clouds">
</div>
<iframe width="1" height="1" src="https://www.youtube.com/embed/F2CXCbz3_Nc?rel=0&autoplay=1" frameborder="0" allowfullscreen></iframe>
</html>
<html>
<style>
* {
margin: 0;
padding: 0;
}
body{
background-color: #000;
}
-webkit-#keyframes we-are {
from {scale: 1.1;}
to {scale: 0;}
}
#keyframes we-are {
from {scale: 1.1;}
to {scale: 0;}
}
-webkit-#keyframes fadeIn {
0% {opacity: 0;}
100% {opacity: 1;}
}
#keyframes fadeIn {
0% {opacity: 0;}
100% {opacity: 1;}
}
#keyframes move-twink-back {
from {background-position:0 0;}
to {background-position:-10000px 5000px;}
}
#-webkit-keyframes move-twink-back {
from {background-position:0 0;}
to {background-position:-10000px 5000px;}
}
#-moz-keyframes move-twink-back {
from {background-position:0 0;}
to {background-position:-10000px 5000px;}
}
#-ms-keyframes move-twink-back {
from {background-position:0 0;}
to {background-position:-10000px 5000px;}
}
#keyframes move-clouds-back {
from {background-position:0 0;}
to {background-position:10000px 0;}
}
#-webkit-keyframes move-clouds-back {
from {background-position:0 0;}
to {background-position:10000px 0;}
}
#-moz-keyframes move-clouds-back {
from {background-position:0 0;}
to {background-position:10000px 0;}
}
#-ms-keyframes move-clouds-back {
from {background-position: 0;}
to {background-position:10000px 0;}
}
.container {
height: 100%;
width: 100%;
justify-content: center;
align-items: center;
display: flex;
}
.text {
font-weight: 100;
font-size: 28px;
color: #FAFAFA;
font-family: Iceland;
text-shadow: 0 0 0.5em cyan, 0 0 0.5em cyan;
}
.dud {
color: #757575;
}
.animation-container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1;
}
.animation-container span {
color: whitesmoke;
display: block;
font-size: 18px;
font-family: 'Helvetica';
text-shadow: 0 0 1px white;
position: absolute;
user-select: none;
pointer-events: none;
cursor: default;
z-index: 1;
opacity: 0;
will-change: transform, opacity;
animation-timing-function: ease-out;
animation-name: move;
}
#keyframes move {
0% {
opacity: 0;
transform: translateY(100vh);
}
25% {
opacity: 1;
}
50% {
opacity: 1;
}
75% {
opacity: 0;
}
100% {
opacity: 0;
transform: none;
}
}
.buzz_wrapper{
position:relative;
width:100%;
margin:180px auto;
background-attachment: fixed;
background-position: 0 0;
background-repeat: no-repeat ;
background-size:cover;
overflow : hidden;
overflow:hidden;
padding:100px;
}
.scanline{
width:100%;
display:block;
background:#000;
height:4px;
position:relative;
z-index:3;
margin-bottom:5px;
opacity:0.1;
}
.buzz_wrapper span{
position:absolute;
-webkit-filter: blur(1px);
font-size:30px;
font-family:'Courier new', fixed;
font-weight:bold;
}
.buzz_wrapper span:nth-child(1){
color:red;
margin-left:-2px;
-webkit-filter: blur(2px);
}
.buzz_wrapper span:nth-child(2){
color:green;
margin-left:2px;
-webkit-filter: blur(2px);
}
.buzz_wrapper span:nth-child(3){
color:blue;
position:20px 0;
-webkit-filter: blur(1px);
}
.buzz_wrapper span:nth-child(4){
color:#fff;
-webkit-filter: blur(1px);
text-shadow:0 0 50px rgba(255,255,255,0.4);
}
.buzz_wrapper span:nth-child(5){
color:rgba(255,255,255,0.4);
-webkit-filter: blur(15px);
}
.buzz_wrapper span{
-webkit-animation: blur 30ms infinite, jerk 50ms infinite;
}
#-webkit-keyframes blur {
0% { -webkit-filter: blur(1px); opacity:0.8;}
50% { -webkit-filter: blur(1px); opacity:1; }
100%{ -webkit-filter: blur(1px); opacity:0.8; }
}
#-webkit-keyframes jerk {
50% { left:1px; }
51% { left:0; }
}
#-webkit-keyframes jerkup {
50% { top:1px; }
51% { top:0; }
}
.buzz_wrapper span:nth-child(3){
-webkit-animation: jerkblue 1s infinite;
}
#-webkit-keyframes jerkblue {
0% { left:0; }
30% { left:0; }
31% { left:10px; }
32% { left:0; }
98% { left:0; }
100% { left:10px; }
}
.buzz_wrapper span:nth-child(2){
-webkit-animation: jerkgreen 1s infinite;
}
#-webkit-keyframes jerkgreen {
0% { left:0; }
30% { left:0; }
31% { left:-10px; }
32% { left:0; }
98% { left:0; }
100% { left:-10px; }
}
.buzz_wrapper .text{
-webkit-animation: jerkwhole 5s infinite;
position:relative;
}
#-webkit-keyframes jerkwhole {
30% { }
40% { opacity:1; top:0; left:0; -webkit-transform:scale(1,1); -webkit-transform:skew(0,0);}
41% { opacity:0.8; top:0px; left:-100px; -webkit-transform:scale(1,1.2); -webkit-transform:skew(50deg,0);}
42% { opacity:0.8; top:0px; left:100px; -webkit-transform:scale(1,1.2); -webkit-transform:skew(-80deg,0);}
43% { opacity:1; top:0; left:0; -webkit-transform:scale(1,1); -webkit-transform:skew(0,0);}
65% { }
}
</style>
</head>
</html>
<script language="JavaScript">
class TextScramble {
constructor(el) {
this.el = el
this.chars = '!##$%^&*()_-=+{}:"|<>?,./;'
this.update = this.update.bind(this)
}
setText(newText) {
const oldText = this.el.innerText
const length = Math.max(oldText.length, newText.length)
const promise = new Promise((resolve) => this.resolve = resolve)
this.queue = []
for (let i = 0; i < length; i++) {
const from = oldText[i] || ''
const to = newText[i] || ''
const start = Math.floor(Math.random() * 40)
const end = start + Math.floor(Math.random() * 40)
this.queue.push({ from, to, start, end })
}
cancelAnimationFrame(this.frameRequest)
this.frame = 0
this.update()
return promise
}
update() {
let output = ''
let complete = 0
for (let i = 0, n = this.queue.length; i < n; i++) {
let { from, to, start, end, char } = this.queue[i]
if (this.frame >= end) {
complete++
output += to
} else if (this.frame >= start) {
if (!char || Math.random() < 0.28) {
char = this.randomChar()
this.queue[i].char = char
}
output += `<span class="dud">${char}</span>`
} else {
output += from
}
}
this.el.innerHTML = output
if (complete === this.queue.length) {
this.resolve()
} else {
this.frameRequest = requestAnimationFrame(this.update)
this.frame++
}
}
randomChar() {
return this.chars[Math.floor(Math.random() * this.chars.length)]
}
}
const phrases = [
'Click no botão para ir pro nosso site',
'❤',
]
const el = document.querySelector('.text')
const fx = new TextScramble(el)
let counter = 0
const next = () => {
fx.setText(phrases[counter]).then(() => {
setTimeout(next, 1500)
})
counter = (counter + 1) % phrases.length
}
next()
'use strict';
var app = {
chars: ['lixo','ta de hack','NAO PODE CAPS','PODE NADA NESSE SERVER','esse 1Fawkes ta xitado','TEM ADM?','TEM GENTE JOGANDO GRANADA','panela','server lixo','o que e bipe','ta enxergando muito'],
init: function () {
app.container = document.createElement('div');
app.container.className = 'animation-container';
document.body.appendChild(app.container);
window.setInterval(app.add, 100);
},
add: function () {
var element = document.createElement('span');
app.container.appendChild(element);
app.animate(element);
},
animate: function (element) {
var character = app.chars[Math.floor(Math.random() * app.chars.length)];
var duration = Math.floor(Math.random() * 15) + 1;
var offset = Math.floor(Math.random() * (50 - duration * 2)) + 3;
var size = 10 + (15 - duration);
element.style.cssText = 'right:'+offset+'vw; font-size:'+size+'px;animation-duration:'+duration+'s';
element.innerHTML = character;
window.setTimeout(app.remove, duration * 1000, element);
},
remove: function (element) {
element.parentNode.removeChild(element);
},
};
document.addEventListener('DOMContentLoaded', app.init);
</script>
https://github.com/wizzz3/website/blob/master/site
the site: https://bf4gatserver.com/
If you are talking about the green button with the white heart then it's a small fix.
When you try to click the button you actually clicking the fixed div that contains all the floating text, because the element is in position: fixed; z-index: 1.
The element that holds the button <div class="a">, add to it the following css position: relative; z-index: 2; and your done!
Hope this is what you needed =]
Add pointer-events: none; to the .animation-container.
Final code:
.animation-container {
pointer-events: none;
}
Why it works? Because all the clicks happened on .animation-container that has position fixed and some other styling which make it be across the entire page.

How to create Ripple effect on Click - Material Design

I'm new to CSS animations and I've been trying to make their animation work for the last hours by looking at their code, but I can't make it work for now.
I'm talking about this effect: https://angular.io/ (menu effect).
Basically, it's an animation on click that spreads a circle from the mouse cursor.
Seems it comes down to these 2 lines:
transition: box-shadow .4s cubic-bezier(.25,.8,.25,1),background-color .4s cubic-bezier(.25,.8,.25,1),-webkit-transform .4s cubic-bezier(.25,.8,.25,1);
transition: box-shadow .4s cubic-bezier(.25,.8,.25,1),background-color .4s cubic-bezier(.25,.8,.25,1),transform .4s cubic-bezier(.25,.8,.25,1);
PS: Maybe there's some jQuery I didn't see.
Ripple effect in Material Design using jQuery and CSS3
To create a UX Ripple effect basically you need to:
append to any element an oveflow:hidden element to contain the ripple circle (you don't want to alter your original element overflow, neither see the ripple effect go outside of a desired container)
append to the overflow container the ripple wave translucent radial element
get the click coordinates and CSS3 animate the scaling and opacity of the ripple element
Listen for the animationend event and destroy the ripple container.
The basic code:
Basically add data-ripple (default as white ripple) or data-ripple="#000" to a desired element:
<a data-ripple> EDIT </a>
<div data-ripple="rgba(0,0,0, 0.3)">Lorem ipsum</div>
CSS:
/* MAD-RIPPLE EFFECT */
.ripple{
position: absolute;
top:0; left:0; bottom:0; right:0;
overflow: hidden;
-webkit-transform: translateZ(0); /* to contain zoomed ripple */
transform: translateZ(0);
border-radius: inherit; /* inherit from parent (rounded buttons etc) */
pointer-events: none; /* allow user interaction */
animation: ripple-shadow 0.4s forwards;
-webkit-animation: ripple-shadow 0.4s forwards;
}
.rippleWave{
backface-visibility: hidden;
position: absolute;
border-radius: 50%;
transform: scale(0.7); -webkit-transform: scale(0.7);
background: rgba(255,255,255, 1);
opacity: 0.45;
animation: ripple 2s forwards;
-webkit-animation: ripple 2s forwards;
}
#keyframes ripple-shadow {
0% {box-shadow: 0 0 0 rgba(0,0,0,0.0);}
20% {box-shadow: 0 4px 16px rgba(0,0,0,0.3);}
100% {box-shadow: 0 0 0 rgba(0,0,0,0.0);}
}
#-webkit-keyframes ripple-shadow {
0% {box-shadow: 0 0 0 rgba(0,0,0,0.0);}
20% {box-shadow: 0 4px 16px rgba(0,0,0,0.3);}
100% {box-shadow: 0 0 0 rgba(0,0,0,0.0);}
}
#keyframes ripple {
to {transform: scale(24); opacity:0;}
}
#-webkit-keyframes ripple {
to {-webkit-transform: scale(24); opacity:0;}
}
jQuery
jQuery(function($) {
// MAD-RIPPLE // (jQ+CSS)
$(document).on("mousedown", "[data-ripple]", function(e) {
var $self = $(this);
if($self.is(".btn-disabled")) {
return;
}
if($self.closest("[data-ripple]")) {
e.stopPropagation();
}
var initPos = $self.css("position"),
offs = $self.offset(),
x = e.pageX - offs.left,
y = e.pageY - offs.top,
dia = Math.min(this.offsetHeight, this.offsetWidth, 100), // start diameter
$ripple = $('<div/>', {class : "ripple",appendTo : $self });
if(!initPos || initPos==="static") {
$self.css({position:"relative"});
}
$('<div/>', {
class : "rippleWave",
css : {
background: $self.data("ripple"),
width: dia,
height: dia,
left: x - (dia/2),
top: y - (dia/2),
},
appendTo : $ripple,
one : {
animationend : function(){
$ripple.remove();
}
}
});
});
});
Here's a full-featured demo:
jQuery(function($) {
// MAD-RIPPLE // (jQ+CSS)
$(document).on("mousedown", "[data-ripple]", function(e) {
var $self = $(this);
if($self.is(".btn-disabled")) {
return;
}
if($self.closest("[data-ripple]")) {
e.stopPropagation();
}
var initPos = $self.css("position"),
offs = $self.offset(),
x = e.pageX - offs.left,
y = e.pageY - offs.top,
dia = Math.min(this.offsetHeight, this.offsetWidth, 100), // start diameter
$ripple = $('<div/>', {class : "ripple",appendTo : $self });
if(!initPos || initPos==="static") {
$self.css({position:"relative"});
}
$('<div/>', {
class : "rippleWave",
css : {
background: $self.data("ripple"),
width: dia,
height: dia,
left: x - (dia/2),
top: y - (dia/2),
},
appendTo : $ripple,
one : {
animationend : function(){
$ripple.remove();
}
}
});
});
});
*{box-sizing:border-box; -webkit-box-sizing:border-box;}
html, body{height:100%; margin:0;}
body{background:#f5f5f5; font: 14px/20px Roboto, sans-serif;}
h1, h2{font-weight: 300;}
/* MAD-RIPPLE EFFECT */
.ripple{
position: absolute;
top:0; left:0; bottom:0; right:0;
overflow: hidden;
-webkit-transform: translateZ(0); /* to contain zoomed ripple */
transform: translateZ(0);
border-radius: inherit; /* inherit from parent (rounded buttons etc) */
pointer-events: none; /* allow user interaction */
animation: ripple-shadow 0.4s forwards;
-webkit-animation: ripple-shadow 0.4s forwards;
}
.rippleWave{
backface-visibility: hidden;
position: absolute;
border-radius: 50%;
transform: scale(0.7); -webkit-transform: scale(0.7);
background: rgba(255,255,255, 1);
opacity: 0.45;
animation: ripple 2s forwards;
-webkit-animation: ripple 2s forwards;
}
#keyframes ripple-shadow {
0% {box-shadow: 0 0 0 rgba(0,0,0,0.0);}
20% {box-shadow: 0 4px 16px rgba(0,0,0,0.3);}
100% {box-shadow: 0 0 0 rgba(0,0,0,0.0);}
}
#-webkit-keyframes ripple-shadow {
0% {box-shadow: 0 0 0 rgba(0,0,0,0.0);}
20% {box-shadow: 0 4px 16px rgba(0,0,0,0.3);}
100% {box-shadow: 0 0 0 rgba(0,0,0,0.0);}
}
#keyframes ripple {
to {transform: scale(24); opacity:0;}
}
#-webkit-keyframes ripple {
to {-webkit-transform: scale(24); opacity:0;}
}
/* MAD-BUTTONS (demo) */
[class*=mad-button-]{
display:inline-block;
text-align:center;
position: relative;
margin: 0;
white-space: nowrap;
vertical-align: middle;
font-family: "Roboto", sans-serif;
font-size: 14px;
font-weight: 500;
text-transform: uppercase;
text-decoration: none;
border: 0; outline: 0;
background: none;
transition: 0.3s;
cursor: pointer;
color: rgba(0,0,0, 0.82);
}
[class*=mad-button-] i.material-icons{
vertical-align:middle;
padding:0;
}
.mad-button-raised{
height: 36px;
padding: 0px 16px;
line-height: 36px;
border-radius: 2px;
box-shadow: /*amb*/ 0 0 2px rgba(0,0,0,0.15),
/*key*/ 0 1px 3px rgba(0,0,0,0.25);
}.mad-button-raised:hover{
box-shadow: /*amb*/ 0 0 2px rgba(0,0,0,0.13),
/*key*/ 0 2px 4px rgba(0,0,0,0.2);
}
.mad-button-action{
width: 56px; height:56px;
padding: 16px 0;
border-radius: 32px;
box-shadow: /*amb*/ 0 0 2px rgba(0,0,0,0.13),
/*key*/ 0 5px 7px rgba(0,0,0,0.2);
}.mad-button-action:hover{
box-shadow: /*amb*/ 0 0 2px rgba(0,0,0,0.11),
/*key*/ 0 6px 9px rgba(0,0,0,0.18);
}
[class*=mad-button-].mad-ico-left i.material-icons{ margin: 0 8px 0 -4px; }
[class*=mad-button-].mad-ico-right i.material-icons{ margin: 0 -4px 0 8px; }
/* MAD-COLORS */
.bg-primary-darker{background:#1976D2; color:#fff;}
.bg-primary{ background:#2196F3; color:#fff; }
.bg-primary.lighter{ background: #BBDEFB; color: rgba(0,0,0,0.82);}
.bg-accented{ background:#FF4081; color:#fff; }
/* MAD-CELL */
.cell{padding: 8px 16px; overflow:auto;}
<link href='https://fonts.googleapis.com/css?family=Roboto:500,400,300&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
<div class="cell">
<button data-ripple class="mad-button-raised mad-ico-left bg-primary"><i class="material-icons">person</i>User settings</button>
<a data-ripple href="#" class="mad-button-action bg-accented"><i class="material-icons">search</i></a>
</div>
<div data-ripple class="cell bg-primary-darker">
<h1>Click to Ripple</h1>
<p>data-ripple</p>
</div>
<div data-ripple="rgba(0,0,0, 0.4)" class="cell bg-primary">
<p>data-ripple="rgba(0,0,0, 0.4)"</p>
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore....</p>
<p><a data-ripple class="mad-button-raised mad-ico-right bg-accented">Edit<i class="material-icons">edit</i></a></p>
</div>
I have used this sort of code before on a few of my projects.
Using jQuery we can position the effect to its not just static and then we add the span element onclick. I have added comments so it makes it easier to follow.
Demo Here
jQuery
$("div").click(function (e) {
// Remove any old one
$(".ripple").remove();
// Setup
var posX = $(this).offset().left,
posY = $(this).offset().top,
buttonWidth = $(this).width(),
buttonHeight = $(this).height();
// Add the element
$(this).prepend("<span class='ripple'></span>");
// Make it round!
if(buttonWidth >= buttonHeight) {
buttonHeight = buttonWidth;
} else {
buttonWidth = buttonHeight;
}
// Get the center of the element
var x = e.pageX - posX - buttonWidth / 2;
var y = e.pageY - posY - buttonHeight / 2;
// Add the ripples CSS and start the animation
$(".ripple").css({
width: buttonWidth,
height: buttonHeight,
top: y + 'px',
left: x + 'px'
}).addClass("rippleEffect");
});
CSS
.ripple {
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.4);
transform: scale(0);
position: absolute;
opacity: 1;
}
.rippleEffect {
animation: rippleDrop .6s linear;
}
#keyframes rippleDrop {
100% {
transform: scale(2);
opacity: 0;
}
}
This can be achieved with box-shadows. The positioning of the circle origin under the mouse when clicked will need JS.
li{
font-size:2em;
background:rgba(51, 51, 254, 0.8);
list-style-type:none;
display:inline-block;
line-height:2em;
width:6em;
text-align:center;
color:#fff;
position:relative;
overflow:hidden;
}
a{color:#fff;}
a:after{
content:'';
position:absolute;
border-radius:50%;
height:10em; width:10em;
top: -4em; left:-2em;
box-shadow: inset 0 0 0 5em rgba(255,255,255,0.2);
transition: box-shadow 0.8s;
}
a:focus:after{
box-shadow: inset 0 0 0 0em rgba(255,255,255,0.2);
}
<ul>
<li>button</li>
</ul>
Here is a CSS - only implementation i.e. no javascript required.
Source: https://ghinda.net/article/css-ripple-material-design/
body {
background: #fff;
}
button {
position: relative;
overflow: hidden;
padding: 16px 32px;
}
button:after {
content: '';
display: block;
position: absolute;
left: 50%;
top: 50%;
width: 120px;
height: 120px;
margin-left: -60px;
margin-top: -60px;
background: #3f51b5;
border-radius: 100%;
opacity: .6;
transform: scale(0);
}
#keyframes ripple {
0% {
transform: scale(0);
}
20% {
transform: scale(1);
}
100% {
opacity: 0;
transform: scale(1);
}
}
button:not(:active):after {
animation: ripple 1s ease-out;
}
/* fixes initial animation run, without user input, on page load.
*/
button:after {
visibility: hidden;
}
button:focus:after {
visibility: visible;
}
<button>
Button
</button>
You could use http://mladenplavsic.github.io/css-ripple-effect/ (note: I'm the author of that product)
Pure CSS solution
<link href="https://cdn.rawgit.com/mladenplavsic/css-ripple-effect/35c35541/dist/ripple.min.css" rel="stylesheet"/>
<button class="ripple">Click me</button>
You can get the same effect with the help of Materialize css, making it with that is quite easy. All you have to do is just add a class to where you want the effect.
Submit
If you want to go with pure CSS check this codepen it : Ripple effect
Here is Material Design button component "The wave effect" Done Using pure CSS3 and JavaScript no libraries no framework
Material Design button component "The wave effect"
https://codepen.io/Mahmoud-Zakaria/pen/NvbORQ
HTML
<div class="md" >Click</div>
CSS
#keyframes glow-out {
30%,80% {
transform: scale(7);
}
100% {
opacity: 0;
}
}
.md {
--y: 0;
--x: 0;
display: inline-block;
padding: 20px 70px;
text-align: center;
background-color: lightcoral;
margin: 5em;
position: relative;
overflow: hidden;
cursor: pointer;
border-radius: 4px;
color: white;
}
.is-clicked {
content: '';
position: absolute;
top: calc(var(--y) * 1px);
left: calc(var(--x) * 1px);
width: 100px;
height:100px;
background: rgba(255, 255, 255, .3);
border-radius: 50%;
animation: glow-out 1s ease-in-out forwards;
transform: translate(-50%, -50%);
}
JS
// Material Design button Module
let md_module = (function() {
let btn = document.querySelectorAll(".md");
let md_btn = Array.prototype.slice.call(btn);
md_btn.forEach(eachCB)
function eachCB (item, index, array){
function md(e) {
let offsetX = e.clientX - item.offsetLeft;
let offsetY = e.clientY - item.offsetTop;
item.style.setProperty("--x", offsetX);
item.style.setProperty("--y", offsetY);
item.innerHTML += '<div class="is-clicked"></div>';
}
function rm() {
let state = item.querySelectorAll(".is-clicked");
console.log(state)
for (let i = 0; i < state.length; i++) {
if (state[i].className === "is-clicked") {
state[i].remove();
}
}
}
item.addEventListener("click", md);
item.addEventListener("animationend", rm);
}
})();
CSS Paint API (introduced in 2018)
The new CSS Paint API (part of the CSS "Houdini" draft) allows to write JavaScript functions to be used in CSS. Quote of the linked document:
CSS Paint API allows you to programmatically generate an image whenever a CSS property expects an image. Properties like background-image or border-image are usually used with url() to load an image file or with CSS built-in functions like linear-gradient(). Instead of using those, you can now use paint(myPainter) to reference a paint worklet.
This means you can implement a paint function in JavaScript and use it inside your CSS.
Browser support (May 2019)
Currently, only Chrome and Opera support the Paint API of the Houdini draft. Firefox has signaled "intent to implement". See ishoudinireadyyet.com or caniuse.com for more information.
Code sample
There is a working "ripple" example implemented by the Houdini task force available here. I extracted the "core" from the example below. It implements the custom paint function, adds custom CSS properties like --ripple-color and uses a JavaScript function to implement the animation and to start and stop the effect.
Note, that it adds the custom paint function like this:
CSS.paintWorklet.addModule('https://googlechromelabs.github.io/houdini-samples/paint-worklet/ripple/paintworklet.js');
If you want to use the effect on your website, I recommend you download the file and reference it locally.
// Adds the custom paint function
CSS.paintWorklet.addModule('https://googlechromelabs.github.io/houdini-samples/paint-worklet/ripple/paintworklet.js');
// the actual animation of the ripple effect
function rippleEffect(element) {
let start, x, y;
element.addEventListener('click', function (evt) {
this.classList.add('animating');
[x, y] = [evt.offsetX, evt.offsetY];
start = performance.now();
const raf = (now) => {
const tick = Math.floor(now - start);
this.style.cssText = `--ripple-x: ${x}; --ripple-y: ${y}; --animation-tick: ${tick};`;
if (tick > 1000) {
this.classList.remove('animating');
this.style.cssText = `--animation-tick: 0`;
return;
}
requestAnimationFrame(raf);
};
requestAnimationFrame(raf);
});
}
rippleEffect(document.querySelector('.ripple'));
.ripple {
font-size: 5em;
background-color: rgb(0, 169, 244);
/* custom property */
--ripple-color: rgba(255, 255, 255, 0.54);
}
.ripple.animating {
/* usage of the custom "ripple" paint function */
background-image: paint(ripple);
}
<button class="ripple">Click me!</button>
Realization javascript + babel -
javascript -
class ImpulseStyleFactory {
static ANIMATION_DEFAULT_DURATION = 1;
static ANIMATION_DEFAULT_SIZE = 300;
static ANIMATION_RATIO = ImpulseStyleFactory.ANIMATION_DEFAULT_DURATION / ImpulseStyleFactory.ANIMATION_DEFAULT_SIZE;
static circleImpulseStyle( x, y, size, color = `#fff`, duration = 1 ){
return {
width: `${ size }px`,
height: `${ size }px`,
background: color,
borderRadius: `50%`,
display: `inline-block`,
pointerEvents: `none`,
position: `absolute`,
top: `${ y - size / 2 }px`,
left: `${ x - size / 2 }px`,
animation: `impulse ${ duration }s`,
};
}
}
class Impulse {
static service = new Impulse();
static install( container ) {
Impulse.service.containerRegister( container );
}
static destroy( container ){
Impulse.service.containerUnregister( container );
}
static applyToElement( {x, y}, container ){
Impulse.service.createImpulse( x, y, container );
}
constructor(){
this.impulse_clickHandler = this.impulse_clickHandler.bind(this);
this.impulse_animationEndHandler = this.impulse_animationEndHandler.bind(this);
this.actives = new Map();
}
containerRegister( container ){
container.addEventListener('click', this.impulse_clickHandler);
}
containerUnregister( container ){
container.removeEventListener('click', this.impulse_clickHandler);
}
createImpulse( x, y, container ){
let { clientWidth, clientHeight } = container;
let impulse = document.createElement('div');
impulse.addEventListener('animationend', this.impulse_animationEndHandler);
let size = Math.max( clientWidth, clientHeight ) * 2;
let color = container.dataset.color;
Object.assign(impulse.style, ImpulseStyleFactory.circleImpulseStyle(
x, y, size, color
));
if( this.actives.has( container ) ){
this.actives.get( container )
.add( impulse );
}else{
this.actives.set( container, new Set( [ impulse ] ) );
}
container.dataset.active = true;
container.appendChild( impulse );
}
impulse_clickHandler({ layerX, layerY, currentTarget: container }){
this.createImpulse( layerX, layerY, container );
}
impulse_animationEndHandler( {currentTarget: impulse} ){
let { parentNode: container } = impulse;
this.actives.get( container )
.delete( impulse );
if( ! this.actives.get( container ).size ){
this.actives.delete( container );
container.dataset.active = false;
}
container.removeChild(impulse);
}
}
css -
#keyframes impulse {
from {
opacity: .3;
transform: scale(0);
}
to {
opacity: 0;
transform: scale(1);
}
}
to use so -
html -
<div class="impulse" data-color="#3f1dcb" data-active="false">
<div class="panel"></div>
</div>
javascript -
let impulses = document.querySelectorAll('.impulse');
let impulseAll = Array.from( impulses );
impulseAll.forEach( Impulse.install );
Life example Impulse.install ( impulse create in coords of click, add handler event click ) -
class ImpulseStyleFactory {
static ANIMATION_DEFAULT_DURATION = 1;
static ANIMATION_DEFAULT_SIZE = 300;
static ANIMATION_RATIO = ImpulseStyleFactory.ANIMATION_DEFAULT_DURATION / ImpulseStyleFactory.ANIMATION_DEFAULT_SIZE;
static circleImpulseStyle( x, y, size, color = `#fff`, duration = 1 ){
return {
width: `${ size }px`,
height: `${ size }px`,
background: color,
borderRadius: `50%`,
display: `inline-block`,
pointerEvents: `none`,
position: `absolute`,
top: `${ y - size / 2 }px`,
left: `${ x - size / 2 }px`,
animation: `impulse ${ duration }s`,
};
}
}
class Impulse {
static service = new Impulse();
static install( container ) {
Impulse.service.containerRegister( container );
}
static destroy( container ){
Impulse.service.containerUnregister( container );
}
static applyToElement( {x, y}, container ){
Impulse.service.createImpulse( x, y, container );
}
constructor(){
this.impulse_clickHandler = this.impulse_clickHandler.bind(this);
this.impulse_animationEndHandler = this.impulse_animationEndHandler.bind(this);
this.actives = new Map();
}
containerRegister( container ){
container.addEventListener('click', this.impulse_clickHandler);
}
containerUnregister( container ){
container.removeEventListener('click', this.impulse_clickHandler);
}
createImpulse( x, y, container ){
let { clientWidth, clientHeight } = container;
let impulse = document.createElement('div');
impulse.addEventListener('animationend', this.impulse_animationEndHandler);
let size = Math.max( clientWidth, clientHeight ) * 2;
let color = container.dataset.color;
Object.assign(impulse.style, ImpulseStyleFactory.circleImpulseStyle(
x, y, size, color
));
if( this.actives.has( container ) ){
this.actives.get( container )
.add( impulse );
}else{
this.actives.set( container, new Set( [ impulse ] ) );
}
container.dataset.active = true;
container.appendChild( impulse );
}
impulse_clickHandler({ layerX, layerY, currentTarget: container }){
this.createImpulse( layerX, layerY, container );
}
impulse_animationEndHandler( {currentTarget: impulse} ){
let { parentNode: container } = impulse;
this.actives.get( container )
.delete( impulse );
if( ! this.actives.get( container ).size ){
this.actives.delete( container );
container.dataset.active = false;
}
container.removeChild(impulse);
}
}
let impulses = document.querySelectorAll('.impulse');
let impulseAll = Array.from( impulses );
impulseAll.forEach( Impulse.install );
#import "https://cdnjs.cloudflare.com/ajax/libs/normalize/6.0.0/normalize.min.css";
/*#import url('https://fonts.googleapis.com/css?family=Roboto+Mono');*/
* {
box-sizing: border-box;
}
html {
font-family: 'Roboto Mono', monospace;
}
body {
width: 100%;
height: 100%;
margin: 0;
position: absolute;
}
main {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
}
.container {
position: absolute;
top: 0;
left: 0;
}
.centred {
display: flex;
justify-content: center;
align-items: center;
}
.shadow-xs {
box-shadow: rgba(0, 0, 0, 0.117647) 0px 1px 6px, rgba(0, 0, 0, 0.117647) 0px 1px 4px;
}
.sample-impulse {
transition: all .5s;
overflow: hidden;
position: relative;
}
.sample-impulse[data-active="true"] {
box-shadow: rgba(0, 0, 0, 0.156863) 0px 3px 10px, rgba(0, 0, 0, 0.227451) 0px 3px 10px;
}
.panel {
width: 300px;
height: 100px;
background: #fff;
}
.panel__hidden-label {
color: #fff;
font-size: 2rem;
font-weight: bold;
pointer-events: none;
z-index: 1;
position: absolute;
}
.panel__default-label {
pointer-events: none;
z-index: 2;
position: absolute;
}
.sample-impulse[data-active="true"] .panel__default-label {
display: none;
}
#keyframes impulse {
from {
opacity: .3;
transform: scale(0);
}
to {
opacity: 0;
transform: scale(1);
}
}
<main class="centred">
<div class="sample-impulse impulse centred shadow-xs" data-color="#3f1dcb" data-active="false">
<div class="group centred">
<div class="panel"></div>
<span class="panel__hidden-label">StackOverflow</span>
<span class="panel__default-label">click me</span>
</div>
</div>
</main>
Life example Impulse.applyToElement ( impulse coords setby user, not add handler event click ) -
class ImpulseStyleFactory {
static ANIMATION_DEFAULT_DURATION = 1;
static ANIMATION_DEFAULT_SIZE = 300;
static ANIMATION_RATIO = ImpulseStyleFactory.ANIMATION_DEFAULT_DURATION / ImpulseStyleFactory.ANIMATION_DEFAULT_SIZE;
static circleImpulseStyle( x, y, size, color = `#fff`, duration = 1 ){
return {
width: `${ size }px`,
height: `${ size }px`,
background: color,
borderRadius: `50%`,
display: `inline-block`,
pointerEvents: `none`,
position: `absolute`,
top: `${ y - size / 2 }px`,
left: `${ x - size / 2 }px`,
animation: `impulse ${ duration }s`,
};
}
}
class Impulse {
static service = new Impulse();
static install( container ) {
Impulse.service.containerRegister( container );
}
static destroy( container ){
Impulse.service.containerUnregister( container );
}
static applyToElement( {x, y}, container ){
Impulse.service.createImpulse( x, y, container );
}
constructor(){
this.impulse_clickHandler = this.impulse_clickHandler.bind(this);
this.impulse_animationEndHandler = this.impulse_animationEndHandler.bind(this);
this.actives = new Map();
}
containerRegister( container ){
container.addEventListener('click', this.impulse_clickHandler);
}
containerUnregister( container ){
container.removeEventListener('click', this.impulse_clickHandler);
}
createImpulse( x, y, container ){
let { clientWidth, clientHeight } = container;
let impulse = document.createElement('div');
impulse.addEventListener('animationend', this.impulse_animationEndHandler);
let size = Math.max( clientWidth, clientHeight ) * 2;
let color = container.dataset.color;
Object.assign(impulse.style, ImpulseStyleFactory.circleImpulseStyle(
x, y, size, color
));
if( this.actives.has( container ) ){
this.actives.get( container )
.add( impulse );
}else{
this.actives.set( container, new Set( [ impulse ] ) );
}
container.dataset.active = true;
container.appendChild( impulse );
}
impulse_clickHandler({ layerX, layerY, currentTarget: container }){
this.createImpulse( layerX, layerY, container );
}
impulse_animationEndHandler( {currentTarget: impulse} ){
let { parentNode: container } = impulse;
this.actives.get( container )
.delete( impulse );
if( ! this.actives.get( container ).size ){
this.actives.delete( container );
container.dataset.active = false;
}
container.removeChild(impulse);
}
}
const generateRandomPointByRectdAll = ( { width, height }, length = 1 ) => {
let result = [];
while( length-- ){
result.push( {
x: Math.round( Math.random() * width ),
y: Math.round( Math.random() * height )
} );
}
return result;
};
const delayTask = ( task, delay ) => new Promise( ( resolve, reject ) => {
let timeoutID = setTimeout( () => task( ), delay )
} );
document.addEventListener( 'click', () => {
const MAX_IMPULSE_DELAY_TIME = 5000;
let container = document.querySelector('.custom-impulse');
let pointAll = generateRandomPointByRectdAll( {
width: container.clientWidth,
height: container.clientHeight
}, 5 );
let taskAll = pointAll.map( point => () => Impulse.applyToElement( point, container ) );
let delayTaskAll = taskAll.map( task => delayTask( task, Math.round( Math.random() * MAX_IMPULSE_DELAY_TIME ) ) );
} );
#import "https://cdnjs.cloudflare.com/ajax/libs/normalize/6.0.0/normalize.min.css";
/*#import url('https://fonts.googleapis.com/css?family=Roboto+Mono');*/
* {
box-sizing: border-box;
}
html {
font-family: 'Roboto Mono', monospace;
}
body {
width: 100%;
height: 100%;
margin: 0;
position: absolute;
}
main {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
}
.container-fill {
width: 100%;
height: 100%;
}
.container {
position: absolute;
top: 0;
left: 0;
}
.centred {
display: flex;
justify-content: center;
align-items: center;
}
.custom-impulse {
will-change: transform, opasity;
position: absolute;
}
#keyframes impulse {
from {
opacity: .3;
transform: scale(0);
}
to {
opacity: 0;
transform: scale(1);
}
}
<main class="centred">
<div class="custom-impulse container-fill centred" data-color="#3f1dcb" data-active="false">
<span>click me</span>
</div>
</main>
You can use Tronic247 Material framework to make the ripple effect.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>A Basic HTML5 Template</title>
<link href="https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Two+Tone|Material+Icons+Round|Material+Icons+Sharp" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/gh/tronic247/material/dist/css/material.min.css" rel="stylesheet" />
</head>
<body class="container">
<div class="background-light-grey elevation-4 ripple-e dark-ripple" style="height: 200px;width: 200px;"></div>
<script src="https://code.jquery.com/jquery-3.6.0.slim.min.js" integrity="sha256-u7e5khyithlIdTpu22PHhENmPcRdFiHRjhAuHcs05RI=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/gh/tronic247/material/dist/js/material.min.js"></script>
</body>
</html>

Categories

Resources