Product Landing Page with HTML, CSS, and JavaScript

Faraz

By Faraz -

Master the art of responsive web design. Build a product landing page with HTML, CSS, and dynamic animations using GSAP and JavaScript.


Product Landing Page with HTML, CSS, and JavaScript.jpg

Table of Contents

  1. Project Introduction
  2. HTML Code
  3. CSS Code
  4. JavaScript Code
  5. Preview
  6. Conclusion

In today's fast-paced digital landscape, the importance of having an enticing and highly functional online presence cannot be overstated. For businesses, both big and small, a well-crafted product landing page serves as a virtual storefront, a digital welcome mat that can make or break a potential customer's decision to engage with your offerings.

But here's the catch: the modern user isn't confined to a single device or screen size. They browse your website on smartphones, tablets, laptops, and desktops, and they expect a seamless and visually appealing experience across them all. This is where the concept of a "Responsive Product Landing Page" comes into play.

In this comprehensive guide, we'll take you on a journey through the art and science of creating a responsive product landing page. We'll delve into the intricacies of HTML, CSS, and JavaScript, and explore the captivating world of GSAP animations. By the end of this journey, you'll be equipped with the knowledge and skills needed to craft landing pages that not only adapt effortlessly to different screen sizes but also engage and convert your visitors effectively.

So, whether you're a seasoned web developer looking to enhance your skills or a newcomer eager to make a mark in the digital realm, join us as we unlock the secrets to building a responsive product landing page that leaves a lasting impression. Let's get started on the path to creating web experiences that truly stand out in the crowd.

Code by: Gerrard

Source Code

Step 1 (HTML Code):

To get started, we will first need to create a basic HTML file. In this file, we will include the main structure for our product page.

After creating the files just paste the following codes into your file. Make sure to save your HTML document with a .html extension, so that it can be properly viewed in a web browser.

Let's break down the code step by step:

1. <!DOCTYPE html>: This is the document type declaration and specifies that this is an HTML5 document.

2. <html lang="en">: This is the opening tag for the HTML document. The lang attribute is set to "en," indicating that the page is written in English.

3. <head>: This section contains metadata and links to external resources. It doesn't display any content on the webpage itself.

  • <title>: Sets the title of the webpage, which typically appears in the browser's title bar or tab.
  • <meta charset="UTF-8">: Specifies the character encoding for the document as UTF-8, which is a standard encoding for handling various characters and symbols.
  • <meta name="viewport" content="width=device-width">: Configures the viewport to adapt to the width of the device's screen, making the page responsive on different devices.
  • <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/remixicon/3.5.0/remixicon.css">: Links to an external stylesheet (CSS) file from the Remixicon library. This library provides icons for the webpage.
  • <link rel="stylesheet" href="styles.css">: Links to another external CSS file named "styles.css," which contains additional styles for the webpage.

4. <body>: This is the main content area of the webpage where visible content is displayed.

5. <main>: Defines the main content section of the webpage.

  • Inside the <main>, there are several sections that make up the webpage's content, each with its unique ID and content.
  • <header id="header">: Represents the header section of the webpage, which typically contains navigation links and other header content.
  • <span id="logo-container">: Contains a logo image represented as an SVG (Scalable Vector Graphics) element.
  • <nav id="navigation-options-container">: Contains navigation links represented as anchor (<a>) elements.
  • <span id="cart">: Represents a shopping cart icon with a dollar amount.
  • <button id="menu-button">: Represents a menu button icon.

6. <section id="headline-container">: Contains a headline, subtext, and a call-to-action button.

7. <section id="bottle-images-and-info-container">: Contains information about different product bottles, including images, names, prices, and buttons for more information.

8. <section id="collection-container">: Represents a section about a bottle collection, including an image, heading, text, and a "Read More" button.

9. <script>: This section includes references to JavaScript files that will provide interactivity and functionality to the webpage.

  • <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>: Links to the GreenSock Animation Platform (GSAP) library, which is used for animation effects.
  • <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/CSSRulePlugin.min.js"></script>: Links to the GSAP CSSRulePlugin, which extends GSAP's capabilities for working with CSS rules.
  • <script src="script.js"></script>: Links to an external JavaScript file named "script.js," which contains custom JavaScript code for the webpage's functionality.

This is the basic structure of our product landing page using HTML, and now we can move on to styling it using CSS.

Step 2 (CSS Code):

Once the basic HTML structure of the product landing page is in place, the next step is to add styling to the landing page using CSS.

Next, we will create our CSS file. In this file, we will use some basic CSS rules to style our product page.

Let's break down the code section by section to understand its purpose:

@import url("..."); This line imports fonts from Google Fonts. It includes two font families, "Big Shoulders Display" with various weights and "Poppins" with various weights.

1. :root { ... }: This section defines global variables using CSS custom properties (variables) within the :root pseudo-class. These variables are used to define colors, font sizes, and other global styles that can be reused throughout the stylesheet.

2. html { ... }: Styles are applied to the html element. It sets some custom properties related to button background colors, opacity, and general styling for the entire HTML document.

3. *, ::after, ::before { ... }: These selectors apply styles to all elements (*), pseudo-elements ::after, and ::before. The styles include resetting margin, padding, and other properties to create a consistent layout.

4. button, input[type="submit"], input[type="reset"] { ... }: This section applies styles to buttons and input elements of specific types (submit and reset). It removes background, borders, padding, and other default styles to make them look consistent and more like text.

5. a { ... }: This applies styles to anchor (<a>) elements. It sets the color to blue and removes text decoration (underlining) for links.

6. body { ... }: Styles for the body element are defined. It sets the background color and specifies a flexbox layout for the body content.

7. main { ... }: Styles for the main element are defined. It sets its position to relative, height and width to 100%, and hides overflow. This seems to be setting up the main content area of the page.

8. Selectors with IDs like #header, #logo-container, #navigation-options-container-desktop, etc.: These selectors define styles for specific elements with IDs. They set up the layout and appearance of various sections of the web page, including the header, logo container, navigation options, and more.

9. Media Queries (@media ... { ... }): These are CSS rules that apply only when certain conditions, like screen width, are met. They define responsive styles for different screen sizes, adjusting the layout and appearance of elements as the screen size changes.

This will give our product landing page an upgraded presentation. Create a CSS file with the name of styles.css and paste the given codes into your CSS file. Remember that you must create a file with the .css extension.

@import url("https://fonts.googleapis.com/css2?family=Big+Shoulders+Display:wght@100;200;300;400;500&family=Poppins:wght@300;400;500;600;700;800&display=swap");
:root {
  font-size: 16px;
  font-family: "Poppins";
  --lavender: hsl(266, 100%, 90%);
  --juniper: hsl(188, 100%, 88%);
  --spirulina: hsl(130, 100%, 88%);
  --pink-lemonade: hsl(4, 100%, 85%);
  --blueberry: hsl(240, 38%, 82%);
  --color-2: hsl(0, 0%, 95%);
  --color-3: hsl(0, 0%, 5%);
  --color-3a: hsla(0, 0%, 5%, 0.3);
  --color-4: hsl(0, 0%, 15%);

  --border-width: 1px;

  --image-info-width: 60%;
  --direction-buttons-width: 6rem;
}

html {
  /* Next And Prev Button Background colors Variables */
  --nextBackgroundColor: var(--spirulina);
  --prevBackgroundColor: var(--blueberry);
  --opacity: 1;
  height: 100%;
  width: 100%;
}

*,
::after,
::before {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

button,
input[type="submit"],
input[type="reset"] {
  background: none;
  color: inherit;
  border: none;
  padding: 0;
  font: inherit;
  cursor: pointer;
  outline: inherit;
}

a {
  color: blue;
  text-decoration: none; /* no underline */
}

body {
  position: relative;
  background-color: var(--spirulina);
  display: flex;
  flex-direction: column;
  align-self: center;
}

main {
  position: relative;
  height: 100%;
  width: 100%;
  overflow: hidden;
}

#background-color-popup {
  position: absolute;
  width: 5rem;
  aspect-ratio: 1/ 1;
  border-radius: 50%;
  scale: 1;
  left: 0;
  top: 0;
  z-index: -1;
}

#header {
  /* position: fixed; */
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  border-bottom: var(--border-width) solid var(--color-3a);
  width: 100%;
  max-height: 6rem;
  z-index: 99;
}

#logo-container {
  width: 15%;
  max-width: 5rem;
  display: flex;
  padding: 1rem;
  border-right: 1px solid var(--color-3a);
}

#logo {
  width: 100%;
  height: auto;
}

#navigation-options-container-desktop {
  display: none;
}

#navigation-options-container {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: center;
  background-color: rgba(255, 255, 255, 0.17);
  gap: 1.5rem;
  top: 0rem;
  width: 100%;
  border-bottom: 1px solid var(--color-3a);
  padding: 1rem;
  font-weight: 500;
  z-index: 1;
  backdrop-filter: blur(10px);
  clip-path: polygon(0 0, 100% 0%, 100% 0, 0 0);
}

.nav-options {
  position: relative;
  color: var(--color-3);
  font-weight: 500;
  padding-bottom: 0.2rem;
  color: black;
}

.nav-options::before {
  position: absolute;
  content: "";
  bottom: 0;
  left: 0;
  width: 100%;
  height: 0.2rem;
  background-color: var(--color-3);
  transform-origin: right;
  scale: 0 1;
  transition: scale 0.2s ease-out;
}

.nav-options:hover:before {
  transform-origin: left;
  scale: 1 1;
  transition: scale 0.2s ease-out;
}

.nav #cart {
  display: flex;
  align-items: center;
  width: 4.5rem;
  justify-content: space-between;
  color: var(--color-3);
  font-weight: 500;
}

#menu-button {
  width: 2rem;
  display: grid;
  place-items: center;
  aspect-ratio: 1 / 1;
  margin-right: 0.75rem;
}

#menu-icon {
  font-size: 1.5rem;
  transition: rotate 0.3s ease;
}

#menu-icon:hover {
  rotate: 180deg;
}

#headline-container {
  padding: 2rem 1rem 2rem 1rem;
  width: 100%;
  height: 100%;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  border-bottom: 1px solid black;
}

#title {
  font-size: clamp(2rem, 5vw, 3rem);
}

#subtext {
  font-size: clamp(0.8rem, 2.5vw, 1rem);
}

#call-to-action {
  position: relative;
  align-self: center;
  padding: 1rem 3rem;
  border-radius: 50%;
  border: 1px solid;
  display: grid;
  place-items: center;
  transition: top .3s ease-out;
}

#call-to-action:before {
  content: "";
  position: absolute;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  border: 1px solid black;
  top: -0.3rem;
  left: 0;
  z-index: -1;
  border-bottom: none;
  border-left: none;
  border-right: none;
  transition: top .3s ease-out;
}

#call-to-action:hover {
  top: -0.3rem;
}

#call-to-action:hover:before {
  top: 0;
}

#bottle-images-and-info-container {
  position: relative;
  display: flex;

  width: 100%;
  max-width: 30rem;
  margin: 0 auto;
  justify-content: center;
  overflow: hidden;
  z-index: 0;
  border-left: var(--border-width) solid black;
  border-right: var(--border-width) solid black;
}

.image-and-info {
  flex: none;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  width: var(--image-info-width);
  max-width: 25rem;
  padding: 2rem 1rem;
  row-gap: 0.5rem;
  translate: 0 0;
  z-index: -1;
}

.image-and-info img {
  width: 80%;
  grid-column: 1/ 4;
  padding-bottom: 0.5rem;
  justify-self: center;

  padding: 0 1rem;
}

.image-and-info h3 {
  width: 100%;
  grid-column: 1 / 4;
  text-align: center;
  grid-row: 2;
  border-bottom: var(--border-width) solid var(--color-3);
  padding-bottom: 0.5rem;
  font-size: 1rem;
}

.price {
  grid-row: 3;
  grid-column: 1;
  align-self: center;
  justify-self: start;
}

.more-info-button {
  grid-column: 3;
  justify-self: end;
  align-self: center;
  width: 2rem;
  display: grid;
  place-items: center;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  border: var(--border-width) solid black;
  transition: rotate 0.5s ease;
}

.more-info-button:hover {
  rotate: 180deg;
}

#direction-button-container {
  position: absolute;
  width: 60%;
  height: 100%;
  max-width: 25rem;
  z-index: 1;
  background-color: transparent;
  pointer-events: none;
}

.direction-buttons {
  position: absolute;
  width: var(--direction-buttons-width);
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  border: 2px solid var(--color-3);
  color: var(--color-3);
  z-index: 1;
  overflow: hidden;
  pointer-events: auto;
}

/* Prev and next background color to cover border*/

#background-color-next,
#background-color-prev {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  background-color: var(--pink-lemonade-color);
  z-index: -1;
}

#next {
  right: 0%;
  top: 50%;
  transform: translate(50%, -50%);
}

#prev {
  left: 0%;
  top: 50%;
  transform: translate(-50%, -50%);
}

/* Check gsap for the background color */
#next::before,
#prev::before {
  content: "";
  position: absolute;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  top: 0;
  left: 0;
  z-index: -1;
  opacity: 0;
  transition: opacity 0.3s ease;
}

#next::before {
  background-color: var(--nextBackgroundColor);
}

#prev::before {
  background-color: var(--prevBackgroundColor);
}

#next:hover:before,
#prev:hover:before {
  opacity: var(--opacity);
}

/* top prevent borders from crosslaping the prev and next button*/
.box {
  position: absolute;
  width: 100%;
  height: calc(50% - (var(--direction-buttons-width) / 2) - 5px);
  border: var(--border-width) solid black;
  border-top: 0px;
  border-bottom: 0px;
  z-index: -1;
}

#box-top {
  top: 0;
  left: 50%;
  translate: -50% 0;
}

#box-bottom {
  bottom: 0;
  left: 50%;
  translate: -50% 0;
}

/* End */

#collection-container {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 3fr 2fr;
  grid-template-rows: 80% 1fr 1fr;
  width: 100%;
  border-top: var(--border-width) solid black;
  padding: 2rem 1rem 2rem 1rem;
  row-gap: 0.5rem;
  column-gap: 1rem;
}

#bottle-collection-image {
  grid-column: 1 / 4;
  grid-row: 1;
  width: 100%;
  max-width: 20rem;
  justify-self: center;
}

#collection-heading {
  grid-column: 1/ 3;
  grid-row: 2;
  font-size: 1rem;
  align-self: end;
}

#collection-text {
  grid-column: 1 / 3;
  grid-row: 3;
  font-size: 0.8rem;
}

#read-more-button {
  grid-column: 3;
  grid-row: 2 / 4;
  width: calc(100% - 2.5rem);
  max-width: 7rem;
  min-width: 5rem;
  aspect-ratio: 1 / 1;
  border: var(--border-width) dashed black;
  border-radius: 50%;
  font-size: 0.8rem;

  rotate: -30deg;
  justify-self: flex-end;
  align-self: end;
  transition: rotate 0.3s ease-out;
}

#read-more-button:hover {
  rotate: 0deg;
}

@media only screen and (min-width: 600px) {
  #collection-container {
    grid-template-columns: 25% 50% 25%;
    grid-template-rows: 50% 50%;
    padding: 2rem 1rem 2rem 1rem;
    row-gap: 0.5rem;
    column-gap: 1rem;
  }

  #bottle-collection-image {
    grid-column: 1;
    grid-row: 1 / 3;
    max-width: 10rem;
  }

  #collection-heading {
    grid-column: 2/3;
    grid-row: 1;
    font-size: 1rem;
    align-self: center;
  }

  #collection-text {
    grid-column: 2 / 3;
    grid-row: 2;
    font-size: 0.8rem;
  }

  #read-more-button {
    grid-column: 3;
    grid-row: 1 / 3;
    place-self: center;
    justify-self: unset;
    align-self: unset;
  }
}

@media (min-width: 53.125rem) {
  main {
    height: 100%;
    display: grid;
    grid-template-columns: 60% 40%;
    grid-template-rows: auto auto auto;
  }

  #header {
    grid-column: 1 / 3;
  }

  #navigation-options-container {
    position: initial;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-evenly;
    gap: 1.5rem;
    top: 0rem;
    width: 100%;
    height: 100%;
    border-bottom: none;
    padding: 0 1rem;
    color: var(--color-3);
    font-weight: 500;
    z-index: 1;
    clip-path: inset(0 0 0 0);
    background-color: unset;
    backdrop-filter: unset;
  }

  #menu-button {
    display: none;
  }

  #headline-container {
    grid-column: 1;
    grid-row: 2 / 3;
    align-self: center;
    padding: 4rem;
    text-align: left;
    margin: none;
    border-bottom: none;
    width: 100%;

    border-right: var(--border-width) solid black;
  }

  #call-to-action {
    align-self: start;
  }

  #bottle-images-and-info-container {
    grid-column: 2;
    grid-row: 2 / 4;
    width: 100%;
    min-width: 20rem;
    max-width: 25rem;
    border: none;
  }

  #box-top {
    height: calc(25% - (var(--direction-buttons-width) / 2) - 5px);
    top: 0;
    left: 50%;
    translate: -50% 0;
  }

  #box-bottom {
    height: calc(75% - (var(--direction-buttons-width) / 2) - 5px);
    bottom: 0;
    left: 50%;
    translate: -50% 0;
  }

  #next {
    right: 0%;
    top: 25%;
    transform: translate(50%, -50%);
  }

  #prev {
    left: 0%;
    top: 25%;
    transform: translate(-50%, -50%);
  }

  #collection-container {
    grid-template-columns: 30% 40% auto;
    grid-column: 1 / 2;
    grid-row: 3;
    height: 100%;
    border-right: var(--border-width) solid black;
  }

  #bottle-collection-image {
    align-self: flex-end;
  }

  #collection-heading {
    align-self: flex-end;
  }

  #read-more-button {
    justify-self: start;
    align-self: center;
  }
}

@media (min-width: 60.625rem) {
  main {
    height: 100%;
    display: grid;
    grid-template-columns: auto 25rem;
    grid-template-rows: auto auto auto;
  }

  #navigation-options-container {
    justify-content: flex-end;
    gap: 4rem;
    top: 0rem;
    width: 100%;
  }

  #headline-container {
    grid-column: 1;
    grid-row: 2 / 3;
    align-self: center;
    padding: 4rem 6rem;
    text-align: left;
    margin: none;
    border-bottom: none;
    width: 100%;

    border-right: var(--border-width) solid black;
  }

  #title {
    font-size: clamp(2rem, 4vw, 4rem);
    font-weight: 600;
  }

  #collection-container {
    grid-template-columns: 20% 40% auto;
  }

  #read-more-button {
    margin-left: 4rem;
  }
} 

Step 3 (JavaScript Code):

Finally, we need to create a function in JavaScript. Let's break down the code section by section:

1. Get CSS Variables: The code starts by getting the computed styles of the document's root element (document.documentElement). These computed styles include CSS custom properties (variables) that are defined in the site's CSS.

2. Element Selection: Several HTML elements are selected using document.getElementById. These elements include the header, navigation container, menu button, direction buttons (left and right), and a background color popup, among others. The code also retrieves the dimensions and positions of some of these elements using getBoundingClientRect().

3. Background Color Management: The code manages the background color of certain elements. It stores the background color of the current, previous, and next elements, and it sets these colors using CSS custom properties.

4. Image Divs and Section: It selects a section containing image divs and clones the first two divs to the end of this section. This relates to a carousel-like image display.

5. Set Background Color List: A function, setbackgroundColorList(), populates an array, backgroundColorList, with the background colors of specific image divs. It calculates the middle bottle's position and extracts the background colors from the corresponding divs.

6. GSAP CSS Set Styles: Functions like setBackgroundPopupPosition, gsapSetBackgroundColor, and gsapSetNextAndPrevBackgroundColor use the GreenSock Animation Platform (GSAP) to set various CSS styles and animations for elements, including the background color popup and button hover effects.

7. GSAP Animations: This section defines animations using GSAP's timeline (tl) to control transitions and transformations of elements. These animations are used to create smooth and visually appealing transitions when interacting with the interface.

8. Next and Previous Item Functions: nextItem and prevItem functions handle the logic for moving between images, specifically when the right and left buttons are clicked. They clone and remove image elements to create the appearance of moving through a set of images.

9. Event Listeners: Event listeners are set up for various elements and events, such as button clicks, window load, and window resize. These listeners trigger the defined functions when the corresponding events occur.

10. Set Initial Positions: A function, setInitialPositions, sets the initial positions of certain elements, related to the display of images.

Create a JavaScript file with the name script.js and paste the given codes into your JavaScript file and make sure it's linked properly to your HTML document so that the scripts are executed on the page. Remember, you’ve to create a file with .js extension.

// get CSS Variables
const styles = getComputedStyle(document.documentElement);


// header
const header = document.getElementById("header");
let headerRect = header.getBoundingClientRect();

//Navigation container
const navigationContainer = document.getElementById(
  "navigation-options-container"
);
let navigationContainerRect = navigationContainer.getBoundingClientRect();
let navigationContainerHeight = navigationContainerRect.height;

// Buttons

// Menu Button
const menuButton = document.getElementById("menu-button");
let isMenuDown = false;

// Direction Buttons
const leftButton = document.getElementById("prev");
const rightButton = document.getElementById("next");

let leftButtonClicked = false;
let rightButtonClicked = false;

let leftButtonRect = leftButton.getBoundingClientRect();
let leftButtonCenter = (leftButtonRect.left + leftButtonRect.right) / 2;

let rightButtonRect = rightButton.getBoundingClientRect();
let rightButtonCenter = (rightButton.left + rightButton.right) / 2;

let buttonWidth = rightButtonRect.width;

let imageAndInfoDiv = document.querySelectorAll(".image-and-info"); // helps to get the left center and right bottle colors
// Buttons End

// Background Color
const backgroundPopup = document.getElementById("background-color-popup");

let backgroundColorPopupRect = backgroundPopup.getBoundingClientRect();
let BackgroundColorRectCenter =
  (backgroundColorPopupRect.left + backgroundColorPopupRect.right) / 2;
let backgroundPopupPositionX = rightButton.left;
let backgroundPopupPositionY = rightButton.top + window.pageYOffset;

let backgroundColorList = [];

let currentBackgroundColor = null;
let gsapSetBackgroundColorStyle;

let prevBackgroundColor = null;
let gsapSetprevBackgroundColorStyle;

let nextBackgroundColor = null;
let gsapSetnextBackgroundColorStyle;

// Location of where the circle will popup
let popupCirclePosX = null;
let popupCirclePosY = null;

// Background Color Ends

// ImageDivs and section
let imageContainersSection = document.getElementById(
  "bottle-images-and-info-container"
);
let imageDivs = document.querySelectorAll(".image-and-info");
const imageDivsCount = imageDivs.length;

// appending the first two divs to the end
let clonefirstImage = imageDivs[0].cloneNode(true);
imageContainersSection.append(clonefirstImage);
let clonelastImage = imageDivs[1].cloneNode(true);
imageContainersSection.append(clonelastImage);

function setbackgroundColorList() {
  // background color popup for left (index 0) right(index 2) and current (index 1)
  backgroundColorList = [];
  let getMiddleBottlePositon = Math.ceil((imageDivsCount + 2) / 2);

  imageAndInfoDiv = document.querySelectorAll(".image-and-info");
  for (
    let color = getMiddleBottlePositon - 2;
    color < getMiddleBottlePositon + 1;
    color++
  ) {
    backgroundColorList.push(imageAndInfoDiv[color].getAttribute("data-color"));
  }
}

// GSAP CSS Set Styles

// Is the popup coming from prev button or next button?
function setBackgroundPopupPosition() {
  gsap.set("#background-color-popup", {
    transform: `translate(${popupCirclePosX}px, ${popupCirclePosY}px)`,
  });
}

// Sets the background color Of the current bottle to the popup
function gsapSetBackgroundColor() {
  gsapSetBackgroundColorStyle = styles.getPropertyValue(
    `--${currentBackgroundColor}`
  );

  // background color for the popup when it increases size
  gsap.set("#background-color-popup", {
    backgroundColor: gsapSetBackgroundColorStyle,
  });
}

function gsapSetNextAndPrevBackgroundColor() {
  // Refer to CSS file for better understanding
  prevBackgroundColor = backgroundColorList[0];
  nextBackgroundColor = backgroundColorList[2];

  // Sets the previous bottle background color on the prev button when hovered
  gsap.set("html", {
    "--opacity": 0,
  });

  gsap.to("html", {
    "--prevBackgroundColor": `var(--${prevBackgroundColor})`,
    "--opacity": 1,

    duration: 0.1,
    delay: 1,
  });

  // Sets the next bottle background color on the next button when hovered
  gsap.to("html", {
    "--nextBackgroundColor": `var(--${nextBackgroundColor})`,
    "--opacity": 1,

    duration: 0.1,
    delay: 1,
  });
}

// GSAP CSS Set End

// GSAP Animations
let tl = gsap.timeline();

function setInitialBarPosition() {
  gsap.set("#navigation-options-container", {
    top: `${headerRect.height}px`,
    clipPath: `polygon(0 0, 100% 0%, 100% 0, 0 0)`,
  });
}

setInitialBarPosition();

function menuDownAnimation() {
  if (!isMenuDown) {
    gsap.set("#navigation-options-container", {
      clipPath: `polygon(0 0, 100% 0%, 100% 0, 0 0)`,
    });

    tl.to("#navigation-options-container", {
      clipPath: `polygon(0 0, 100% 0%, 100% 100%, 0% 100%)`,
    });
    isMenuDown = true;
  } else {
    gsap.set("#navigation-options-container", {
      clipPath: `inset(0 0 0 0)`,
    });
    tl.to("#navigation-options-container", {
      clipPath: `inset(0 0 100% 0)`,
    });
    isMenuDown = false;
  }
}

function gsapToAnimation() {
  if (imageDivsCount % 2 === 1) {
    gsap.to(".image-and-info", {
      translate: `0`,
      duration: 1,
      ease: Power3.easeOut,
    });
  } else {
    gsap.to(".image-and-info", {
      translate: `50%`,
      duration: 1,
      ease: Power3.easeOut,
    });
  }
}

function backgroundColorPosition() {
  setBackgroundPopupPosition();
  gsapSetBackgroundColor();

  tl.to("#background-color-popup", {
    scale: 40,
    duration: 1,
  });

  tl.to("body", {
    backgroundColor: gsapSetBackgroundColorStyle,
  });

  tl.set("#background-color-popup", {
    scale: 1,
    opacity: 1,
    duration: 0,
  });
}

// GSAP Animations End



function nextItem() {
  imageDivs = document.querySelectorAll(".image-and-info");
  let cloneCurrentImage = imageDivs[2].cloneNode(true);
  imageContainersSection.append(cloneCurrentImage);
  gsapToAnimation();
  imageDivs[0].remove();
}

function prevItem() {
  imageDivs = document.querySelectorAll(".image-and-info");

  imageDivs[imageDivsCount + 1].remove(); // Remove the very last node in the new array
  let cloneCurrentImage = imageDivs[imageDivsCount - 1].cloneNode(true);
  imageContainersSection.prepend(cloneCurrentImage);
  gsapToAnimation();
}

// Event Listeners

menuButton.addEventListener("click", () => {
  menuDownAnimation();
});

rightButton.addEventListener("click", () => {
  rightButtonRect = rightButton.getBoundingClientRect();
  buttonWidth = rightButtonRect.width;

  let rightButtonCircleExpanPositionX =
    (rightButtonRect.left + rightButtonRect.right) / 2;
  popupCirclePosX = rightButtonCircleExpanPositionX - buttonWidth / 2;

  let rightButtonCircleExpanPositionY =
    (rightButtonRect.top + rightButtonRect.bottom) / 2;
  popupCirclePosY =
    rightButtonCircleExpanPositionY - buttonWidth / 2 + window.pageYOffset;

  if (imageDivsCount % 2 === 1) {
    gsap.set(".image-and-info", {
      translate: `100%`,
    });
    nextItem();
  } else {
    gsap.set(".image-and-info", {
      translate: `150%`,
    });
    nextItem();
  }

  currentBackgroundColor = backgroundColorList[2];
  backgroundColorPosition();
  setbackgroundColorList();
  gsapSetNextAndPrevBackgroundColor();
});

leftButton.addEventListener("click", () => {
  leftButtonRect = leftButton.getBoundingClientRect();

  buttonWidth = leftButtonRect.width;
  let leftButtonCircleExpanPositionX =
    (leftButtonRect.left + leftButtonRect.right) / 2;
  popupCirclePosX = leftButtonCircleExpanPositionX - buttonWidth / 2;

  let leftButtonCircleExpanPositionY =
    (leftButtonRect.top + leftButtonRect.bottom) / 2;
  popupCirclePosY =
    leftButtonCircleExpanPositionY - buttonWidth / 2 + window.pageYOffset;

  if (imageDivsCount % 2 === 1) {
    gsap.set(".image-and-info", {
      translate: `-100%`,
    });
    prevItem();
  } else {
    gsap.set(".image-and-info", {
      translate: `-50%`,
    });
    prevItem();
  }

  currentBackgroundColor = backgroundColorList[0];
  backgroundColorPosition();
  setbackgroundColorList();
  gsapSetNextAndPrevBackgroundColor();
});

window.addEventListener("load", () => {
  setInitialPositions();
  setbackgroundColorList();
  gsapSetBackgroundColor();

  // initialize the background color in regards to the bottle
  gsap.set("body", {
    backgroundColor: `var(--${backgroundColorList[1]})`,
  });

  gsapSetNextAndPrevBackgroundColor();
});

window.addEventListener("resize", (e) => {
  headerRect = header.getBoundingClientRect();

  gsap.set("#navigation-options-container", {
    top: `${headerRect.height}px`,
  });

  if (window.innerWidth >= 850) {
    gsap.set("#navigation-options-container", {
      clipPath: `polygon(0 0, 100% 0%, 100% 100%, 0% 100%)`,
    });
  } else {
    isMenuDown = false;
    gsap.set("#navigation-options-container", {
      clipPath: `polygon(0 0, 100% 0%, 100% 0, 0 0)`,
    });
  }
});

// Event Listeners End

function setInitialPositions() {
  if (imageDivsCount % 2 === 1) {
    gsap.set(".image-and-info", {
      translate: `0%`,
    });
  } else {
    gsap.set(".image-and-info", {
      translate: `50%`,
    });
  }
}

Final Output:

Product Landing Page with HTML, CSS, and JavaScript.gif

Conclusion:

In this journey through the intricacies of creating a Responsive Product Landing Page, we've uncovered the essential ingredients for success in the digital realm. From the fundamental structure provided by HTML to the captivating styling with CSS, the interactivity infused by JavaScript, and the eye-catching animations achieved with GSAP, you've been armed with the tools needed to craft an outstanding online presence.

So, take the knowledge you've gained here and embark on your own digital odyssey. Whether you're launching a new product, promoting a service, or simply sharing your passion with the world, remember that your responsive product landing page is your digital handshake—a warm invitation to explore, engage, and connect.

In the vast landscape of the internet, your landing page can be the oasis that weary travelers seek. Create it with purpose, and you'll leave a lasting impression on those who visit.

Thank you for joining us on this journey. Now, go forth and craft a remarkable responsive product landing page that makes a difference in the digital world. Your audience is waiting to be wowed.

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 😊

End of the article

Subscribe to my Newsletter

Get the latest posts delivered right to your inbox


Latest Post