Build a SpaceX Landing Page Clone with HTML, CSS & JAVASCRIPT
In this blog, You will learn how to build a landing page like the SpaceX website.
Demo
Live Demo
You can see the live demo from here .
Source code
You can find all the source code, media files from here
You will learn:
- Javascript intersection observer to add cool effects
- DOM manipulation
- Aligning elements with css positions.
- How to make responsive websites.
Requirements:
- Basic Html
- Basic Css
- Basic Javascript
I have already made a video tutorial about it. I have explained everything in details in the video.
Don't forget to like, share and subscribe to Cules Coding.
I will only explain the javascript code about Intersection observer and Header animation in this blog. Because that will be quite long and you will not like that. Instead, I will go over HTML and css briefly. Don't worry you will understand. If you don't understand anything, please watch the video and feel free to ask me questions.
So, Let's do it.
We will make the page with a mobile first approach.
Footer
1<footer class="footer">2 <div class="footer__text">SPACEX © 2021</div>34 <ul class="footer__list">5 <li><a class="footer__list__link" href="#">Twitter</a></li>6 <li><a class="footer__list__link" href="#">youtube</a></li>7 <li><a class="footer__list__link" href="#">instagram</a></li>8 <li><a class="footer__list__link" href="#">flickr</a></li>9 <li><a class="footer__list__link" href="#">Linkedin</a></li>10 <li><a class="footer__list__link" href="#">Privacy Policy</a></li>11 </ul>12</footer>
1.footer {2 position: relative;3 margin: 0 auto;4 text-align: center;5 text-transform: uppercase;6 font-size: 0.7rem;7 font-weight: 400;8 padding: 1.5rem 0;9}1011.footer__text {12 color: #979797;13}1415.footer__list {16 display: flex;17 flex-wrap: wrap;18 justify-content: space-evenly;19 align-items: center;20 padding: 0 1rem;21 padding-top: 1rem;22 margin: 0 auto;23}2425.footer__list li {26 margin: 0 10px 10px 0;27}2829.footer__list__link {30 font-weight: 600;31 transition: color 1s cubic-bezier(0.25, 1, 0.25, 1);32}3334.footer__list__link:hover {35 color: #8b939b;36}
Mission Sections
1<section class="mission__container">2 <div class="background one"></div>34 <div class="bottom__content">5 <h4 class="bottom__content__subheader">RECENT LAUNCH</h4>67 <h1 class="bottom__content__header">8 Double Asteroid Redirection Test (DART) Mission9 </h1>1011 <a class="content__button" href="#">12 <span class="text">RE-WATCH</span>13 <div class="hover"></div>14 </a>15 </div>16</section>1718<section class="mission__container">19 <div class="background two"></div>2021 <div class="bottom__content">22 <h4 class="bottom__content__subheader">RECENT LAUNCH</h4>2324 <h1 class="bottom__content__header">25 Double Asteroid Redirection Test (DART) Mission26 </h1>2728 <a class="content__button" href="#">29 <span class="text">RE-WATCH</span>30 <div class="hover"></div>31 </a>32 </div>33</section>3435<section class="mission__container">36 <div class="background three"></div>3738 <div class="bottom__content">39 <h4 class="bottom__content__subheader">RECENT LAUNCH</h4>4041 <h1 class="bottom__content__header">42 Double Asteroid Redirection Test (DART) Mission43 </h1>4445 <a class="content__button" href="#">46 <span class="text">RE-WATCH</span>47 <div class="hover"></div>48 </a>49 </div>50</section>5152<section class="mission__container">53 <div class="background four"></div>5455 <div class="bottom__content">56 <h4 class="bottom__content__subheader">RECENT LAUNCH</h4>5758 <h1 class="bottom__content__header">59 Double Asteroid Redirection Test (DART) Mission60 </h1>6162 <a class="content__button" href="#">63 <span class="text">RE-WATCH</span>64 <div class="hover"></div>65 </a>66 </div>67</section>6869<section class="mission__container">70 <div class="background five"></div>7172 <div class="bottom__content">73 <h4 class="bottom__content__subheader">RECENT LAUNCH</h4>7475 <h1 class="bottom__content__header">76 Double Asteroid Redirection Test (DART) Mission77 </h1>7879 <a class="content__button" href="#">80 <span class="text">RE-WATCH</span>81 <div class="hover"></div>82 </a>83 </div>84</section>
1.mission__container {2 height: 100vh;3 position: relative;4}56.mission__container .background {7 height: 100%;8 background-repeat: no-repeat;9 background-size: cover;10 background-position: center;11}1213.mission__container .background:after {14 content: '';15 position: absolute;16 top: 0;17 left: 0;18 width: 100%;19 height: 100%;20 background-color: rgba(0, 0, 0, 0.2);21}2223.mission__container .background.one {24 background-image: url(../media/1.webp);25}2627.mission__container .background.two {28 background-image: url(../media/2.webp);29}3031.mission__container .background.three {32 background-image: url(../media/3.webp);33}3435.mission__container .background.four {36 background-image: url(../media/4.webp);37}3839.mission__container .background.five {40 background-image: url(../media/5.webp);41 background-position: 65% center;42}4344.mission__container .bottom__content {45 position: absolute;46 bottom: 10%;47 left: 1.5rem;48 width: 90%;49 max-width: 500px;50 overflow: hidden;51 opacity: 0;52 transform: translateY(-100%);53 transition: opacity 1s, transform 1s;54}5556.mission__container .bottom__content .bottom__content__header {57 font-size: 2rem;58 text-align: left;59 margin: 0 0 1rem auto;60 font-weight: 600;61}6263.mission__container .bottom__content .bottom__content__subheader {64 font-size: 1rem;65}6667.mission__container .bottom__content .content__button {68 border: 2px solid white;69 display: inline-block;70 position: relative;71 z-index: 2;72 margin-top: 1rem;73}7475.mission__container .bottom__content .content__button .text {76 font-weight: bold;77 font-size: 0.8rem;78 display: inline-block;79 text-transform: uppercase;80 padding: 1.2rem 2.5rem;81 transition: color 0.5s cubic-bezier(0.19, 1, 0.22, 1);82}8384.mission__container .bottom__content .content__button .hover {85 position: absolute;86 top: 0;87 left: 0;88 background: white;89 height: 100%;90 width: 100%;91 z-index: -1;92 transform: scale3d(1, 0, 1);93 transform-origin: top center;94 transition: transform 0.6s cubic-bezier(0.19, 1, 0.22, 1);95}9697.mission__container .bottom__content .content__button:hover .hover {98 transform: scale3d(1, 1, 1);99 transform-origin: bottom center;100}101102.mission__container .bottom__content .content__button:hover .text {103 color: black;104}105106.mission__container.on__screen .bottom__content {107 opacity: 1;108 transform: translateY(0);109}
1const missons = document.querySelectorAll('.mission__container')23const missionObserver = new IntersectionObserver(4 entries => {5 const ON_SCREEN = 'on__screen'6 entries.forEach(entry => {7 const { isIntersecting, target } = entry89 if (isIntersecting) {10 target.classList.add(ON_SCREEN)11 return true12 }1314 target.classList.remove(ON_SCREEN)15 })16 },17 {18 threshold: 0.5,19 }20)2122missons.forEach(misson => {23 missionObserver.observe(misson)24})
Explaination:
First, we have selected all the mission containers.
Then we created a new Instance of
IntersectionObserver
. We have passed aThen we created a new Instance of
IntersectionObserver
. We have passed a function that will run every time an element comes into the view.We loop over every single mission element and observe them with
missionObserver
.We got all the entries(array of objects) as params. Every entry has two properties.
- isIntersecting: boolean value if an element is on the view or not.
- target: Current element.
If
isIntersecting
is true then we will attach theon__screen
class to that element. Else we will remove the class.on__screen
class will be responsible to show thebottom__content
.
Header
1<header class="header show">2 <div class="background"></div>34 <div class="header__inner">5 <div class="header__logo">6 <a href="#">7 <img src="./media/logos//spacex-logo.png" alt="SpaceX" />8 </a>9 </div>1011 <nav class="header__navigation">12 <ul>13 <li>14 <a class="nav__link" href="#">Falcon 9</a>15 </li>16 <li>17 <a class="nav__link" href="#">Falcon Heavy</a>18 </li>19 <li>20 <a class="nav__link" href="#">Dragon</a>21 </li>22 <li>23 <a class="nav__link" href="#">STARSHIP</a>24 </li>25 <li>26 <a class="nav__link" href="#">human space flight</a>27 </li>28 <li>29 <a class="nav__link" href="#">rideshare</a>30 </li>31 </ul>3233 <div class="shop__container">34 <a class="nav__link" href="#">shop</a>35 </div>36 </nav>3738 <button class="hamburger hamburger--emphatic" type="button">39 <span class="hamburger-box">40 <span class="hamburger-inner"></span>41 </span>42 </button>43 </div>44</header>
1.header {2 height: 5rem;3 position: fixed;4 top: 0;5 left: 0;6 width: 100%;7 z-index: 10;8 transform: translateY(-100%);9 transition: transform 0s 0s;10}1112header#hiding .header__inner {13 transition-delay: 0s;14}1516header#hiding .background {17 transition-delay: 0.3s;18}1920header#hiding {21 transition-delay: 0.9s;22}2324.header.show {25 transform: translateY(0);26}2728.header.show .header__inner {29 opacity: 1;30}3132.header .background {33 background: black;34 position: absolute;35 top: 0;36 left: 0;37 width: 100%;38 height: 100%;39 z-index: -1;40 transform: translateY(-100%);41 transition: transform 0.5s cubic-bezier(0.19, 1, 0.22, 1) 0.1s;42}4344.header.show.with__background .background {45 transform: translateY(0);46}4748.header .header__inner {49 height: 100%;50 width: 100%;51 display: flex;52 opacity: 0;53 transition: opacity 0.2s 0.6s;54}5556.header__logo {57 flex-grow: 1;58 overflow: hidden;59 margin: auto 0;60}6162.header__logo a {63 display: block;64 width: 10rem;65 margin: 0 auto;66}6768.header__logo a img {69 height: 100%;70 width: 100%;71 object-fit: cover;72}7374.header__navigation {75 flex-grow: 2;76 display: none;77 justify-content: space-between;78 align-items: center;79}8081.header__navigation ul li {82 margin: 0 0.7rem;83 display: inline-block;84}8586.header__navigation .nav__link {87 font-weight: bold;88 font-size: 0.8rem;89 text-transform: uppercase;90 position: relative;91}9293.header__navigation .shop__container {94 flex-basis: 5rem;95 text-align: center;96}9798.header__navigation .nav__link:after {99 content: '';100 position: absolute;101 bottom: 0;102 left: 0;103 width: 100%;104 height: 1px;105 background: white;106 transform: scaleX(0);107 transform-origin: right center;108 transition: transform 0.6s cubic-bezier(0.19, 1, 0.22, 1);109}110111.header__navigation .nav__link:hover:after {112 transform: scaleX(1);113 transform-origin: left center;114}
1const header = document.querySelector('.header')23const IS_ACTIVE = 'is-active'4const SHOW = 'show'5const WITH_BACKGROUND = 'with__background'67let prevScrollPos = window.pageYOffset89window.onscroll = () => {10 const currentScrollPos = window.pageYOffset11 const halfScreenHeight = Math.floor(window.innerHeight / 2)1213 if (currentScrollPos > halfScreenHeight) {14 header.classList.add(WITH_BACKGROUND)15 } else {16 header.classList.remove(WITH_BACKGROUND)17 }1819 const HIDING = 'hiding'2021 if (currentScrollPos > prevScrollPos) {22 header.classList.remove(SHOW)23 header.setAttribute('id', HIDING)2425 setTimeout(() => {26 header.removeAttribute('id', HIDING)27 }, 900)28 } else {29 header.classList.add(SHOW)30 }3132 prevScrollPos = currentScrollPos33}
Let me explain the header animation.
The Header will only be displayed if
header
has ashow
class. By default, it will be there. If we are scrolling down, then theshow
class will be removed. And will be added if we scroll down. When we will remove the class, we will attach ahiding
id. After0.9s
we will remove that id.The background will be shown only if the header has the
with__background
class. IfThe background will be shown only if the header has the
with__background
class. If the scroll position is on the top half of the page thenwith__background
class will be removed. There will be two types of animation.Scroll down:
- Header inner part will be removed.
- Then background will be removed.
- Finally, the header will be removed.
Scroll up:
- Header will be shown.
- Background will be shown.
- Header inner part will be shown.
The thing you need to care about is the animation duration and delay.
- Scroll up:
- Header will come instantly without any delay.
- Background will be shown in
0.5
second with a0.1
delay. - Header inner part will be shown in
0.2
second. But it will be after - Header inner part will be shown in
0.2
second. But it will be after background animation which will take0.5 + 0.1 = 0.6
second. So, it will be our delay.
- Scroll down:
- Now we only need to change the delay.
- Header inner will disappear without delay.
- Background will be removed after header inner. Header inner animation will take about
0.2
seconds. So background delay would be0.3
second. - Header will be removed after the Background. Background animation will take
0.5 + 0.3
second. So, the delay would be0.9
second.
Right Navigation
1<nav class="navigation__menu">2 <ul>3 <li><a href="#">Home</a></li>4 <li><a href="#">About</a></li>5 <li><a href="#">Launch</a></li>6 <li><a href="#">mission</a></li>7 <li><a href="#">History</a></li>8 <li><a href="#">Press</a></li>9 <li><a href="#">Careers</a></li>10 <li><a href="#">Contact</a></li>11 </ul>12</nav>
1.navigation__menu {2 position: fixed;3 top: 0;4 right: 0;5 background: black;6 z-index: 5;7 width: 80%;8 max-width: 20rem;9 height: 100%;10 transform: translateX(100%);11 transition: all 0.5s ease-in-out;12}1314.navigation__menu ul {15 width: 80%;16 margin: 0 auto;17 margin-top: 8rem;18 text-align: right;19}2021.navigation__menu ul li {22 transform: translateY(100%);23 transition: all 1s 0.6s;24 opacity: 0;25}2627.navigation__menu ul li a {28 display: block;29 font-size: 1rem;30 line-height: 40px;31 font-weight: 500;32 text-transform: uppercase;33 border-bottom: 1pt solid #252525;34 transition: color 0.4s cubic-bezier(0.25, 1, 0.25, 1);35}3637.navigation__menu ul li a:hover {38 color: #8b939b;39}4041.navigation__menu.open {42 transform: translateX(0);43}4445.navigation__menu.open ul li {46 opacity: 1;47 transform: translateY(0);48}
1const hamburger = document.querySelector('.hamburger')2const navigation = document.querySelector('.navigation__menu')34const IS_ACTIVE = 'is-active'56hamburger.addEventListener('click', () => {7 hamburger.classList.toggle(IS_ACTIVE)8 navigation.classList.toggle('open')9})
Explaination:
- navigation will only be seen if the
is-active
class is present. - When we will click on the hamburger, we will toggle the is-active class on both
- When we will click on the hamburger, we will toggle the is-active class on both
hamburger
andnavigation
elements.
Responsive
1/* sm = 600 */2/* md = 900 */3/* lg = 1200 */4/* xl = 1600 */56@media screen and (min-width: 600px) {7 .mission__container .bottom__content {8 bottom: 15%;9 left: 3rem;10 }1112 .header .header__logo a {13 width: 13rem;14 }1516 .footer .footer__list {17 width: 90%;18 }19}2021@media screen and (min-width: 900px) {22 .mission__container .bottom__content {23 left: 4rem;24 max-width: 600px;25 }2627 .mission__container .bottom__content .bottom__content__header {28 font-size: 2.5rem;29 margin: 1rem 0;30 }3132 .mission__container .bottom__content .bottom__content__subheader {33 font-size: 1.5rem;34 }3536 .footer .footer__list {37 width: 60%;38 }39}4041@media screen and (min-width: 1200px) {42 .header__navigation {43 display: flex;44 }4546 .mission__container .bottom__content {47 left: 6rem;48 }4950 .mission__container .bottom__content .bottom__content__header {51 font-size: 3rem;52 }5354 .mission__container .bottom__content .content__button .text {55 padding: 1.5rem 3rem;56 }5758 .header {59 height: 6.5rem;60 }6162 .header .header__logo {63 flex-grow: 0;64 margin-left: 6rem;65 margin-right: 2rem;66 }6768 .header .header__logo a {69 width: 15rem;70 }7172 .navigation__menu {73 max-width: 30rem;74 }7576 .footer .footer__list {77 width: 50%;78 }79}8081@media screen and (min-width: 1600px) {82 .mission__container .bottom__content {83 left: 15rem;84 }8586 .header .header__logo {87 margin-left: 15rem;88 }8990 .footer .footer__list {91 width: 40%;92 }93}
XS
SM
MD
LG
XL
That's it for this blog. I have tried to explain things simply. Feel free to watch the video if you get stuck. And like always you can ask me questions.
By the way, I am looking for a new opportunity in a company where I can provide great value with my skills. If you are a recruiter, looking for someone skilled in full stack web development and passionate about revolutionizing the world, feel free to contact me. Also, I am open to talking about any freelance project.
Shameless Plug
I have made an Xbox landing page clone with React and Styled components. I hope you will enjoy it. Please consider like this video and subscribe to my channel.
That's it for this blog. I have tried to explain things simply. If you get stuck, you can ask me questions.
Contacts
- Email: thatanjan@gmail.com
- LinkedIn: @thatanjan
- Portfolio: anjan
- Github: @thatanjan
- Instagram : @thatanjan
- Twitter: @thatanjan
Blogs you might want to read:
- Eslint, prettier setup with TypeScript and react
- What is Client-Side Rendering?
- What is Server Side Rendering?
- Everything you need to know about tree data structure
- 13 reasons why you should use Nextjs
- Beginners guide to quantum computers
Videos might you might want to watch: