This tutorial will guide you through creating a web application that features a digital clock, customizable countdowns, and background music. The application uses HTML, CSS (with Tailwind), and JavaScript to create an interactive and visually appealing user interface.
Key Features
1. Digital Clock: Displays the current time and date.
2. Countdown System: Allows users to add and track multiple countdown events.
3. Background Music: Includes three audio tracks that play in sequence.
4. Animated Background: Features floating, colorful shapes for visual interest.
Structure Overview
The application is built using a single HTML file that includes all necessary styles and scripts. Here's a breakdown of its main components:
HTML Structure
- The `<head>` section includes links to Tailwind CSS and Font Awesome, as well as custom styles for the animated background shapes.
- The `<body>` contains:
- Animated background shapes
- A navigation bar with a music toggle button
- The main content area with the clock and countdown sections
- Audio elements for the background music
CSS Styling
- Tailwind CSS classes are used extensively for layout and basic styling.
- Custom CSS animations are defined for the floating background shapes.
JavaScript Functionality
The script at the bottom of the file handles three main functions:
1. Updating the digital clock
2. Managing the countdown system
3. Controlling the background music
Key Code Sections Explained
1. Digital Clock
The `updateClock()` function is responsible for updating the time and date display. It's called every second using `setInterval()`.
2. Countdown System
The countdown system allows users to add up to 6 countdowns. Key functions include:
- `updateCountdown()`: Calculates and updates the remaining time for each countdown.
- `createCountdownElement()`: Creates the HTML structure for a new countdown.
- Event listener on the "Add Countdown" button to create new countdowns.
3. Background Music
The music system cycles through three audio tracks. Key features include:
- Toggle button to play/pause music.
- Automatic progression to the next track when one ends.
4. Animated Background
Five floating shapes are created using CSS animations. Each shape has a unique animation defined in the `<style>` section of the HTML.
Conclusion
This application demonstrates how to combine HTML, CSS, and JavaScript to create an interactive web application with multiple features. By studying and modifying this code, you can learn about real-time updates, user input handling, and audio control in web development.
The complete code for this application is provided below:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Digital Clock with Scrollable Countdowns and Music</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
<style>
/* Add this CSS for scrolling */
body {
overflow-y: auto; /* Allow vertical scrolling */
}
main {
height: auto; /* Allow main content to expand with more countdowns */
}
@keyframes float1 {
0%, 100% { transform: translate(-50px, -50px) rotate(0deg); }
50% { transform: translate(50px, 50px) rotate(360deg); }
}
@keyframes float2 {
0%, 100% { transform: translate(50px, -50px) rotate(0deg); }
50% { transform: translate(-50px, 50px) rotate(-360deg); }
}
@keyframes float3 {
0%, 100% { transform: translate(-50px, 50px) scale(1); }
50% { transform: translate(50px, -50px) scale(1.2); }
}
@keyframes float4 {
0%, 100% { transform: translate(0, -100px) rotate(0deg); }
50% { transform: translate(0, 100px) rotate(180deg); }
}
@keyframes float5 {
0%, 100% { transform: translate(-100px, 0) scale(1); }
50% { transform: translate(100px, 0) scale(0.8); }
}
.shape {
position: absolute;
border-radius: 50%;
filter: blur(50px);
opacity: 0.6;
z-index: -1;
}
#shape1 {
width: 300px; height: 300px;
background: #ff6b6b;
animation: float1 20s infinite ease-in-out;
top: 10%; left: 10%;
}
#shape2 {
width: 250px; height: 250px;
background: #4ecdc4;
animation: float2 25s infinite ease-in-out;
top: 60%; right: 10%;
}
#shape3 {
width: 200px; height: 200px;
background: #45aaf2;
animation: float3 22s infinite ease-in-out;
bottom: 15%; left: 15%;
}
#shape4 {
width: 350px; height: 350px;
background: #f7b731;
animation: float4 28s infinite ease-in-out;
top: 40%; left: 60%;
}
#shape5 {
width: 280px; height: 280px;
background: #26de81;
animation: float5 24s infinite ease-in-out;
top: 20%; right: 20%;
}
</style>
</head>
<body class="bg-[#000033] min-h-screen flex flex-col items-center justify-between">
<div class="shape" id="shape1" aria-hidden="true"></div>
<div class="shape" id="shape2" aria-hidden="true"></div>
<div class="shape" id="shape3" aria-hidden="true"></div>
<div class="shape" id="shape4" aria-hidden="true"></div>
<div class="shape" id="shape5" aria-hidden="true"></div>
<nav class="w-full bg-white/10 backdrop-blur-md p-4 flex justify-end">
<button id="musicToggle" class="text-white text-2xl focus:outline-none mr-4" aria-label="Toggle music">
<i class="fas fa-music"></i>
</button>
</nav>
<main class="flex flex-col items-center justify-center flex-grow w-full max-w-4xl mx-auto px-4 py-8">
<div class="bg-white/10 backdrop-blur-md border border-white/20 rounded-xl p-8 shadow-lg w-full flex flex-col items-center justify-between relative z-10 mb-8">
<div id="clock" class="font-mono text-7xl text-white tracking-wider mb-4"></div>
<div id="date" class="font-mono text-2xl text-white tracking-wide"></div>
</div>
<div class="bg-white/10 backdrop-blur-md border border-white/20 rounded-xl p-8 shadow-lg w-full flex flex-col items-center justify-between relative z-10">
<h2 class="text-white text-2xl mb-4">Countdowns</h2>
<div class="flex flex-wrap justify-center gap-4 mb-4">
<input type="text" id="countdownName" class="bg-white/20 text-white px-2 py-1 rounded" placeholder="Countdown Name">
<input type="date" id="countdownDate" class="bg-white/20 text-white px-2 py-1 rounded">
<button id="addCountdown" class="bg-blue-500 text-white px-4 py-1 rounded">Add Countdown</button>
</div>
<div id="countdowns" class="w-full grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 max-h-96 overflow-y-auto p-4"></div>
</div>
</main>
<audio id="music1" loop>
<source src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" type="audio/mpeg">
</audio>
<audio id="music2" loop>
<source src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" type="audio/mpeg">
</audio>
<audio id="music3" loop>
<source src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" type="audio/mpeg">
</audio>
<script>
function updateClock() {
const now = new Date();
let hours = now.getHours();
const minutes = now.getMinutes().toString().padStart(2, '0');
const seconds = now.getSeconds().toString().padStart(2, '0');
const ampm = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12;
hours = hours ? hours : 12; // the hour '0' should be '12'
hours = hours.toString().padStart(2, '0');
const timeString = `${hours}:${minutes}:${seconds} ${ampm}`;
document.getElementById('clock').textContent = timeString;
const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
const dateString = now.toLocaleDateString(undefined, options);
document.getElementById('date').textContent = dateString;
}
updateClock(); // Initial call
setInterval(updateClock, 1000); // Update every second
// Countdown functionality
const countdownName = document.getElementById('countdownName');
const countdownDate = document.getElementById('countdownDate');
const addCountdown = document.getElementById('addCountdown');
const countdownsContainer = document.getElementById('countdowns');
let countdowns = [];
function updateCountdown(countdown) {
const now = new Date().getTime();
const distance = new Date(countdown.date).getTime() - now;
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
countdown.element.querySelector('.countdown-timer').textContent =
`${days}d ${hours}h ${minutes}m ${seconds}s`;
if (distance < 0) {
countdown.element.querySelector('.countdown-timer').textContent = "EXPIRED";
}
}
function createCountdownElement(countdown) {
const element = document.createElement('div');
element.className = 'bg-white/5 p-4 rounded-lg';
element.innerHTML = `
<h3 class="text-white text-lg font-semibold mb-2">${countdown.name}</h3>
<p class="text-white mb-2">${new Date(countdown.date).toLocaleDateString()}</p>
<p class="countdown-timer text-white text-xl"></p>
<button class="remove-countdown text-red-500 mt-2">Remove</button>
`;
element.querySelector('.remove-countdown').addEventListener('click', () => {
countdowns = countdowns.filter(c => c !== countdown);
element.remove();
});
return element;
}
addCountdown.addEventListener('click', () => {
if (countdowns.length >= 6) {
alert('Maximum of 6 countdowns reached!');
return;
}
if (!countdownName.value || !countdownDate.value) {
alert('Please enter both a name and a date for the countdown.');
return;
}
const countdown = {
name: countdownName.value,
date: countdownDate.value
};
countdown.element = createCountdownElement(countdown);
countdownsContainer.appendChild(countdown.element);
countdowns.push(countdown);
countdownName.value = '';
countdownDate.value = '';
});
setInterval(() => {
countdowns.forEach(updateCountdown);
}, 1000);
const musicToggle = document.getElementById('musicToggle');
const music1 = document.getElementById('music1');
const music2 = document.getElementById('music2');
const music3 = document.getElementById('music3');
let currentMusic = music1;
let isPlaying = false;
musicToggle.addEventListener('click', () => {
if (isPlaying) {
currentMusic.pause();
musicToggle.innerHTML = '<i class="fas fa-music"></i>';
} else {
currentMusic.play();
musicToggle.innerHTML = '<i class="fas fa-pause"></i>';
}
isPlaying = !isPlaying;
});
music1.addEventListener('ended', () => {
currentMusic = music2;
currentMusic.play();
});
music2.addEventListener('ended', () => {
currentMusic = music3;
currentMusic.play();
});
music3.addEventListener('ended', () => {
currentMusic = music1;
currentMusic.play();
});
</script>
</body>
</html>