Learn how to build a Netflix Clone Project using HTML, CSS, and JavaScript. Step by step guide for beginners to design a streaming website layout.
Table of Contents
The Netflix Clone Project is a simple web application built using HTML, CSS, and JavaScript. The main aim is to replicate the Netflix user interface (UI) to understand how streaming websites are designed.
This project is a great way for beginners to practice web development. You will learn how to create a navigation bar, a banner section, and movie rows just like Netflix.
By the end of this tutorial, you will have a working Netflix-style homepage that looks professional and responsive.
Prerequisites
Before starting, make sure you have:
- Basic knowledge of HTML tags, CSS styling, and JavaScript functions
- A code editor like Visual Studio Code (VS Code)
- A web browser (Chrome, Firefox, or Edge)
- Basic idea of linking CSS and JS files to HTML
Source Code
Step 1 (HTML Code):
First, we will start with HTML. In this step, we create the basic layout of the website. The structure will include the header, banner, movie sections, and FAQ section.
For design, we will use Tailwind CSS because it helps us style faster with ready classes. For the carousel (movie slider), we will use the Swiper plugin, which makes sliding movies smooth and responsive.
Let’s break down the HTML code step by step:
1. Head Section
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Netflix Clone - Watch TV Shows Online, Watch Movies Online</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.min.css" />
<link href="https://fonts.googleapis.com/css2?family=Inter...">
<link rel="shortcut icon" href="netflix.ico" />
<link rel="stylesheet" href="styles.css">
</head>
- TailwindCSS is loaded via CDN (for utility-based styling).
- Swiper CSS is included for the trending slider.
- Google Fonts (Inter) for typography.
- Netflix favicon so the browser tab shows the red “N.”
- Custom styles.css for extra styling.
2. Hero Section (Header + Banner)
<div class="hero-bg">
<header> ... Netflix Logo + Language Selector + Sign In </header>
<div class="text-center ...">
<h1>Unlimited movies, TV shows and more</h1>
<p>Starts at ₹149. Cancel at any time.</p>
<form> ... email input + Get Started button </form>
</div>
</div>
- Shows Netflix logo (SVG).
- Language dropdown (English/Hindi).
- Sign In button.
- A hero message with title, subtitle, and email form.
3. Curved Banner Transition
<div class="banner-curve-wrapper">
<div class="curve-container">
<div class="banner-curve"></div>
</div>
</div>
- Adds a curved divider effect between the hero and the next section.
4. Trending Now (Swiper Carousel)
<section>
<h2>Trending Now</h2>
<div class="swiper-container">
<ul class="swiper-wrapper">
<li class="swiper-slide"> ... Poster, Rank Number ... </li>
</ul>
<!-- Swiper nav buttons -->
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
</div>
</section>
- Uses SwiperJS to create a sliding carousel of shows.
- Each list item has:
- Poster background image.
- Show title.
- Ranking badge (1,2,3...).
5. More Reasons to Join
<section>
<h2>More reasons to join</h2>
<div class="grid">
<div>Enjoy on your TV</div>
<div>Download your shows to watch offline</div>
<div>Watch everywhere</div>
<div>Create profiles for kids</div>
</div>
</section>
- Four feature cards with icons/text about Netflix benefits.
6. FAQ Section
<section>
<h2>Frequently Asked Questions</h2>
<button class="faq-question">What is Netflix? ...</button>
<div class="faq-answer">Netflix is a streaming service...</div>
...
<form> Email input + Get Started button </form>
</section>
- Accordion-style FAQ questions with expandable answers.
- Another email subscription form is at the bottom.
7. Footer
<footer>
<p>Questions? Call 000-800-919-1742</p>
<div class="grid"> ... FAQ, Help Centre, Jobs, Privacy, etc ... </div>
<select>Language dropdown</select>
</footer>
- Customer support phone number.
- Footer links like Terms of Use, Privacy, Jobs, etc.
- Language selector (again).
Step 2 (CSS Code):
After HTML, we move to CSS. Even though TailwindCSS handles most of the styling, we will still use some custom CSS to make our project look closer to Netflix.
Let’s break down the CSS code step by step:
1. Base Styles
body {
font-family: 'Inter', sans-serif;
background-color: #000000;
color: #ffffff;
}
- Uses Inter font everywhere.
- Black background, white text → Netflix’s dark theme.
2. Hero Background
.hero-bg {
background-image: linear-gradient(
to top,
rgba(0, 0, 0, 0.9) 0,
rgba(0, 0, 0, 0.4) 60%,
rgba(0, 0, 0, 0.9) 100%
),
url('...hero-bg.jpg');
background-size: cover;
background-position: center;
}
- Gradient overlay on top of a background image → makes text readable.
- The gradient fades darker at the top and bottom, lighter in the middle.
3. FAQ Accordion
.faq-question { transition: background-color 0.3s ease; }
.faq-question:hover { background-color: #4a4a4a; }
- FAQ buttons darken on hover.
.faq-answer {
max-height: 0;
overflow: hidden;
transition: max-height 0.5s ease-in-out, padding 0.5s ease-in-out;
}
.faq-question.open + .faq-answer {
max-height: 1200px;
padding-top: 1.5rem;
padding-bottom: 1.5rem;
}
- Answers are collapsed by default.
- When .open is added, they expand smoothly with animation.
.faq-question svg { transition: transform 0.3s ease; }
.faq-question.open svg { transform: rotate(45deg); }
- Expands the “+” icon into an “×” when open.
4. Floating Labels (Form Input)
.form-input-container label {
transform: translateY(-50%);
transition: all 0.2s ease-out;
}
.form-input-container input:focus + label,
.form-input-container input:not(:placeholder-shown) + label {
top: 0.5rem;
transform: translateY(0) scale(0.75);
font-weight: 600;
}
- Labels float up & shrink when the input is filled or focused (modern Netflix form style).
5. Scrollbars (Hidden in Sliders)
.category-row::-webkit-scrollbar { display: none; }
.category-row { -ms-overflow-style: none; scrollbar-width: none; }
- Hides scrollbars across browsers for a clean slider effect.
6. Swiper Slider Buttons
.trending-swiper .swiper-slide { width: auto; }
.trending-swiper .swiper-button-next,
.trending-swiper .swiper-button-prev {
height: 7.5rem;
width: 1.5rem;
border-radius: 0.5rem;
display: flex;
align-items: center;
background-color: rgba(255, 255, 255, 0.1);
color: rgba(255, 255, 255, 0.7);
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
}
.trending-swiper .swiper-button-next:hover,
.trending-swiper .swiper-button-prev:hover {
background-color: rgba(20, 20, 20, 0.9);
}
- Custom navigation arrows for the trending carousel.
- Semi-transparent white by default → turns darker on hover.
- .swiper-button-disabled { display: none !important; }
- Hides navigation arrows when you can’t scroll further.
7. Netflix Logo
.logo {
width: 9.25rem;
height: 2.5rem;
color: rgb(229, 9, 20);
fill: currentColor;
display: block;
}
@media screen and (max-width: 959.98px) {
.logo { width: 5.5625rem; height: 1.5rem; }
}
- Red Netflix “N” logo.
- Responsive size → smaller on mobile.
8. Language Selector Icon
.svg-lang {
top: 58%;
left: 0.8rem;
}
- Positions the globe icon inside the language dropdown.
9. Gradient Background (Reusable Class)
.gradient-bg {
background: linear-gradient(149deg, #192247 0%, #210e17 99.08%);
}
- Dark purplish gradient used in sections.
10. Banner Curve (Wavy Divider)
.banner-curve-wrapper {
overflow-x: hidden;
position: relative;
height: 6.25rem;
z-index: 1;
}
.banner-curve {
position: absolute;
height: 100%;
border-top-left-radius: 50% 100%;
border-top-right-radius: 50% 100%;
background: radial-gradient(...), black;
}
.banner-curve:before {
content: '';
background: linear-gradient(to right, #210d16 16%, #b82869, #e50914, #b82869, #210d16 84%);
}
- Creates the curved transition effect between the hero and trending section.
- Uses gradients + rounded borders for smooth waves.
- Responsive sizes adjust width/position across screen sizes.
11. List Items (Movie Cards)
.list-item-wrapper {
flex-shrink: 0;
scroll-snap-align: start;
display: flex;
}
.card-btn {
background: rgb(35, 35, 35);
border-radius: 0.5rem;
transition: transform 0.2s ease-in-out;
}
- .card-btn:hover { transform: scale(1.05); z-index: 2; }
- Each movie card is scroll-snapped in the row.
- Slight zoom effect on hover → feels interactive.
12. Poster Styling
.poster {
border-radius: 0.5rem;
background-color: rgb(35, 35, 35);
}
@media all {
.poster { width: 7rem; height: 9.8rem; }
}
@media all and (min-width: 960px) {
.poster { width: 8.75rem; height: 12.25rem; }
}
- Responsive movie poster sizes.
- Dark background placeholder before image loads.
13. Ranking Numbers
.rank-number {
position: absolute;
font-size: 4rem;
left: -0.625rem;
}
.rank-inner {
font-weight: 700;
color: rgb(65, 65, 65);
-webkit-text-stroke: 0.25rem white;
text-shadow: 0 0 1.5rem rgba(0, 0, 0, 0.5);
}
.rank-inner::before {
content: attr(data-content);
-webkit-text-fill-color: black;
}
- Big ranking numbers (1,2,3,...) shown behind posters.
- White stroke + dark shadow → “pop out” effect.
body {
font-family: 'Inter', sans-serif;
background-color: #000000;
color: #ffffff;
}
.hero-bg {
background-image: linear-gradient(
to top,
rgba(0, 0, 0, 0.9) 0,
rgba(0, 0, 0, 0.4) 60%,
rgba(0, 0, 0, 0.9) 100%
),
url('https://raw.githubusercontent.com/farazc60/Project-Images/refs/heads/main/netflix/hero-bg.jpg');
background-size: cover;
background-position: center;
}
.faq-question {
transition: background-color 0.3s ease;
}
.faq-question:hover {
background-color: #4a4a4a;
}
.faq-answer {
max-height: 0;
overflow: hidden;
transition: max-height 0.5s ease-in-out, padding 0.5s ease-in-out;
}
.faq-question.open + .faq-answer {
max-height: 1200px; /* Adjust as needed */
padding-top: 1.5rem;
padding-bottom: 1.5rem;
}
.faq-question svg {
transition: transform 0.3s ease;
}
.faq-question.open svg {
transform: rotate(45deg);
}
.form-input-container label {
transform: translateY(-50%);
transition: all 0.2s ease-out;
}
.form-input-container input:focus + label,
.form-input-container input:not(:placeholder-shown) + label {
top: 0.5rem;
transform: translateY(0) scale(0.75);
font-weight: 600;
}
.category-row::-webkit-scrollbar {
display: none; /* Hide scrollbar for Chrome, Safari and Opera */
}
.category-row {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
.trending-swiper .swiper-slide {
width: auto;
}
.trending-swiper .swiper-button-next,
.trending-swiper .swiper-button-prev {
height: 7.5rem;
width: 1.5rem;
border-radius: 0.5rem;
border: none;
display: flex;
-webkit-box-align: center;
align-items: center;
padding: 0px;
margin: 0px;
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
color: rgba(255, 255, 255, 0.7);
background-color: rgba(255, 255, 255, 0.1);
cursor: pointer;
}
.trending-swiper .swiper-button-next:hover,
.trending-swiper .swiper-button-prev:hover {
background-color: rgba(20, 20, 20, 0.9);
}
.trending-swiper .swiper-button-next:after,
.trending-swiper .swiper-button-prev:after {
font-size: 16px;
font-weight: 600;
}
.swiper-button-disabled {
display: none !important;
}
.logo {
width: 9.25rem;
height: 2.5rem;
color: rgb(229, 9, 20);
fill: currentColor;
display: block;
}
@media screen and (max-width: 959.98px) {
.logo {
width: 5.5625rem;
height: 1.5rem;
}
}
.svg-lang {
top: 58%;
left: 0.8rem;
}
.gradient-bg {
background: linear-gradient(149deg, #192247 0%, #210e17 99.08%);
}
.banner-curve-wrapper {
box-sizing: border-box;
overflow-x: hidden;
position: relative;
height: 6.25rem;
z-index: 1;
}
.banner-curve {
box-sizing: border-box;
position: absolute;
height: 100%;
top: 0;
margin: auto;
display: flex;
align-items: center;
border: solid 0.25rem transparent;
border-top-left-radius: 50% 100%;
border-top-right-radius: 50% 100%;
border-bottom: none;
background: radial-gradient(
50% 500% at 50% -420%,
rgba(64, 97, 231, 0.4) 80%,
rgba(0, 0, 0, 0.1) 100%
), black;
background-clip: padding-box;
}
@media all {
.banner-curve {
width: 200%;
left: -50%;
}
}
@media all and (min-width: 600px) {
.banner-curve {
width: 180%;
left: -40%;
}
}
@media all and (min-width: 960px) {
.banner-curve {
width: 150%;
left: -25%;
}
}
@media all and (min-width: 1280px) {
.banner-curve {
width: 130%;
left: -15%;
}
}
@media all and (min-width: 1920px) {
.banner-curve {
width: 120%;
left: -10%;
}
}
.banner-curve:before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: -1;
margin-top: -0.25rem;
border-radius: inherit;
background: linear-gradient(
to right,
rgba(33, 13, 22, 1) 16%,
rgba(184, 40, 105, 1),
rgba(229, 9, 20, 1),
rgba(184, 40, 105, 1),
rgba(33, 13, 22, 1) 84%
);
}
/* List Item Wrapper */
.list-item-wrapper {
flex-shrink: 0;
scroll-snap-align: start;
display: flex;
}
@media all {
.list-item-wrapper {
scroll-margin-inline-start: 2.3rem;
padding: 0.3rem 0.625rem;
}
}
@media all and (min-width: 600px) {
.list-item-wrapper {
scroll-margin-inline-start: 2.4rem;
}
}
@media all and (min-width: 960px) {
.list-item-wrapper {
padding: 0.4rem 1.375rem;
}
}
@media all and (min-width: 1280px) {
.list-item-wrapper {
scroll-margin-inline-start: 2.75rem;
padding: 0.5rem 1.375rem;
}
}
@media all and (min-width: 1920px) {
.list-item-wrapper {
padding: 0.55rem 1.375rem;
}
}
/* Button Card */
.card-btn {
position: relative;
padding: 0;
background: rgb(35, 35, 35);
border: none;
border-radius: 0.5rem;
transition: transform 0.2s ease-in-out;
}
.card-btn:hover {
transform: scale(1.05);
z-index: 2;
}
/* Poster Container */
.poster {
position: relative;
border-radius: 0.5rem;
background-color: rgb(35, 35, 35);
}
@media all {
.poster {
width: 7rem;
height: 9.8rem;
}
}
@media all and (min-width: 960px) {
.poster {
width: 8.75rem;
height: 12.25rem;
}
}
@media all and (min-width: 1280px) {
.poster {
width: 11.25rem;
height: 15.75rem;
}
}
@media all and (min-width: 1920px) {
.poster {
width: 13.375rem;
height: 18.75rem;
}
}
/* Poster Background Image */
.poster-bg {
position: absolute;
inset: 0;
border-radius: 0.5rem;
background-size: cover;
z-index: 2;
}
.rank-number {
position: absolute;
z-index: 2;
}
@media all {
.rank-number {
font-size: 4rem;
bottom: 0.1rem;
left: -0.625rem;
}
}
@media all and (min-width: 960px) {
.rank-number {
font-size: 5rem;
bottom: 0;
left: -1.375rem;
}
}
@media all and (min-width: 1280px) {
.rank-number { font-size: 6.25rem; }
}
@media all and (min-width: 1920px) {
.rank-number { font-size: 7.5rem; }
}
.rank-inner {
line-height: 1;
display: inline-block;
height: 1em;
position: relative;
font-weight: 700;
color: rgb(65, 65, 65);
-webkit-text-stroke: 0.25rem rgb(255, 255, 255);
text-shadow: 0 0 1.5rem rgba(0, 0, 0, 0.5);
}
.rank-inner::before {
content: attr(data-content);
-webkit-text-fill-color: rgb(0, 0, 0);
-webkit-text-stroke: 0;
position: absolute;
} Step 3 (JavaScript Code):
This is our final step, where we use JavaScript to add interactivity. With JS, we make our website dynamic and functional.
Let’s break down the JS code step by step:
1. FAQ Toggle Code
document.querySelectorAll('.faq-question').forEach(button => {
button.addEventListener('click', () => {
button.classList.toggle('open');
});
});
- Finds all elements with .faq-question class.
- Loops over them (forEach).
- Adds a click event listener to each button.
- When clicked → toggles the .open class on that element.
💡 Why it matters:
- The CSS you saw earlier uses .faq-question.open + .faq-answer to expand/collapse the FAQ answers.
- It also rotates the “+” icon into “×”.
- So this tiny JS snippet powers the whole FAQ accordion.
2. Swiper Initialization
const swiper = new Swiper('.trending-swiper', {
slidesPerView: 'auto',
loop: false,
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
}
});
- Creates a Swiper instance (that’s the library used for carousels).
- Targets .trending-swiper → the container for “Trending Now” movies.
🔧 Options explained:
- slidesPerView: 'auto' → slide width adjusts automatically (posters can have different widths).
- loop: false → the slider does not wrap around when you reach the end.
- navigation → defines the next/prev buttons by their CSS selectors:
- .swiper-button-next → right arrow.
- .swiper-button-prev → left arrow.
💡 Why it matters:
- Without this, the Trending carousel wouldn’t slide.
- It gives Netflix-like scrolling with custom arrows.
document.querySelectorAll('.faq-question').forEach(button => {
button.addEventListener('click', () => {
button.classList.toggle('open');
});
});
// Initialize Swiper
const swiper = new Swiper('.trending-swiper', {
slidesPerView: 'auto',
loop: false,
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
}
});Final Output:
Conclusion:
Creating a Netflix Clone with HTML, CSS, and JavaScript is a great way to practice web design. You learned how to use background images, gradients, responsive layouts, and text styling.
This project not only makes your coding portfolio strong but also gives you confidence to build real websites. Once you master HTML and CSS, you can improve this project further by adding JavaScript for interactivity or even turning it into a React project.
Start today and showcase your Netflix Clone to the world!
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 😊


