What You'll Build

In this tutorial, you'll build a CSS neon digital clock entirely from scratch — no libraries, no canvas, just HTML, CSS, and vanilla JavaScript. The clock displays live hours, minutes, and seconds using a 7-segment display system styled with neon glow effects, sits in a 3D perspective scene, and includes a glowing floor reflection.

This project is a step up from beginner work — it's ideal if you want to practice requestAnimationFrame, CSS 3D transforms, data attribute selectors, and dynamic DOM generation in one visually impressive project.


Key Features of This Neon Clock

🕐
Real-Time Display
Updates live every second using requestAnimationFrame for smooth rendering.
💡
Neon Glow Segments
CSS drop-shadow filters create realistic neon tube glow on each digit segment.
📐
3D Perspective Camera
preserve-3d and CSS keyframes animate a slow orbit around the clock.
🔢
7-Segment Digit System
Each digit uses CSS [data-digit] selectors to show the correct segments.
🪞
Floor Reflection Effect
Shadow clone elements below the clock simulate a glowing reflection on the surface.
📱
Responsive with vmin
Uses vmin units throughout so the clock scales cleanly on any screen size.
🌐
Cross-Browser Support
Includes Safari-specific fixes for consistent rendering across all modern browsers.
🚀
Zero Dependencies
Pure HTML, CSS, and JavaScript — no external libraries, build tools, or CDN scripts.

Full Source Code (Free)

The project uses three files: HTML for the minimal container structure, CSS for the 3D scene and neon glow styling, and JavaScript for the digit generation and real-time update logic. Use the tabs to switch between them.

HTML — index.html
CSS — style.css
JS — script.js
💡 Quick Start: Copy all three files into the same folder and open index.html in your browser. The clock starts displaying the current time immediately — no server required.

How It Works — Step by Step

Here's a breakdown of the eight core techniques behind this neon digital clock, from DOM generation to the 3D scene setup.

01

Minimal HTML Structure

The HTML contains only a <main> element. All clock segments, digits, colons, and reflection elements are generated and injected by JavaScript, keeping the markup completely clean and the rendering logic centralized in the JS file.

02

JavaScript Digit Generator

An addDigits() function creates a set of seven <span> elements — one per segment of a 7-segment display. Each digit container receives a data-digit attribute that CSS uses to show or hide the correct segments for numbers 0–9.

03

Real-Time Clock with requestAnimationFrame

A recursive requestAnimationFrame(update) loop runs on every frame. Inside the loop, new Date() reads the current time. When the seconds value changes, the function updates data-digit on the relevant elements, which triggers CSS to redraw the correct segments instantly.

04

CSS Neon Glow via drop-shadow

Active segments receive filter: drop-shadow(0 0 Xpx var(--glow-color)) with multiple layered shadow values. Because drop-shadow follows the actual shape — not a bounding box — the glow hugs each bar segment precisely, creating a convincing neon tube appearance.

05

3D Perspective Scene

The clock container uses transform-style: preserve-3d and perspective: Xpx to enable 3D rendering. A CSS @keyframes animation continuously rotates the container around the Y-axis, creating a slow camera orbit that shows the clock from slightly different angles over time.

06

data-digit CSS Selectors

Each of the 7 spans inside a digit has a positional class (top, mid, bot, top-left, etc.). CSS rules like [data-digit="7"] .top, [data-digit="7"] .top-right, [data-digit="7"] .bot-right { opacity: 1; } activate only the segments needed for that digit, while all others remain dim.

07

Floor Reflection

JavaScript clones each digit group and appends it below the clock with transform: scaleY(-1). A gradient mask-image fades the reflection from fully opaque at the top to transparent at the bottom, simulating a glowing surface below the clock.

08

Cross-Browser Safari Fixes

navigator.userAgent detects Safari and applies -webkit- prefixed properties where needed. Safari has historically had inconsistent support for preserve-3d in combination with certain CSS filters, so targeted overrides ensure consistent rendering.

⚠️ Performance Note: CSS drop-shadow filters on many elements simultaneously can be GPU-intensive on lower-end devices. If you notice frame drops on mobile, reduce the number of shadow layers or lower the blur radius in the filter values.

JavaScript & CSS Concepts Used

This project covers these intermediate-to-advanced web development techniques:

  • requestAnimationFrame — Building a performant real-time update loop that syncs with the display refresh rate.
  • Dynamic DOM Generation — Creating and injecting all clock elements programmatically from JavaScript.
  • CSS Data Attribute Selectors — Using [data-digit="X"] to conditionally style elements based on their data values.
  • CSS 3D Transformstransform-style: preserve-3d, perspective, and rotateY() for 3D scenes.
  • CSS drop-shadow Filter — Layered glow effects that follow element shapes precisely.
  • CSS vmin Units — Responsive sizing that scales with the smaller viewport dimension for consistent layouts.
  • CSS mask-image — Gradient masks to fade the reflection element from visible to transparent.
  • Cross-Browser Detection — UA detection and conditional styles for Safari compatibility.

Frequently Asked Questions

How do I create a real-time digital clock with JavaScript?
Use requestAnimationFrame() in a recursive loop. On each frame, call new Date() and extract getHours(), getMinutes(), and getSeconds(). When the seconds value changes, update your DOM elements with the new time values. Full source code is in the tabs above.
How does the neon glow effect work in CSS?
The glow uses filter: drop-shadow() with multiple layered values at different blur radii and opacities. Unlike box-shadow, drop-shadow follows the actual painted shape of the element — so for thin bar segments, the glow hugs each bar rather than a rectangular boundary.
What is a 7-segment display and how is it built with CSS?
A 7-segment display represents each digit using 7 bar-shaped segments. In CSS, each segment is a <span> styled as a horizontal or vertical bar. CSS attribute selectors like [data-digit="3"] .top { opacity: 1; } activate the correct segments for each number 0–9 while all others stay dim.
Why use requestAnimationFrame instead of setInterval?
requestAnimationFrame syncs with the display's refresh rate (~60fps), resulting in smoother CSS transitions and better battery efficiency than setInterval. It also automatically pauses when the tab is inactive, saving CPU resources.
How does the 3D camera animation work?
The clock wrapper has transform-style: preserve-3d and a perspective value set on its parent. A CSS @keyframes animation continuously rotates the wrapper from rotateY(0deg) to rotateY(360deg) over a long duration, creating a slow, continuous orbit.
Is this project good for beginner developers?
It's labeled intermediate — it uses concepts beyond basic HTML/CSS: requestAnimationFrame, CSS 3D transforms, data attribute selectors, and dynamic DOM generation. It's an ideal third or fourth project for someone who has completed the basics and wants to build something visually impressive.

Conclusion

This CSS neon digital clock demonstrates how far vanilla web technologies can go. By combining requestAnimationFrame for real-time updates, CSS data attribute selectors for the 7-segment display system, drop-shadow filters for the neon glow, and CSS 3D transforms for the perspective scene — you get a production-quality visual project with zero dependencies.

Whether you're building a portfolio piece, learning advanced JavaScript timing, or just want to master CSS 3D — this project covers the real-world techniques that matter. Copy the code, change the glow color, adjust the animation speed, and make it yours.

Found this useful? Explore more HTML CSS JavaScript projects in the sidebar.