Last active
November 29, 2023 15:55
-
-
Save peternatewood/f69f8c12b36e20601930a54970201286 to your computer and use it in GitHub Desktop.
A simple, efficient countdown clock. No jQuery required.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<style type="text/css"> | |
.countdown-container { | |
display: flex; | |
align-items: flex-start; /* Use flex-end if the digit titles go above the digits */ | |
justify-content: space-between; | |
width: 480px; | |
} | |
.countdown-container.hide-separators .countdown-separator { display: none } | |
.countdown-digit-container { width: 22% } | |
.countdown-separator { width: 4% } | |
.countdown-digits, | |
.countdown-separator, | |
.countdown-digit-title { | |
text-align: center; | |
margin: 0; | |
} | |
.countdown-digits, | |
.countdown-separator { | |
font: 48px/1.2 Arial, Helvetica, sans-serif; | |
} | |
.countdown-digit-title { | |
font: 24px/1.5 Arial, Helvetica, sans-serif; | |
} | |
</style> | |
<div class="countdown-container"> | |
<div class="countdown-digit-container"> | |
<div class="countdown-days countdown-digits">00</div> | |
<h6 class="countdown-digit-title">Days</h6> | |
</div> | |
<div class="countdown-separator">:</div> | |
<div class="countdown-digit-container"> | |
<div class="countdown-hours countdown-digits">00</div> | |
<h6 class="countdown-digit-title">Hrs</h6> | |
</div> | |
<div class="countdown-separator">:</div> | |
<div class="countdown-digit-container"> | |
<div class="countdown-minutes countdown-digits">00</div> | |
<h6 class="countdown-digit-title">Mins</h6> | |
</div> | |
<div class="countdown-separator">:</div> | |
<div class="countdown-digit-container"> | |
<div class="countdown-seconds countdown-digits">00</div> | |
<h6 class="countdown-digit-title">Sec</h6> | |
</div> | |
</div> | |
<script type="text/javascript"> | |
(function() { | |
var CONFIG = { | |
ENABLE_DAYS: true, | |
ENABLE_HOURS: true, | |
ENABLE_MINUTES: true, | |
ENABLE_SECONDS: true, | |
// Set the digit element ids here | |
DAYS_SELECTOR: ".countdown-days", | |
HOURS_SELECTOR: ".countdown-hours", | |
MINUTES_SELECTOR: ".countdown-minutes", | |
SECONDS_SELECTOR: ".countdown-seconds", | |
// This format is valid in all browsers, and ensures there's no | |
// confusion about the month and day | |
DEADLINE: Date.parse("17 May 2024 11:59 PM") | |
}; | |
// Calculate the time to the deadline with a minimum value of 0 | |
var now = Date.now(); | |
var timeToDeadline = Math.max(0, CONFIG.DEADLINE - now); | |
/* | |
We could compare each number against the related element's html, but | |
number-to-number comparison is faster, and by being simpler is more | |
reliable. So, we keep track of what each number was during the previous | |
iteration. | |
*/ | |
var days, hours, minutes, seconds; | |
var lastDays, lastHours, lastMinutes, lastSeconds; | |
var lastTimestamp = 0; | |
function updateHTMLElements() { | |
// Set these to the id of whatever element should contain the digits | |
var daysElements = document.querySelectorAll(CONFIG.DAYS_SELECTOR); | |
var hoursElements = document.querySelectorAll(CONFIG.HOURS_SELECTOR); | |
var minutesElements = document.querySelectorAll(CONFIG.MINUTES_SELECTOR); | |
var secondsElements = document.querySelectorAll(CONFIG.SECONDS_SELECTOR); | |
// Updating the DOM is the most intensive part of this, so we only do it | |
// if the digit has changed | |
if (CONFIG.ENABLE_DAYS && lastDays !== days) { | |
lastDays = days; | |
daysElements.forEach(element => element.innerHTML = (days < 10 ? "0" : "") + days); | |
} | |
if (CONFIG.ENABLE_HOURS && lastHours !== hours) { | |
lastHours = hours; | |
hoursElements.forEach(element => element.innerHTML = (hours < 10 ? "0" : "") + hours); | |
} | |
if (CONFIG.ENABLE_MINUTES && lastMinutes !== minutes) { | |
lastMinutes = minutes; | |
minutesElements.forEach(element => element.innerHTML = (minutes < 10 ? "0" : "") + minutes); | |
} | |
if (CONFIG.ENABLE_SECONDS && lastSeconds !== seconds) { | |
lastSeconds = seconds; | |
secondsElements.forEach(element => element.innerHTML = (seconds < 10 ? "0" : "") + seconds); | |
} | |
} | |
function updateCountdown(timestamp) { | |
var milliseconds = parseInt(timestamp - lastTimestamp); | |
timeToDeadline = Math.max(0, timeToDeadline - milliseconds); | |
lastTimestamp = timestamp; | |
/* | |
For each unit of time, we only want to modulo (%) the number if the | |
next larger unit is enabled. | |
E.G. 2 Hours : 30 Minutes, not 2 Hours : 120 Minutes | |
*/ | |
if (CONFIG.ENABLE_DAYS) { | |
days = parseInt(timeToDeadline / 86400000); | |
} | |
if (CONFIG.ENABLE_HOURS) { | |
hours = parseInt(timeToDeadline / 3600000); | |
if (CONFIG.ENABLE_DAYS) { | |
hours = hours % 24; | |
} | |
} | |
if (CONFIG.ENABLE_MINUTES) { | |
minutes = parseInt(timeToDeadline / 60000) | |
if (CONFIG.ENABLE_HOURS) { | |
minutes = minutes % 60; | |
} | |
} | |
if (CONFIG.ENABLE_SECONDS) { | |
seconds = parseInt(timeToDeadline / 1000) | |
if (CONFIG.ENABLE_MINUTES) { | |
seconds = seconds % 60; | |
} | |
} | |
updateHTMLElements(); | |
// Stop updating once we reach the deadline | |
if (timeToDeadline > 0) { | |
window.requestAnimationFrame(updateCountdown); | |
} | |
} | |
window.requestAnimationFrame(updateCountdown); | |
})(); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment