Learn to create stunning Valentine's Day animations using HTML, CSS, and JavaScript. Simple steps for beautiful and interactive love-themed animations!

Table of Contents
Valentine's Day is all about love, and what better way to celebrate than with a custom animation? If you want to add some interactive and beautiful animations to your website or project, this guide is for you! In this blog, we will show you how to create a Valentine's Day animation using HTML, CSS, and JavaScript. You don't need to be a coding expert to follow along; we'll keep things simple and fun!
Prerequisites:
- Basic understanding of HTML, CSS, and JavaScript.
- A text editor (like Visual Studio Code or Notepad++).
- A modern web browser (for testing your animations).
Let’s dive into the steps!
Source Code
Step 1 (HTML Code):
To get started, we will first need to create a basic HTML file. Let me explain the structure and key parts of the code:
1. Document Structure
- The document begins with
<!DOCTYPE html>
, specifying it is an HTML5 document. - The
<html lang="en">
tag sets the language of the page to English.
2. Head Section
- Meta tags: The page uses:
<meta charset="UTF-8">
to specify the character encoding.<meta name="viewport" content="width=device-width, initial-scale=1.0">
for responsiveness, ensuring the page looks good on various devices.<meta http-equiv="X-UA-Compatible" content="ie=edge">
for compatibility with older versions of Internet Explorer.
- Title: Sets the page title as "Happy Valentine :)".
- Links:
- A link to a Google font (
Work Sans
) is included for the text styling. - A
favicon
(a small icon that appears in the browser tab) is set to a heart image. - An external CSS file (
styles.css
) is linked to style the page.
- A link to a Google font (
3. Body Section
- The
<body>
contains severaldiv
elements, each representing different sections of the webpage:div class="container"
: The main container that wraps the whole content.- Sections like
one
,three
,four
,five
, etc.: These contain different messages, elements, and visual components like images, text, and animations.- Personalized Greeting: "Hey xyz, I really like your name btw!" is displayed, with "xyz" being a placeholder for the name.
- Valentine's Day Message: A text box with "Happy Valentine's Day" and interactive elements like "Send".
- Images: Several images of balloons, hearts, smiling faces, and other related icons are used for visual decoration.
- SVG Circles: Several
<svg>
circles are included for animations. - Messages: Various lines with personalized Valentine's messages, such as "You are Special" and "Happy Valentine's Day Gorgeous".
- Final Section (
nine
): Includes a prompt asking the user if they liked the page and a playful message to "come back" or "watch it again".
4. External Scripts
- Babel: A JavaScript compiler that allows the use of modern JavaScript syntax.
- GSAP (GreenSock Animation Platform): A powerful library for animations, used here for adding animation effects.
- External JavaScript file (
script.js
): This file is included for further dynamic behavior and animation control.
Step 2 (CSS Code):
Next, we will create our CSS file. Here’s an explanation of the key parts:
- Global Styles:
html { box-sizing: border-box; }
: Ensures padding and borders are included in the element's total width and height calculations, making layout easier to manage.body { margin: 0; font-family: "Work Sans", sans-serif; }
: Removes default margin and sets the font of the body to "Work Sans" or a fallback sans-serif font.
- Container Styling (
.container
):.container
: A full-screen container (100vh height and 110vh width), centered horizontally (margin: 0 auto
), with hidden overflow. Its visibility is initially hidden..container div.six
: This class targets thesix
div inside the container, setting its position slightly down (top: 10vh
) and giving it az-index
for layering control.
- Positioning of Child Divs:
.container div.seven, .container div.eight
: These divs are set to be full-screen fixed elements (width: 100vw; height: 100vh
), staying fixed at the top of the viewport..container > div
: All child divs in the container are absolutely positioned with atop
of20vh
(20% from the top of the viewport).
- Text Styles:
- Classes like
.one
,.two
,.three
,.five
adjust font size, weight, and other styles. For example:.one
has a large font size (4.5rem) for a prominent element..two
uses a lighter font weight..five p
has a large font size and absolute positioning.
- Classes like
- Interactive and Visual Elements:
.four .text-box
: Creates a styled box with a border, padding, and a button (.fake-btn
) inside it, positioned absolutely to the bottom-right corner of the text box..six img
: Adjusts image size to be responsive with amax-width: 45%
for images within thesix
section..baloons img
: Positions images of balloons at various locations within the.baloons
div using absolute positioning.
- SVGs for Animation:
.eight svg
: Defines multiple SVGs that appear as balloons or floating elements. They are absolutely positioned with varying fill colors and visibility set to hidden.
- Text Styling for Wishes:
.wish-hbd
: Increases font size for birthday or wish messages, with specific styles for headings inside it (.wish h5
).
- Replay Button:
#replay
: This ID is given a higherz-index
for layering above other elements and is made clickable withcursor: pointer
.
- Responsive Design (Media Queries):
- Media queries adjust the layout for various screen sizes:
max-height: 1000px
: Adjusts the position of.hat
based on screen height.max-width: 500px
: Shrinks the container and text box widths and modifies font sizes and element positioning for smaller screens (e.g., mobile devices).
- Media queries adjust the layout for various screen sizes:
html {
box-sizing: border-box;
}
body {
margin: 0;
font-family: "Work Sans", sans-serif;
}
.container {
height: 100vh;
width: 110vh;
margin: 0 auto;
text-align: center;
visibility: hidden;
position: relative;
overflow: hidden;
}
.container div.six {
top: 10vh;
z-index: 1;
}
.container div.seven,
.container div.eight {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
}
.container > div {
position: absolute;
left: 0;
right: 0;
top: 20vh;
}
.one {
font-size: 4.5rem;
}
.one > img {
vertical-align: middle;
margin-bottom: 10px;
max-width: 100%;
height: auto;
}
.two {
font-size: 1.2rem;
font-weight: lighter;
}
.three {
font-size: 3rem;
}
.four .text-box {
width: 600px;
margin: 0 auto;
border: 3px solid #aaa;
border-radius: 5px;
padding: 10px;
position: relative;
}
.text-box p {
margin: 0;
text-align: left;
}
.text-box span {
visibility: hidden;
}
.text-box .fake-btn {
position: absolute;
right: 5px;
bottom: 5px;
color: #fff;
background-color: rgb(21, 161, 237);
padding: 5px 8px;
border-radius: 3px;
}
.five p {
font-size: 2rem;
position: absolute;
left: 0;
right: 0;
}
.idea-3 strong {
padding: 3px 5px;
border-radius: 3px;
display: inline-block;
}
.five .idea-5 {
font-size: 4rem;
}
.idea-5 span,
.idea-6 span,
.wish-hbd span {
display: inline-block;
}
.idea-6 span {
font-size: 15rem;
}
.six {
position: relative;
}
.six img {
display: inline-block;
max-width: 45%;
height: auto;
}
.six .hat {
position: absolute;
width: 80px;
top: -35px;
left: 41.5%;
/* transform: scale(0.1); */
}
.baloons img {
display: inline-block;
position: absolute;
width: 200px;
}
.baloons img:nth-child(even) {
left: 10%;
}
.baloons img:nth-child(odd) {
right: 10%;
}
.baloons img:nth-child(3n + 0) {
left: 30%;
}
.eight svg {
width: 25px;
position: absolute;
top: 0;
left: 0;
visibility: hidden;
z-index: -1;
}
.eight svg:nth-child(1) {
top: 7vh;
left: 5vw;
fill: #bd6ecf;
}
.eight svg:nth-child(2) {
top: 23vh;
left: 35vw;
fill: #7dd175;
}
.eight svg:nth-child(3) {
top: 33vh;
left: 23vw;
fill: #349d8b;
}
.eight svg:nth-child(4) {
top: 43vh;
left: 57vw;
fill: #347a9d;
}
.eight svg:nth-child(5) {
top: 68vh;
left: 7vw;
fill: #c66053;
}
.eight svg:nth-child(6) {
top: 42vh;
left: 77vw;
fill: #bfaa40;
}
.eight svg:nth-child(7) {
top: 68vh;
left: 83vw;
fill: #e3bae8;
}
.eight svg:nth-child(8) {
top: 86vh;
left: 37vw;
fill: #8762cb;
}
.eight svg:nth-child(9) {
top: 94vh;
left: 87vw;
fill: #9a90da;
}
.wish-hbd {
font-size: 3em;
margin: 0;
/* text-transform: uppercase; */
}
.wish h5 {
font-weight: lighter;
font-size: 2rem;
margin: 10px 0 0;
}
.nine p {
font-size: 2rem;
font-weight: lighter;
}
#replay {
z-index: 3;
cursor: pointer;
}
/* Media Queries */
@media screen and (max-height: 1000px) {
.six .hat {
left: 40%;
}
}
@media screen and (max-height: 800px) {
.six .hat {
left: 37%;
}
}
@media screen and (max-height: 700px) {
.six .hat {
left: 32%;
}
}
@media screen and (max-height: 850px) and (max-width: 450px) {
.six .hat {
left: 32%;
}
}
@media screen and (max-width: 500px) {
.container {
width: 90%;
}
.four .text-box {
width: 90%;
}
.text-box .fake-btn {
right: 5px;
bottom: -38px;
}
.idea-5 span {
display: block;
}
.idea-6 span {
font-size: 10rem;
}
.six .hat {
width: 50px;
top: -20px;
}
.wish-hbd {
font-size: 2.3em;
}
.wish h5 {
font-size: 1.4rem;
}
.nine p {
font-size: 1.5rem;
font-weight: lighter;
}
}
Step 3 (JavaScript Code):
Finally, we need to create a function in JavaScript. This JavaScript code creates a detailed animation timeline using the GreenSock Animation Platform (GSAP). Here's a breakdown of what the code does:
Key Components:
- Splitting text into spans:
- The
textBoxChars
andhbd
elements have their text split into individual<span>
elements so that each character can be animated separately. - The
innerHTML
of these elements is modified by splitting the text into an array of characters, then joining them back with the<span>
tags surrounding each character.
- The
- Setting up animation properties:
ideaTextTrans
andideaTextTransLeave
are objects defining the initial and final states of the text elements during the animation. These states include properties like opacity, vertical position (y
), rotation, and skew.
- Animation Timeline (using GSAP's
TimelineMax
):tl
(timeline): This is the main GSAP timeline object where various animations are defined step by step. Each animation (like fading in, moving, scaling, etc.) is chained together, with some elements starting after a certain delay using+=
for timing..to()
and.from()
methods are used to animate the elements to/from certain properties..staggerTo()
and.staggerFrom()
animate multiple elements sequentially, applying a delay between each animation.- The
stagger
methods create animations where each element in a group animates one after the other with a small time gap, making the animation appear more dynamic.
- Specific animations:
- Text animations: Characters in the
.hbd-chatbox
and.wish-hbd
elements are animated one after another with effects like rotation, scaling, and color changes. - Image animations: Elements like
.baloons img
and.girl-dp
are animated with scaling and moving along the y-axis. .wish-hbd span
elements: These elements undergo multiple transformations, including opacity changes, rotations, scaling, and color shifts.
- Text animations: Characters in the
- Replay Button:
- A replay button (
#replay
) is linked to restart the entire animation timeline when clicked. Thetl.restart()
method is triggered by the button click.
- A replay button (
- Additional animations:
- Other elements, like
.wish h5
,.eight svg
,.nine p
, and.last-smile
, are animated with various effects like scaling, opacity changes, and rotation.
- Other elements, like
// Animation Timeline
const animationTimeline = () => {
// Spit chars that needs to be animated individually
const textBoxChars = document.getElementsByClassName("hbd-chatbox")[0];
const hbd = document.getElementsByClassName("wish-hbd")[0];
textBoxChars.innerHTML = `<span>${textBoxChars.innerHTML
.split("")
.join("</span><span>")}</span`;
hbd.innerHTML = `<span>${hbd.innerHTML
.split("")
.join("</span><span>")}</span`;
const ideaTextTrans = {
opacity: 0,
y: -20,
rotationX: 5,
skewX: "15deg",
};
const ideaTextTransLeave = {
opacity: 0,
y: 20,
rotationY: 5,
skewX: "-15deg",
};
const tl = new TimelineMax();
tl.to(".container", 0.1, {
visibility: "visible",
})
.from(".one", 0.7, {
opacity: 0,
y: 10,
})
.from(".two", 0.4, {
opacity: 0,
y: 10,
})
.to(
".one",
0.7,
{
opacity: 0,
y: 10,
},
"+=2.5"
)
.to(
".two",
0.7,
{
opacity: 0,
y: 10,
},
"-=1"
)
.from(".three", 0.7, {
opacity: 0,
y: 10,
// scale: 0.7
})
.to(
".three",
0.7,
{
opacity: 0,
y: 10,
},
"+=2"
)
.from(".four", 0.7, {
scale: 0.2,
opacity: 0,
})
.from(".fake-btn", 0.3, {
scale: 0.2,
opacity: 0,
})
.staggerTo(
".hbd-chatbox span",
0.5,
{
visibility: "visible",
},
0.05
)
.to(".fake-btn", 0.1, {
backgroundColor: "rgb(127, 206, 248)",
})
.to(
".four",
0.5,
{
scale: 0.2,
opacity: 0,
y: -150,
},
"+=0.7"
)
.from(".idea-1", 0.7, ideaTextTrans)
.to(".idea-1", 0.7, ideaTextTransLeave, "+=1.5")
.from(".idea-2", 0.7, ideaTextTrans)
.to(".idea-2", 0.7, ideaTextTransLeave, "+=1.5")
.from(".idea-3", 0.7, ideaTextTrans)
.to(".idea-3 strong", 0.5, {
scale: 1.2,
x: 10,
backgroundColor: "rgb(21, 161, 237)",
color: "#fff",
})
.to(".idea-3", 0.7, ideaTextTransLeave, "+=1.5")
.from(".idea-4", 0.7, ideaTextTrans)
.to(".idea-4", 0.7, ideaTextTransLeave, "+=1.5")
.from(
".idea-5",
0.7,
{
rotationX: 15,
rotationZ: -10,
skewY: "-5deg",
y: 50,
z: 10,
opacity: 0,
},
"+=0.5"
)
.to(
".idea-5 span",
0.7,
{
rotation: 90,
x: 8,
},
"+=0.4"
)
.to(
".idea-5",
0.7,
{
scale: 0.2,
opacity: 0,
},
"+=2"
)
.staggerFrom(
".idea-6 span",
0.8,
{
scale: 3,
opacity: 0,
rotation: 15,
ease: Expo.easeOut,
},
0.2
)
.staggerTo(
".idea-6 span",
0.8,
{
scale: 3,
opacity: 0,
rotation: -15,
ease: Expo.easeOut,
},
0.2,
"+=1"
)
.staggerFromTo(
".baloons img",
2.5,
{
opacity: 0.9,
y: 1400,
},
{
opacity: 1,
y: -1000,
},
0.2
)
.from(
".girl-dp",
0.5,
{
scale: 3.5,
opacity: 0,
x: 25,
y: -25,
rotationZ: -45,
},
"-=2"
)
.from(".hat", 0.5, {
x: -100,
y: 350,
rotation: -180,
opacity: 0,
})
.staggerFrom(
".wish-hbd span",
0.7,
{
opacity: 0,
y: -50,
// scale: 0.3,
rotation: 150,
skewX: "30deg",
ease: Elastic.easeOut.config(1, 0.5),
},
0.1
)
.staggerFromTo(
".wish-hbd span",
0.7,
{
scale: 1.4,
rotationY: 150,
},
{
scale: 1,
rotationY: 0,
color: "#ff69b4",
ease: Expo.easeOut,
},
0.1,
"party"
)
.from(
".wish h5",
0.5,
{
opacity: 0,
y: 10,
skewX: "-15deg",
},
"party"
)
.staggerTo(
".eight svg",
1.5,
{
visibility: "visible",
opacity: 0,
scale: 80,
repeat: 3,
repeatDelay: 1.4,
},
0.3
)
.to(".six", 0.5, {
opacity: 0,
y: 30,
zIndex: "-1",
})
.staggerFrom(".nine p", 1, ideaTextTrans, 1.2)
.to(
".last-smile",
0.5,
{
rotation: 90,
},
"+=1"
);
// tl.seek("currentStep");
// tl.timeScale(2);
// Restart Animation on click
const replyBtn = document.getElementById("replay");
replyBtn.addEventListener("click", () => {
tl.restart();
});
};
animationTimeline();
Final Output:

Conclusion:
In this tutorial, we walked through creating a Valentine's Day animation using HTML, CSS, and JavaScript. You can easily add charming love animations to your websites by following simple steps. These animations will bring joy to anyone who visits your page, making them perfect for the holiday season.
Don’t hesitate to experiment with different animations and effects to make your project even more exciting!
If you found this blog helpful, don’t forget to share it!
Created by Afiur Rahman Fahim
That’s a wrap!
I hope you enjoyed this post. Now, with these examples, you can create your own amazing page.
Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee
And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!
Thanks!
Faraz 😊