Skip to content

Commit 571dfec

Browse files
committed
add animated countdown
1 parent 4d033e6 commit 571dfec

File tree

4 files changed

+191
-1
lines changed

4 files changed

+191
-1
lines changed

34-animated countdown/index.html

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<link rel="stylesheet" href="style.css" />
7+
<title>Animated Countdown</title>
8+
</head>
9+
<body>
10+
<div class="counter">
11+
<div class="nums">
12+
<span class="in">3</span>
13+
<span>2</span>
14+
<span>1</span>
15+
<span>0</span>
16+
</div>
17+
<h4>Get Ready</h4>
18+
</div>
19+
<div class="final">
20+
<h1>GO</h1>
21+
<button id="replay">Replay</button>
22+
</div>
23+
<script src="script.js"></script>
24+
</body>
25+
</html>

34-animated countdown/script.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const nums = document.querySelectorAll(".nums span");
2+
const counter = document.querySelector(".counter");
3+
const finalMessage = document.querySelector(".final");
4+
const replay = document.querySelector("#replay");
5+
6+
const resetDOM = () => {
7+
counter.classList.remove("hide");
8+
finalMessage.classList.remove("show");
9+
nums.forEach((num) => (num.classList.value = ""));
10+
nums[0].classList.add("in");
11+
};
12+
13+
const runAnimation = () => {
14+
nums.forEach((num, index) => {
15+
const nextToLast = nums.length - 1;
16+
num.addEventListener("animationend", (e) => {
17+
if (e.animationName === "goIn" && index !== nextToLast) {
18+
num.classList.remove("in");
19+
num.classList.add("out");
20+
} else if (e.animationName === "goOut" && num.nextElementSibling) {
21+
num.nextElementSibling.classList.add("in");
22+
} else {
23+
counter.classList.add("hide");
24+
finalMessage.classList.add("show");
25+
}
26+
});
27+
});
28+
};
29+
30+
runAnimation();
31+
32+
replay.addEventListener("click", () => {
33+
resetDOM();
34+
runAnimation();
35+
});

34-animated countdown/style.css

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap");
2+
3+
* {
4+
box-sizing: border-box;
5+
}
6+
7+
body {
8+
font-family: "Roboto", sans-serif;
9+
height: 100vh;
10+
overflow: hidden;
11+
margin: 0;
12+
}
13+
14+
h4 {
15+
font-size: 20px;
16+
margin: 5px;
17+
text-transform: uppercase;
18+
}
19+
20+
.counter {
21+
position: fixed;
22+
top: 50%;
23+
left: 50%;
24+
transform: translate(-50%, -50%);
25+
text-align: center;
26+
}
27+
28+
.counter.hide {
29+
transform: translate(-50%, -50%) scale(0);
30+
animation: hide 0.2s ease-out;
31+
}
32+
33+
@keyframes hide {
34+
0% {
35+
transform: translate(-50%, -50%) scale(1);
36+
}
37+
100% {
38+
transform: translate(-50%, -50%) scale(0);
39+
}
40+
}
41+
42+
.final {
43+
position: fixed;
44+
top: 50%;
45+
left: 50%;
46+
transform: translate(-50%, -50%) scale(0);
47+
text-align: center;
48+
}
49+
50+
.final.show {
51+
transform: translate(-50%, -50%) scale(1);
52+
animation: show 0.2s ease-out;
53+
}
54+
55+
@keyframes show {
56+
0% {
57+
transform: translate(-50%, -50%) scale(0);
58+
}
59+
33% {
60+
transform: translate(-50%, -50%) scale(1.4);
61+
}
62+
100% {
63+
transform: translate(-50%, -50%) scale(1);
64+
}
65+
}
66+
67+
.nums {
68+
color: #3498db;
69+
font-size: 50px;
70+
position: relative;
71+
overflow: hidden;
72+
width: 250px;
73+
height: 50px;
74+
}
75+
76+
.nums span {
77+
position: absolute;
78+
top: 50%;
79+
left: 50%;
80+
transform: translate(-50%, -50%) rotate(120deg);
81+
transform-origin: bottom center;
82+
}
83+
84+
.nums span.in {
85+
transform: translate(-50%, -50%) rotate(0deg);
86+
animation: goIn 0.5s ease-in-out;
87+
}
88+
89+
.nums span.out {
90+
animation: goOut 0.5s ease-in-out;
91+
}
92+
93+
@keyframes goIn {
94+
0% {
95+
transform: translate(-50%, -50%) rotate(120deg);
96+
}
97+
30% {
98+
transform: translate(-50%, -50%) rotate(-20deg);
99+
}
100+
60% {
101+
transform: translate(-50%, -50%) rotate(10deg);
102+
}
103+
100% {
104+
transform: translate(-50%, -50%) rotate(0deg);
105+
}
106+
}
107+
108+
@keyframes goOut {
109+
0% {
110+
transform: translate(-50%, -50%) rotate(0deg);
111+
}
112+
60% {
113+
transform: translate(-50%, -50%) rotate(20deg);
114+
}
115+
100% {
116+
transform: translate(-50%, -50%) rotate(-120deg);
117+
}
118+
}
119+
120+
#replay {
121+
background-color: #3498db;
122+
text-transform: uppercase;
123+
color: #fff;
124+
font-family: inherit;
125+
border: none;
126+
border-radius: 5px;
127+
font-size: 1rem;
128+
padding: 0.5rem;
129+
cursor: pointer;
130+
}

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
| 31 | [Password Generator](https://github.com/solygambas/html-css-fifty-projects/tree/master/31-password%20generator) | [Live Demo](https://codepen.io/solygambas/full/rNMRvWb) |
4040
| 32 | [Good Cheap Fast](https://github.com/solygambas/html-css-fifty-projects/tree/master/32-good%20cheap%20fast) | [Live Demo](https://codepen.io/solygambas/full/QWKoxwP) |
4141
| 33 | [Notes App](https://github.com/solygambas/html-css-fifty-projects/tree/master/33-notes%20app) | [Live Demo](https://codepen.io/solygambas/full/qBavQog) |
42-
| 34 | [Animated Countdown](https://github.com/solygambas/html-css-fifty-projects/tree/master/animated-countdown) | [Live Demo](/animated-countdown/) |
42+
| 34 | [Animated Countdown](https://github.com/solygambas/html-css-fifty-projects/tree/master/34-animated%20countdown) | [Live Demo](https://codepen.io/solygambas/full/vYXPbYW) |
4343
| 35 | [Image Carousel](https://github.com/solygambas/html-css-fifty-projects/tree/master/image-carousel) | [Live Demo](/image-carousel/) |
4444
| 36 | [Hoverboard](https://github.com/solygambas/html-css-fifty-projects/tree/master/hoverboard) | [Live Demo](/hoverboard/) |
4545
| 37 | [Pokedex](https://github.com/solygambas/html-css-fifty-projects/tree/master/pokedex) | [Live Demo](/pokedex/) |

0 commit comments

Comments
 (0)