Skip to content

Commit c7a9fa8

Browse files
Merge pull request #936 from Kanavpreet-Singh/feature/time-travel
Feature/time travel
1 parent f213af6 commit c7a9fa8

File tree

8 files changed

+374
-0
lines changed

8 files changed

+374
-0
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ Please be aware that the demos may exhibit significant accessibility issues, suc
118118
- [MakemyTrip](#mmt)
119119
- [Text Spoiler Effect](#text-spoiler)
120120
- [Timeline](#timeline)
121+
- [Time Travel](#time-travel)
121122
- [Thank You Animation](#thankyou-animation)
122123
- [Toast Notification](#toast-notifications)
123124
- [Todo List](#todo-list)
@@ -565,6 +566,16 @@ Your browser does not support the video tag.
565566

566567
---
567568

569+
## <a id="time-travel"></a>Time Travel
570+
571+
[<img src="Time-Travel/preview.png" height="230" title="Time Travel">](Time-Travel/index.html)
572+
573+
A pure CSS time travel timeline that allows you to explore different eras.
574+
575+
**[⬆ back to top](#quick-links)**
576+
577+
---
578+
568579
## <a id="toast-notifications"></a>Toast Notifications
569580

570581
[<img src="toast-notifications/toast-notif.png" height="230" title="Demo">](https://codepen.io/Rajat-Hegde/pen/bNEqqym)

Time-Travel/ancient.png

301 KB
Loading

Time-Travel/future.png

172 KB
Loading

Time-Travel/index.html

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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+
<title>CSS Time Travel Timeline</title>
7+
<link rel="stylesheet" href="style.css">
8+
9+
<!-- Google Fonts -->
10+
<link href="https://fonts.googleapis.com/css2?family=Orbitron&family=UnifrakturCook&display=swap" rel="stylesheet">
11+
</head>
12+
13+
<body>
14+
<header>🌌 Time Travel Timeline</header>
15+
16+
<!-- place radios as siblings of main so CSS sibling selectors can target main::before correctly -->
17+
<input type="radio" name="era" id="ancient">
18+
<input type="radio" name="era" id="medieval">
19+
<input type="radio" name="era" id="modern">
20+
<input type="radio" name="era" id="future">
21+
22+
<div class="timeline">
23+
<label for="ancient"> Ancient</label>
24+
<label for="medieval">⚔️ Medieval</label>
25+
<label for="modern">🏙️ Modern</label>
26+
<label for="future">🚀 Future</label>
27+
</div>
28+
29+
<!-- transition overlay: shows animation (rocket/clock) when user switches eras -->
30+
<div class="transition" aria-hidden="true">
31+
<div class="overlay">
32+
<div class="anim-wrap">
33+
<div class="rocket" aria-hidden="true">
34+
<div class="rocket-body">
35+
<div class="rocket-fin rocket-fin-left"></div>
36+
<div class="rocket-fin rocket-fin-right"></div>
37+
<div class="rocket-window"></div>
38+
<div class="rocket-exhaust"></div>
39+
</div>
40+
</div>
41+
42+
<div class="clock" aria-hidden="true">
43+
<div class="clock-face">
44+
<div class="hand hour"></div>
45+
<div class="hand minute"></div>
46+
</div>
47+
</div>
48+
</div>
49+
</div>
50+
</div>
51+
52+
<main class="era">
53+
<div class="content">
54+
<div class="era-media" aria-hidden="false">
55+
<img id="img-ancient" src="ancient.png" alt="Ancient era visual">
56+
<img id="img-medieval" src="medeival.png" alt="Medieval era visual">
57+
<img id="img-modern" src="modern.png" alt="Modern era visual">
58+
<img id="img-future" src="future.png" alt="Future era visual">
59+
</div>
60+
61+
<div class="era-info">
62+
<h1 class="era-title">Welcome, Time Traveler</h1>
63+
<p class="era-desc">Choose an era to begin your journey.</p>
64+
</div>
65+
</div>
66+
</main>
67+
68+
<footer>Made with 💫 pure CSS magic</footer>
69+
</body>
70+
</html>

Time-Travel/medeival.png

527 KB
Loading

Time-Travel/modern.png

577 KB
Loading

Time-Travel/preview.png

599 KB
Loading

Time-Travel/style.css

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
:root{
2+
--radius:18px;
3+
--gap:14px;
4+
--trans-dur: 3.2s;
5+
--accent:#00ffd1;
6+
--muted:#98a0b3;
7+
--bg:#f7f8fb;
8+
--panel-radius:16px;
9+
--ui-bg: rgba(255,255,255,0.6);
10+
}
11+
12+
/* Reset / layout */
13+
*{box-sizing:border-box}
14+
body{
15+
margin:0;
16+
min-height:100vh;
17+
display:flex;
18+
flex-direction:column;
19+
font-family: Inter, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;
20+
background:var(--bg);
21+
color:#0b1220;
22+
}
23+
24+
header{
25+
text-align:center;
26+
padding:1rem 1.25rem;
27+
font-size:1.25rem;
28+
}
29+
30+
.timeline{
31+
display:flex;
32+
justify-content:center;
33+
gap:var(--gap);
34+
padding:0.6rem;
35+
flex-wrap:wrap;
36+
}
37+
38+
/* hide inputs but keep accessibility */
39+
input[type="radio"]{
40+
position:absolute;
41+
opacity:0;
42+
pointer-events:none;
43+
}
44+
45+
/* label buttons */
46+
label{
47+
display:inline-flex;
48+
align-items:center;
49+
gap:0.6rem;
50+
padding:0.6rem 1rem;
51+
background:var(--ui-bg);
52+
border-radius:999px;
53+
border:1px solid rgba(11,18,32,0.06);
54+
box-shadow: 0 2px 8px rgba(12,18,28,0.04);
55+
cursor:pointer;
56+
transition:transform .28s cubic-bezier(.2,.9,.2,1), box-shadow .28s, background .28s;
57+
font-weight:600;
58+
}
59+
60+
label:hover{ transform:translateY(-4px) }
61+
62+
/* active label for the radio immediately before the label */
63+
/* active label styling: target the label inside .timeline that matches the checked input */
64+
#ancient:checked ~ .timeline label[for="ancient"],
65+
#medieval:checked ~ .timeline label[for="medieval"],
66+
#modern:checked ~ .timeline label[for="modern"],
67+
#future:checked ~ .timeline label[for="future"]{
68+
background: linear-gradient(90deg,#08162e 0%, #0e2a3e 100%);
69+
color:var(--accent);
70+
transform:translateY(-6px) scale(1.02);
71+
box-shadow: 0 8px 30px rgba(6,16,32,0.25);
72+
}
73+
74+
label[for]{
75+
user-select:none;
76+
}
77+
78+
/* main stage (background + transition layer) */
79+
main{
80+
display:flex;
81+
align-items:center;
82+
justify-content:center;
83+
flex:1 1 auto;
84+
padding:2.25rem;
85+
position:relative;
86+
overflow:hidden;
87+
}
88+
89+
/* transition overlay container (placed between timeline and main in DOM) */
90+
.transition{position:fixed;inset:0;z-index:100;pointer-events:none}
91+
.transition .overlay{
92+
position:fixed;
93+
inset:0;
94+
display:flex;
95+
align-items:center;
96+
justify-content:center;
97+
pointer-events:none;
98+
z-index:10;
99+
background:rgba(0,0,0,0.2);
100+
}
101+
.transition .anim-wrap{display:flex;gap:2rem;align-items:center;justify-content:center}
102+
103+
/* rocket & clock initial hidden states */
104+
.rocket,.clock{width:120px;height:120px;display:flex;align-items:center;justify-content:center;opacity:0;transform:translateY(0);}
105+
.rocket .rocket-body{
106+
width: 60px;
107+
height: 100px;
108+
background: linear-gradient(180deg, #d0d0d0, #f0f0f0);
109+
border-radius: 50% 50% 10% 10% / 60% 60% 40% 40%;
110+
position: relative;
111+
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
112+
}
113+
114+
.rocket-fin {
115+
position: absolute;
116+
bottom: 10px;
117+
width: 20px;
118+
height: 35px;
119+
background: #b03a2e;
120+
border-radius: 40% 10% 10% 40%;
121+
}
122+
123+
.rocket-fin-left {
124+
left: -15px;
125+
transform: rotate(-20deg);
126+
}
127+
128+
.rocket-fin-right {
129+
right: -15px;
130+
transform: rotate(20deg);
131+
}
132+
133+
.rocket-window {
134+
position: absolute;
135+
top: 20px;
136+
left: 50%;
137+
transform: translateX(-50%);
138+
width: 25px;
139+
height: 25px;
140+
background: #85c1e9;
141+
border-radius: 50%;
142+
border: 3px solid #d0d0d0;
143+
}
144+
145+
.rocket-exhaust {
146+
position: absolute;
147+
bottom: -20px;
148+
left: 50%;
149+
transform: translateX(-50%);
150+
width: 20px;
151+
height: 40px;
152+
background: linear-gradient(180deg, #f7dc6f, #f39c12);
153+
border-radius: 0 0 50% 50%;
154+
filter: blur(5px);
155+
opacity: 0.8;
156+
}
157+
158+
.clock .clock-face{width:88px;height:88px;border-radius:50%;background:linear-gradient(#fff,#f0f3f8);box-shadow:0 6px 18px rgba(6,16,32,0.12);position:relative;display:flex;align-items:center;justify-content:center}
159+
.clock .hand{position:absolute;width:2px;background:#111;transform-origin:50% 70%;border-radius:2px}
160+
.clock .hand.hour{height:18px;top:34px}
161+
.clock .hand.minute{height:26px;top:28px}
162+
163+
/* animated background pseudo layer */
164+
main::before{
165+
content:"";
166+
position:absolute;
167+
inset:0;
168+
background-size:cover;
169+
background-position:center;
170+
filter:contrast(1.02) saturate(1.02);
171+
transition:opacity .9s ease, transform .9s cubic-bezier(.2,.9,.2,1);
172+
opacity:0;
173+
transform:scale(1.02);
174+
z-index:0;
175+
}
176+
177+
/* soft overlay */
178+
main::after{
179+
content:"";
180+
position:absolute;inset:0;
181+
background:linear-gradient(180deg, rgba(0,0,0,0.08), rgba(3,6,16,0.06));
182+
pointer-events:none; z-index:2;
183+
}
184+
185+
.content{position:relative;z-index:3;max-width:1000px;width:100%;text-align:center;padding:0;border-radius:0;background:transparent;box-shadow:none}
186+
187+
/* show the correct image for each era */
188+
#ancient:checked ~ main .era-media img#img-ancient{opacity:1;transform:translate(-50%, -50%) scale(1);filter:none}
189+
#medieval:checked ~ main .era-media img#img-medieval{opacity:1;transform:translate(-50%, -50%) scale(1);filter:none}
190+
#modern:checked ~ main .era-media img#img-modern{opacity:1;transform:translate(-50%, -50%) scale(1);filter:none}
191+
#future:checked ~ main .era-media img#img-future{opacity:1;transform:translate(-50%, -50%) scale(1);filter:none}
192+
193+
/* media area: images show/hidden via opacity and transform */
194+
.era-media{position:relative;width:100%;height:70vh;display:block;padding:1rem 0;overflow:hidden}
195+
.era-media img{
196+
position:absolute;
197+
top:50%;
198+
left:50%;
199+
transform:translate(-50%, -50%);
200+
max-width:100%;
201+
height:auto;
202+
max-height:65vh;
203+
object-fit:contain;
204+
display:block;
205+
margin:0 auto;
206+
border-radius:12px;
207+
box-shadow:0 8px 28px rgba(6,16,32,0.12);
208+
opacity:0;
209+
transition: none;
210+
}
211+
212+
/* text overlay area below image */
213+
.era-info{padding:1rem 1.25rem}
214+
.era-title{margin:0 0 .35rem;font-size:clamp(1.25rem,2.2vw,1.6rem)}
215+
.era-desc{margin:0;color:var(--muted)}
216+
217+
footer{padding:.6rem;text-align:center;font-size:.85rem;color:var(--muted)}
218+
219+
/* era backgrounds (use same images as before but with better crossfade) */
220+
#ancient:checked ~ main::before{opacity:.22; background-image: linear-gradient(180deg, rgba(242,226,186,0.82), rgba(242,226,186,0.82)), url('ancient.png'); transform:translateY(0); filter:blur(2px) saturate(.95)}
221+
#medieval:checked ~ main::before{opacity:.22; background-image: linear-gradient(180deg, rgba(43,31,13,0.6), rgba(43,31,13,0.6)), url('medeival.png'); filter:grayscale(.06) contrast(1.03) blur(2px)}
222+
#modern:checked ~ main::before{opacity:.22; background-image: linear-gradient(180deg, rgba(229,229,229,0.66), rgba(229,229,229,0.66)), url('modern.png'); transform:scale(1.03); filter:blur(2px) saturate(1.02)}
223+
#future:checked ~ main::before{opacity:.22; background-image: linear-gradient(180deg, rgba(13,12,35,0.58), rgba(13,12,35,0.58)), url('future.png'); filter:hue-rotate(20deg) saturate(1.2) blur(2px)}
224+
225+
/* subtle enter animation for content depending on state */
226+
#ancient:checked ~ main .content{transform:translateY(0); opacity:1}
227+
#medieval:checked ~ main .content{transform:translateY(0); opacity:1}
228+
#modern:checked ~ main .content{transform:translateY(0); opacity:1}
229+
#future:checked ~ main .content{transform:translateY(0); opacity:1}
230+
231+
/* show the correct image for each era */
232+
/* delay image reveal until after transition animation completes */
233+
#ancient:checked ~ .transition .overlay .rocket{animation:rocketFly var(--trans-dur) cubic-bezier(.22,.9,.25,1) forwards}
234+
#ancient:checked ~ main .era-media img#img-ancient{transition-delay:0s;opacity:1;transform:translate(-50%, -50%) scale(1);filter:none}
235+
236+
#medieval:checked ~ .transition .overlay .rocket{animation:rocketFly var(--trans-dur) cubic-bezier(.22,.9,.25,1) forwards}
237+
#medieval:checked ~ main .era-media img#img-medieval{transition-delay:0s;opacity:1;transform:translate(-50%, -50%) scale(1);filter:none}
238+
239+
#modern:checked ~ .transition .overlay .rocket{animation:rocketFly var(--trans-dur) cubic-bezier(.22,.9,.25,1) forwards}
240+
#modern:checked ~ main .era-media img#img-modern{transition-delay:0s;opacity:1;transform:translate(-50%, -50%) scale(1);filter:none}
241+
242+
#future:checked ~ .transition .overlay .rocket{animation:rocketFly var(--trans-dur) cubic-bezier(.22,.9,.25,1) forwards}
243+
#future:checked ~ main .era-media img#img-future{transition-delay:0s;opacity:1;transform:translate(-50%, -50%) scale(1);filter:none}
244+
245+
/* overlay visibility animation: fade-in, hold, fade-out */
246+
@keyframes overlayFade{
247+
0%{opacity:0}
248+
10%{opacity:.95}
249+
85%{opacity:.95}
250+
100%{opacity:0}
251+
}
252+
253+
/* clock ticking animation */
254+
@keyframes clockTick{
255+
0%{opacity:0;transform:scale(.9)}
256+
8%{opacity:1;transform:scale(1)}
257+
20%{transform:scale(1.02)}
258+
80%{transform:scale(1.02)}
259+
100%{opacity:0;transform:scale(.9)}
260+
}
261+
262+
/* rocket flight animation */
263+
@keyframes rocketFly{
264+
0%{opacity:0;transform:translateY(60vh) scale(.6) rotate(-15deg)}
265+
12%{opacity:1;transform:translateY(30vh) scale(.85) rotate(-8deg)}
266+
60%{opacity:1;transform:translateY(-30vh) scale(1.2) rotate(12deg)}
267+
100%{opacity:0;transform:translateY(-80vh) scale(1.4) rotate(20deg)}
268+
}
269+
270+
/* trigger overlay animation when any era is checked */
271+
@keyframes ancient-kf {}
272+
@keyframes medieval-kf {}
273+
@keyframes modern-kf {}
274+
@keyframes future-kf {}
275+
276+
#ancient:checked ~ .transition .overlay{animation:overlayFade var(--trans-dur) ease forwards, ancient-kf 1s}
277+
#medieval:checked ~ .transition .overlay{animation:overlayFade var(--trans-dur) ease forwards, medieval-kf 1s}
278+
#modern:checked ~ .transition .overlay{animation:overlayFade var(--trans-dur) ease forwards, modern-kf 1s}
279+
#future:checked ~ .transition .overlay{animation:overlayFade var(--trans-dur) ease forwards, future-kf 1s}
280+
281+
main .content{transition:transform .7s cubic-bezier(.2,.9,.2,1), opacity .7s ease; transform:translateY(6px); opacity:1}
282+
283+
/* responsive */
284+
@media (max-width:760px){
285+
.timeline{gap:8px;padding:8px}
286+
label{padding:10px 12px;font-size:0.95rem}
287+
.content{padding:1.25rem;border-radius:12px}
288+
}
289+
290+
@media (prefers-reduced-motion: reduce){
291+
*{transition:none!important;animation:none!important}
292+
}
293+

0 commit comments

Comments
 (0)