Create a beautiful Snowy Weather Widget โ๏ธ๐ง๏ธ using HTML, CSS, and JavaScript.
In this tutorial, youโll learn how to design a realistic snowfall and rain weather animation perfect for websites, dashboards, portfolios, and weather apps.
โจ What youโll learn:
- Snowfall animation using CSS & JavaScript
- Rain effect for weather UI
- Modern glassmorphism weather widget
- Responsive & lightweight design
- Easy customization for any project
๐ Ideal for frontend developers, UI designers, and JavaScript beginners.
๐ Like | ๐ฌ Comment | ๐ Subscribe for more HTML, CSS & JS projects!
HTML:
Create a HTML file and add the following code:
<div class="bg-photo"></div>
<div class="bg-tint"></div>
<div class="container">
<div class="card">
<div class="card-body">
<div class="backgroundNight"></div>
<div class="background"></div>
<div class="temperature cardInfo">
<span id="temperature">33</span>ยฐF
</div>
<div class="weatherType cardInfo">
<span id="weatherType">Snow</span>
</div>
<div class="currentDay cardInfo">
<span id="currentDay">New York City</span>
</div>
<div class="sun"></div>
<div class="moon"></div>
<div id="cloud"></div>
<div id="light-snow"></div>
<div class="hours-container">
<div class="hours"></div>
</div>
</div>
</div>
</div>
CSS:
Create a CSS file and add the following code:
:root {
--title: "Snowy Weather Widget";
--author: "Matt Cannon";
--contact: "mc@mattcannon.design";
--description: "A clean, interactive New York City weather widget with a blurred photo background behind the card. Includes drifting clouds, heavy animated snow, and a sun and moon that move smoothly across the sky based on the selected hour.";
--keywords: "weather app, snow animation, glassmorphism, nyc, parallax clouds, particles.js, sun and moon animation, hourly forecast, codepenchallenge, cpc-snow-ice, interactive ui, winter design, css js animation";
--last-modified: "2025-12-08";
--content-language: "en";
--generator: "HTML5, CSS3, JavaScript, jQuery, particles.js";
}
body {
height: 100vh;
margin: 0;
background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%);
overflow: hidden;
font-family: "Plus Jakarta Sans", sans-serif;
font-weight: 300;
color: #000;
}
.bg-photo {
--bg-photo: url("https://codewithubes.in/cloud-images/new-york.jpg");
position: fixed;
inset: 0;
background-image: var(--bg-photo);
background-size: cover;
background-position: center;
filter: blur(12px) saturate(120%) brightness(0.7);
transform: scale(1.06);
z-index: -2;
}
.bg-tint {
position: fixed;
inset: 0;
background: radial-gradient(
circle at top,
rgba(148, 163, 184, 0.5),
transparent 60%
),
linear-gradient(180deg, rgba(15, 23, 42, 0.85), #020617 80%, #000 100%);
mix-blend-mode: soft-light;
z-index: -1;
}
.container {
max-width: 400px;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.card {
position: relative;
overflow: hidden;
height: 566px;
width: 350px;
border-radius: 32px;
border: 1px solid rgba(255, 255, 255, 0.14);
background: linear-gradient(
135deg,
rgba(255, 255, 255, 0.16),
rgba(15, 23, 42, 0.9)
);
backdrop-filter: blur(24px) saturate(160%);
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.85);
margin: 0;
}
.card::before {
content: "";
position: absolute;
inset: 0;
padding: 1px;
border-radius: inherit;
background: conic-gradient(
from 160deg,
rgba(56, 189, 248, 0.7),
rgba(129, 140, 248, 0.2),
rgba(244, 114, 182, 0.7),
rgba(56, 189, 248, 0.7)
);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
opacity: 0.9;
pointer-events: none;
}
.card::after {
content: "";
position: absolute;
width: 180px;
height: 180px;
top: -60px;
right: -40px;
background: radial-gradient(
circle at center,
rgba(255, 255, 255, 0.35),
transparent 60%
);
filter: blur(12px);
opacity: 0.8;
pointer-events: none;
}
.card,
.card-body {
background: transparent !important;
padding: 0;
}
.background {
position: absolute;
width: 100%;
height: 100%;
background-image: linear-gradient(0deg, #fefefe 0%, #00a4e4 74%);
z-index: 0;
opacity: 0.95;
transition: all 2s linear;
}
.backgroundNight {
position: absolute;
width: 100%;
height: 100%;
background-image: linear-gradient(0deg, #4c5177 0%, #051428 74%);
z-index: -1;
transition: all 2s linear;
}
.sun,
.moon {
position: absolute;
left: 50%;
width: 80px;
height: 80px;
border-radius: 50%;
transform-origin: 0px 220px;
transition: all 1s;
transform: rotate(-90deg);
}
.sun {
bottom: 300px;
background: #fceabb;
box-shadow: 0px 0px 40px 15px #fceabb;
opacity: 1;
}
.moon {
bottom: 250px;
background: url("https://drive.google.com/thumbnail?id=1nbYvuzW1fU3iiXoxKeMSb4TvP7rkryuy&sz=w1000");
background-size: contain;
box-shadow: 0px 0px 20px 5px #ffffff;
opacity: 0;
}
.hours-container {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
overflow-x: scroll;
white-space: nowrap;
backdrop-filter: blur(20px);
scroll-behavior: smooth;
}
.hours {
display: flex;
padding: 8px;
}
.hour {
padding: 5px 10px;
cursor: pointer;
margin: 2px;
transition: background-color 0.3s ease;
border-radius: 16px;
height: 107px;
min-width: 80px;
text-align: center;
}
.hour:hover {
background-color: rgba(255, 255, 255, 0.3);
}
.active {
background-color: rgba(255, 255, 255, 0.7);
}
.hour span {
position: relative;
display: flex;
text-align: center;
color: black;
}
.hour .timeSpan {
font-size: 14px;
font-weight: 300;
}
.hour .tempSpan {
font-size: 14px;
font-weight: 700;
}
.hour .material-symbols-rounded {
font-size: 32px;
line-height: 40px;
}
.hour[data-weather="snowy"] .material-symbols-rounded::after {
content: "ac_unit";
}
.hour .material-symbols-rounded::after {
content: "ac_unit" !important;
}
.temperature {
position: absolute;
z-index: 2;
right: 24px;
top: 24px;
text-align: right;
font-size: 60px;
font-weight: 400;
color: #000;
}
.weatherType {
position: absolute;
z-index: 2;
right: 24px;
top: 100px;
text-align: right;
font-size: 25px;
line-height: 34px;
text-transform: capitalize;
color: #000;
}
.currentDay {
position: absolute;
z-index: 2;
left: 16px;
bottom: 144px;
text-align: left;
font-size: 25px;
line-height: 34px;
color: #000;
}
#light-snow {
opacity: 1;
top: 0;
position: absolute;
pointer-events: none;
z-index: 0;
width: 100%;
height: 100%;
transition: all 2s;
}
#cloud {
position: absolute;
z-index: 0;
width: 100%;
height: 100%;
background-image: url("");
background-repeat: no-repeat;
background-size: cover;
background-position: 50% 50%;
filter: brightness(200%) drop-shadow(0 0 10px rgba(255, 255, 255, 1));
top: 0;
transition: all 2s;
opacity: 60%;
}
JavaScript:
Create a JS file and add the following code:
$(document).ready(function () {
const hoursData = [
{ day: "tod", hour: 8, weather: "snowy", temp: 29, time: "8 AM" },
{ day: "tod", hour: 10, weather: "snowy", temp: 31, time: "10 AM" },
{ day: "tod", hour: 12, weather: "snowy", temp: 33, time: "12 PM" },
{ day: "tod", hour: 14, weather: "snowy", temp: 32, time: "2 PM" },
{ day: "tod", hour: 16, weather: "snowy", temp: 30, time: "4 PM" },
{ day: "tod", hour: 18, weather: "snowy", temp: 28, time: "6 PM" },
{ day: "tod", hour: 20, weather: "snowy", temp: 27, time: "8 PM" },
{ day: "tod", hour: 22, weather: "snowy", temp: 25, time: "10 PM" },
{ day: "tom", hour: 8, weather: "snowy", temp: 28, time: "8 AM" },
{ day: "tom", hour: 10, weather: "snowy", temp: 30, time: "10 AM" },
{ day: "tom", hour: 12, weather: "snowy", temp: 32, time: "12 PM" },
{ day: "tom", hour: 14, weather: "snowy", temp: 33, time: "2 PM" },
{ day: "tom", hour: 16, weather: "snowy", temp: 31, time: "4 PM" },
{ day: "tom", hour: 18, weather: "snowy", temp: 29, time: "6 PM" },
{ day: "tom", hour: 20, weather: "snowy", temp: 27, time: "8 PM" },
{ day: "tom", hour: 22, weather: "snowy", temp: 24, time: "10 PM" }
];
hoursData.forEach((data) => {
const hourDiv = $("<div>", {
class: "hour d-flex flex-column align-items-center",
"data-day": data.day,
"data-hour": data.hour,
"data-weather": data.weather,
"data-temp": data.temp
});
const timeSpan = $("<span class='timeSpan'>").text(data.time);
const iconSpan = $("<span>", { class: "material-symbols-rounded" });
const tempSpan = $("<span class='tempSpan'>").text(data.temp + "ยฐF");
hourDiv.append(timeSpan, iconSpan, tempSpan);
$(".hours").append(hourDiv);
});
const background = $(".background");
const backgroundNight = $(".backgroundNight");
const sun = $(".sun");
const moon = $(".moon");
const hoursContainer = $(".hours-container");
const hours = $(".hour");
const snow = $("#snow");
const temperatureDisplay = $("#temperature");
const weatherTypeDisplay = $("#weatherType");
const currentDay = $("#currentDay");
const initialHourIndex = 2;
function toggleSunMoon(hour) {
if (hour >= 6 && hour <= 21) {
const rotation = -90 + (hour - 7) * (180 / 15);
sun.css("transform", "rotate(" + rotation + "deg)");
sun.css("opacity", "1");
moon.css("opacity", "0");
background.css("opacity", "1");
backgroundNight.css("opacity", "0");
} else {
moon.css("opacity", "1");
sun.css("opacity", "0");
const adjustedHour = hour < 7 ? hour + 24 : hour;
const rotation = -90 + (adjustedHour - 6) * (180 / 8);
moon.css("transform", "rotate(" + rotation + "deg)");
background.css("opacity", "0");
backgroundNight.css("opacity", "1");
}
}
function highlightHour(index) {
hours.removeClass("active");
hours.eq(index).addClass("active");
}
function updateWeatherAndTemperature(currentHour) {
const temperature = currentHour.data("temp");
const day = currentHour.data("day");
temperatureDisplay.text(temperature);
weatherTypeDisplay.text("Snow");
snow.css("opacity", "1");
background.css("filter", "grayscale(0.4) opacity(0.9)");
sun.css("filter", "grayscale(0.8)");
moon.css("filter", "none");
if (day === "tom") currentDay.text("Tomorrow");
else currentDay.text("New York City");
}
function handleScrollEvent() {
const sl = hoursContainer.scrollLeft();
const hourIndex = Math.round(sl / hours.outerWidth());
const currentHour = hours.eq(hourIndex);
const hr = parseInt(currentHour.data("hour"), 10) || 12;
toggleSunMoon(hr);
highlightHour(hourIndex);
updateWeatherAndTemperature(currentHour);
}
function init() {
highlightHour(initialHourIndex);
const initialHour = hours.eq(initialHourIndex);
const hr = parseInt(initialHour.data("hour"), 10) || 12;
toggleSunMoon(hr);
updateWeatherAndTemperature(initialHour);
hoursContainer.scrollLeft(81 * initialHourIndex);
}
hoursContainer.on("scroll", handleScrollEvent);
hours.on("click", function () {
const idx = hours.index(this);
const hr = parseInt($(this).data("hour"), 10) || 12;
toggleSunMoon(hr);
highlightHour(idx);
updateWeatherAndTemperature($(this));
});
particlesJS("cloud", {
particles: {
number: { value: 5, density: { enable: true, value_area: 200 } },
shape: {
type: "image",
image: {
src: "https://codewithubes.in/cloud-images/fluffyvloud.png",
width: 100,
height: 100
}
},
opacity: { value: 1, random: true },
size: {
value: 800,
random: false
},
line_linked: { enable: false },
move: {
enable: true,
speed: 1,
direction: "left",
random: true,
straight: false,
out_mode: "out"
}
},
retina_detect: true
});
particlesJS("light-snow", {
particles: {
number: {
value: 900,
density: { enable: true, value_area: 500 }
},
color: { value: "#ffffff" },
shape: { type: "circle" },
opacity: {
value: 1,
random: true
},
size: {
value: 3.8,
random: true
},
line_linked: { enable: false },
move: {
enable: true,
speed: 2,
direction: "bottom",
random: true,
straight: false,
out_mode: "out",
bounce: false
}
},
retina_detect: true
});
init();
});
Scripts:
<script src="https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js" type="text/javascript"></script>
SnowyWeather #WeatherWidget #HTMLCSSJS #SnowAnimation #RainEffect #WebAnimation #FrontendDevelopment #JavaScriptProjects #CSSAnimation #UIUX #WebDesign #CodingTutorial โ๏ธ๐ง๏ธ
Happy coding!

