Frontend Forever App
We have a mobile app for you to download and use. And you can unlock many features in the app.
Get it now
Intall Later
Run
HTML
CSS
Javascript
Output
Document
Countdown to
New Year
@charset "UTF-8"; @import url(https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,600,700,800); *, :after, :before { box-sizing: border-box; padding: 0; margin: 0; } .countdown{ --number-color: hsl(0 0% 100%); --text-color: hsl(0 0% 25%); --dot-color: hsl(0 0% 10%); --dot-color-remaining: hsl(182, 100%, 66%); --dot-color-active: hsl(0 100% 50%); font-family: system-ui, sans-serif; display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; width: min(60rem, 100%); margin-inline: auto; container: inline-size; > .part { aspect-ratio: 1/1; display: grid; place-items: center; > .remaining { grid-area: 1/1; color: hsl(0 0% 100%); display: grid; text-align: center; font-size: 4cqi; >.number { color: var(--number-color); } >.text { color: var(--text-color); text-transform: uppercase; font-size: 0.5em; } } > .dot-container { grid-area: 1/1; height: 100%; width: 4%; rotate: calc(360deg / var(--dots) * var(--dot-idx)); > .dot { width: 100%; aspect-ratio: 1/1; background-color: var(--dot-color); border-radius: 50%; transition: background-color .25s; &[data-active=true]{ background-color: var(--dot-color-remaining); &[data-lastactive=true]{ background-color: var(--dot-color-active); } } } } } } * { box-sizing: border-box } html, body { height: 100% } body { margin: 0; padding: 2rem; background-color: hsl(0 0% 0%); display: grid; gap: 1rem; align-content: center; } h1 { font-family: system-ui, sans-serif; color: hsl(0 0% 100%); text-align: center; >span:last-of-type{ color: hsl(182 100% 66%) } }
console.log("Event Fired") const countdownEls = document.querySelectorAll(".countdown") countdownEls.forEach(countdownEl => createCountdown(countdownEl)) function createCountdown(countdownEl){ const target = new Date(new Date(countdownEl.dataset.targetDate).toLocaleString('en', )) const parts = { days: {text: ["days","day"], dots: 30}, hours: {text: ["hours","hour"], dots: 24}, minutes: {text: ["minutes","minute"], dots: 60}, seconds: {text: ["seconds","second"], dots: 60}, } Object.entries(parts).forEach(([key, value])=>{ const partEl = document.createElement("div"); partEl.classList.add("part", key); partEl.style.setProperty("--dots", value.dots); value.element = partEl; const remainingEl = document.createElement("div"); remainingEl.classList.add("remaining"); remainingEl.innerHTML = `
` partEl.append(remainingEl); for(let i = 0; i < value.dots; i++){ const dotContainerEl = document.createElement("div"); dotContainerEl.style.setProperty("--dot-idx", i); dotContainerEl.classList.add("dot-container") const dotEl = document.createElement("div"); dotEl.classList.add("dot") dotContainerEl.append(dotEl); partEl.append(dotContainerEl); } countdownEl.append(partEl); }) getRemainingTime(target, parts) } function getRemainingTime(target, parts, first=true){ const now = new Date() if(first) console.log({target, now}) const remaining = {} let seconds = Math.floor((target - (now))/1000); let minutes = Math.floor(seconds/60); let hours = Math.floor(minutes/60); let days = Math.floor(hours/24); hours = hours-(days*24); minutes = minutes-(days*24*60)-(hours*60); seconds = seconds-(days*24*60*60)-(hours*60*60)-(minutes*60); Object.entries({days, hours, minutes, seconds}).forEach(([key, value])=>{ const remaining = parts[key].element.querySelector(".number"); const text = parts[key].element.querySelector(".text"); remaining.innerText = value; text.innerText = parts[key].text[Number(value==1)] const dots = parts[key].element.querySelectorAll(".dot") dots.forEach((dot, idx)=>{ dot.dataset.active = idx <= value; dot.dataset.lastactive = idx == value; }) }) if(now <= target){ window.requestAnimationFrame(()=>{ getRemainingTime(target, parts, false) }); } }