Snowy Weather Widget
Snowy Weather Widget

Snowy Weather Widget โ„๏ธ๐ŸŒง๏ธ | Realistic Snow & Rain Animation using HTML CSS JavaScript

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:

  1. Snowfall animation using CSS & JavaScript
  2. Rain effect for weather UI
  3. Modern glassmorphism weather widget
  4. Responsive & lightweight design
  5. 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!