Back to Components
Do You Love Me? – Interactive Valentine Web Animation
Component

Do You Love Me? – Interactive Valentine Web Animation

CodewithLord
February 9, 2026

A playful Valentine-themed interactive web experience using HTML, CSS, and JavaScript where users try to click a moving 'No' button, a heart loader animation plays, and a cute reveal appears on saying Yes.

💖 Overview

This project is a fun, interactive Valentine web animation where the user is asked
“Do you love me?”

  • Clicking No becomes impossible because the button escapes the cursor
  • Clicking Yes triggers a heart loader animation
  • After a short delay, a cute confirmation message with a video is revealed

Perfect for:

  • Valentine reels & shorts
  • Beginner-friendly JavaScript projects
  • Cute UI demos for portfolios

🧩 Code

🔹 HTML, CSS & JavaScript (Combined)

1<!DOCTYPE html> 2<html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 <link rel="preconnect" href="https://fonts.googleapis.com" /> 7 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> 8 <link 9 href="https://fonts.googleapis.com/css2?family=Quicksand:wght@300..700&display=swap" 10 rel="stylesheet" /> 11 <link rel="stylesheet" href="style.css" /> 12 <title>Do you love me?</title> 13</head> 14<body> 15 16<div class="question-container container"> 17<video class="local-gif" src="Reply me love.mp4" autoplay muted loop></video> 18 <h2 class="question">Do you love me?</h2> 19 <div class="button-container"> 20 <button class="yes-btn btn js-yes-btn">Yes</button> 21 <button class="no-btn btn js-no-btn">No</button> 22 </div> 23</div> 24<div class="result-container container"> 25 <video class="gif-result" src="Love me.mp4" autoplay loop></video> 26 <h2>I knew it😍!</h2> 27</div> 28 29<div class="cssload-main"> 30 <div class="cssload-heart"> 31 <span class="cssload-heartL"></span> 32 <span class="cssload-heartR"></span> 33 <span class="cssload-square"></span> 34 </div> 35 <div class="cssload-shadow"></div> 36</div> 37<script src="script.js"></script> 38 39</body> 40</html>

CSS Code


1* { 2 padding: 0; 3 margin: 0; 4 box-sizing: border-box; 5} 6body { 7 display: grid; 8 justify-content: center; 9 align-items: center; 10 background-color: white; 11 font-family: "Quicksand", sans-serif; 12} 13.container { 14 position: absolute; 15 top: 50%; 16 left: 50%; 17 transform: translate(-50%, -50%); 18 -o-transform: translate(-50%, -50%); 19 -ms-transform: translate(-50%, -50%); 20 -webkit-transform: translate(-50%, -50%); 21 -moz-transform: translate(-100%, -50%); 22 transition: 0.2s; 23} 24 25.question-container { 26 position: absolute; 27 top: 40%; 28 left: 50%; 29 transition: 0.2s; 30} 31.local-gif { 32 width: 100%; 33 max-width: 300px; 34 border-radius: 10px; 35 display: block; 36 margin: 0 auto 3rem auto; 37 pointer-events: none; 38} 39.question { 40 font-size: 3.5rem; 41 margin-bottom: 1rem; 42} 43.button-container { 44 display: flex; 45 justify-content: center; 46 gap: 1.5rem; 47} 48.btn { 49 position: absolute; 50 border: none; 51 border-radius: 50px; 52 padding: 14px 24px; 53 font-family: "Poppins", sans-serif; 54 font-size: 18px; 55 cursor: pointer; 56 transition: all 0.3s ease; 57 background-color: #ff54a4; 58 color: white; 59 transform: scale(1.05); 60 box-shadow: 0px 4px 15px 61 rgba(255, 107, 129, 0.5); 62} 63.btn:hover { 64 background-color: #ffa4b1; 65 transform: scale(1.1); 66 box-shadow: 0px 6px 20px rgba(255, 107, 129, 0.7); 67 text-shadow: 1px 1px 5px rgba(255, 182, 193, 0.8); 68} 69 70.yes-btn { 71 right: 54%; 72} 73.no-btn { 74 left: 54%; 75} 76 77.result-container { 78 display: none; 79 position: absolute; 80 top: 40%; 81 left: 50%; 82 transform: translate(-50%, -50%); 83 -o-transform: translate(-50%, -50%); 84 -ms-transform: translate(-50%, -50%); 85 -webkit-transform: translate(-50%, -50%); 86 -moz-transform: translate(-100%, -50%); 87 transition: 0.2s; 88} 89.gif-result { 90 border-radius: 10px; 91 margin-bottom: 2rem; 92} 93.result-container h2 { 94 font-size: 3.2rem; 95 text-align: center; 96} 97 98/* heart loader */ 99.cssload-main { 100 display: none; 101 position: absolute; 102 content: ""; 103 top: 17%; 104 left: 50%; 105 margin: 200px auto 0 auto; 106 transform: translate(-100%, -50%); 107 -o-transform: translate(-100%, -240%); 108 -ms-transform: translate(-100%, -240%); 109 -webkit-transform: translate(-100%, -240%); 110 -moz-transform: translate(-100%, -240%); 111} 112 113.cssload-main * { 114 font-size: 62px; 115} 116 117.cssload-heart { 118 animation: cssload-heart 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite normal; 119 -o-animation: cssload-heart 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 120 normal; 121 -ms-animation: cssload-heart 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 122 normal; 123 -webkit-animation: cssload-heart 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 124 normal; 125 -moz-animation: cssload-heart 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 126 normal; 127 top: 50%; 128 content: ""; 129 left: 50%; 130 position: absolute; 131} 132 133.cssload-heartL { 134 width: 1em; 135 height: 1em; 136 border: 1px solid #ff0000; 137 background-color: #ff0000; 138 content: ""; 139 position: absolute; 140 display: block; 141 border-radius: 100%; 142 animation: cssload-heartL 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite normal; 143 -o-animation: cssload-heartL 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 144 normal; 145 -ms-animation: cssload-heartL 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 146 normal; 147 -webkit-animation: cssload-heartL 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 148 normal; 149 -moz-animation: cssload-heartL 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 150 normal; 151 transform: translate(-28px, -27px); 152 -o-transform: translate(-28px, -27px); 153 -ms-transform: translate(-28px, -27px); 154 -webkit-transform: translate(-28px, -27px); 155 -moz-transform: translate(-28px, -27px); 156} 157 158.cssload-heartR { 159 width: 1em; 160 height: 1em; 161 border: 1px solid #ff0000; 162 background-color: #ff0000; 163 content: ""; 164 position: absolute; 165 display: block; 166 border-radius: 100%; 167 transform: translate(28px, -27px); 168 -o-transform: translate(28px, -27px); 169 -ms-transform: translate(28px, -27px); 170 -webkit-transform: translate(28px, -27px); 171 -moz-transform: translate(28px, -27px); 172 animation: cssload-heartR 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite normal; 173 -o-animation: cssload-heartR 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 174 normal; 175 -ms-animation: cssload-heartR 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 176 normal; 177 -webkit-animation: cssload-heartR 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 178 normal; 179 -moz-animation: cssload-heartR 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 180 normal; 181} 182 183.cssload-square { 184 width: 1em; 185 height: 1em; 186 border: 1px solid #ff0000; 187 background-color: #ff0000; 188 position: relative; 189 display: block; 190 content: ""; 191 transform: scale(1) rotate(-45deg); 192 -o-transform: scale(1) rotate(-45deg); 193 -ms-transform: scale(1) rotate(-45deg); 194 -webkit-transform: scale(1) rotate(-45deg); 195 -moz-transform: scale(1) rotate(-45deg); 196 animation: cssload-square 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite normal; 197 -o-animation: cssload-square 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 198 normal; 199 -ms-animation: cssload-square 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 200 normal; 201 -webkit-animation: cssload-square 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 202 normal; 203 -moz-animation: cssload-square 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 204 normal; 205} 206 207.cssload-shadow { 208 top: 97px; 209 left: 50%; 210 content: ""; 211 position: relative; 212 display: block; 213 bottom: -0.5em; 214 width: 1em; 215 height: 0.24em; 216 background-color: rgb(215, 215, 215); 217 border: 1px solid rgb(215, 215, 215); 218 border-radius: 50%; 219 animation: cssload-shadow 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite normal; 220 -o-animation: cssload-shadow 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 221 normal; 222 -ms-animation: cssload-shadow 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 223 normal; 224 -webkit-animation: cssload-shadow 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 225 normal; 226 -moz-animation: cssload-shadow 2.88s cubic-bezier(0.75, 0, 0.5, 1) infinite 227 normal; 228} 229 230@keyframes cssload-square { 231 50% { 232 border-radius: 100%; 233 transform: scale(0.5) rotate(-45deg); 234 } 235 100% { 236 transform: scale(1) rotate(-45deg); 237 } 238} 239 240@-o-keyframes cssload-square { 241 50% { 242 border-radius: 100%; 243 -o-transform: scale(0.5) rotate(-45deg); 244 } 245 100% { 246 -o-transform: scale(1) rotate(-45deg); 247 } 248} 249 250@-ms-keyframes cssload-square { 251 50% { 252 border-radius: 100%; 253 -ms-transform: scale(0.5) rotate(-45deg); 254 } 255 100% { 256 -ms-transform: scale(1) rotate(-45deg); 257 } 258} 259 260@-webkit-keyframes cssload-square { 261 50% { 262 border-radius: 100%; 263 -webkit-transform: scale(0.5) rotate(-45deg); 264 } 265 100% { 266 -webkit-transform: scale(1) rotate(-45deg); 267 } 268} 269 270@-moz-keyframes cssload-square { 271 50% { 272 border-radius: 100%; 273 -moz-transform: scale(0.5) rotate(-45deg); 274 } 275 100% { 276 -moz-transform: scale(1) rotate(-45deg); 277 } 278} 279 280@keyframes cssload-heart { 281 50% { 282 transform: rotate(360deg); 283 } 284 100% { 285 transform: rotate(720deg); 286 } 287} 288 289@-o-keyframes cssload-heart { 290 50% { 291 -o-transform: rotate(360deg); 292 } 293 100% { 294 -o-transform: rotate(720deg); 295 } 296} 297 298@-ms-keyframes cssload-heart { 299 50% { 300 -ms-transform: rotate(360deg); 301 } 302 100% { 303 -ms-transform: rotate(720deg); 304 } 305} 306 307@-webkit-keyframes cssload-heart { 308 50% { 309 -webkit-transform: rotate(360deg); 310 } 311 100% { 312 -webkit-transform: rotate(720deg); 313 } 314} 315 316@-moz-keyframes cssload-heart { 317 50% { 318 -moz-transform: rotate(360deg); 319 } 320 100% { 321 -moz-transform: rotate(720deg); 322 } 323} 324 325@keyframes cssload-heartL { 326 60% { 327 transform: scale(0.4); 328 } 329} 330 331@-o-keyframes cssload-heartL { 332 60% { 333 -o-transform: scale(0.4); 334 } 335} 336 337@-ms-keyframes cssload-heartL { 338 60% { 339 -ms-transform: scale(0.4); 340 } 341} 342 343@-webkit-keyframes cssload-heartL { 344 60% { 345 -webkit-transform: scale(0.4); 346 } 347} 348 349@-moz-keyframes cssload-heartL { 350 60% { 351 -moz-transform: scale(0.4); 352 } 353} 354 355@keyframes cssload-heartR { 356 40% { 357 transform: scale(0.4); 358 } 359} 360 361@-o-keyframes cssload-heartR { 362 40% { 363 -o-transform: scale(0.4); 364 } 365} 366 367@-ms-keyframes cssload-heartR { 368 40% { 369 -ms-transform: scale(0.4); 370 } 371} 372 373@-webkit-keyframes cssload-heartR { 374 40% { 375 -webkit-transform: scale(0.4); 376 } 377} 378 379@-moz-keyframes cssload-heartR { 380 40% { 381 -moz-transform: scale(0.4); 382 } 383} 384 385@keyframes cssload-shadow { 386 50% { 387 transform: scale(0.5); 388 border-color: rgb(228, 228, 228); 389 } 390} 391 392@-o-keyframes cssload-shadow { 393 50% { 394 -o-transform: scale(0.5); 395 border-color: rgb(228, 228, 228); 396 } 397} 398 399@-ms-keyframes cssload-shadow { 400 50% { 401 -ms-transform: scale(0.5); 402 border-color: rgb(228, 228, 228); 403 } 404} 405 406@-webkit-keyframes cssload-shadow { 407 50% { 408 -webkit-transform: scale(0.5); 409 border-color: rgb(228, 228, 228); 410 } 411} 412 413@-moz-keyframes cssload-shadow { 414 50% { 415 -moz-transform: scale(0.5); 416 border-color: rgb(228, 228, 228); 417 } 418}

Javascript Code


1const questionContainer = document.querySelector(".question-container"); 2const resultContainer = document.querySelector(".result-container"); 3const gifResult = document.querySelector(".gif-result"); 4const heartLoader = document.querySelector(".cssload-main"); 5const yesBtn = document.querySelector(".js-yes-btn"); 6const noBtn = document.querySelector(".js-no-btn"); 7 8// /change the postion of no button 9noBtn.addEventListener("mouseover", () => { 10 const newX = Math.floor(Math.random() * questionContainer.offsetWidth); 11 const newY = Math.floor(Math.random() * questionContainer.offsetWidth); 12 13 noBtn.style.left = `${newX}px`; 14 noBtn.style.top = `${newY}px`; 15}); 16 17// yes button functionality 18 19yesBtn.addEventListener("click", () => { 20 questionContainer.style.display = "none"; 21 heartLoader.style.display = "inherit"; 22 23 const timeoutId = setTimeout(() => { 24 heartLoader.style.display = "none"; 25 resultContainer.style.display = "inherit"; 26 gifResult.play(); 27 }, 3000); 28}); 29

🧠 Explanation of the Code


🔹 HTML Structure

Question container shows the video, question, and buttons

Result container stays hidden until the Yes button is clicked

Heart loader is a pure CSS animation shown during the delay

🎨 CSS Styling & Animation


Buttons use soft shadows and scaling for a playful feel

The No button is positioned absolutely to allow free movement

Heart loader is built using:

Circles + square

Rotation, scaling, and shadow animations

⚙️ JavaScript Logic


mouseover on No button randomly changes its position

Clicking Yes:

Hides the question

Shows heart loader

Reveals the result after 3 seconds

✨ Features

Cute Valentine UI 💕

Impossible-to-click “No” button 😈

Pure CSS heart loader animation ❤️

Beginner-friendly JavaScript logic

Love this component?

Explore more components and build amazing UIs.

View All Components