In this tutorial we’ll continue our tour of Bootstrap 4. More specifically, we’ll learn how to use it to build a responsive landing page.
What We’ll be Working Towards
Before starting, as always, let’s take a quick look at our demo project:
Be sure to check the full screen version and resize your browser window to see how its layout changes depending on the viewport size.
Note: This tutorial assumes you have some familiarity with Bootstrap 4. For example, you should understand how its grid system and flex component work. In addition, a good understanding of its responsive breakpoints will be serve you well.
To help you get up to speed, here at Tuts+ we have a number of courses focusing on Bootstrap 4.
The Assets
We’ll be using a few assets in this project, here’s where you’ll find them:
- For the icons used in this demo, I’ve incorporated the Font Awesome library into our pen.
- All images come from Unsplash.
1. Set Out the Markup
Let’s begin! We do so with typical page markup; a header, a footer, and five sections:
<header>...</header> <main> <!-- Banner Section --> <section>...</section> <!-- Process Section --> <section>...</section> <!-- Featured Destinations Section --> <section>...</section> <!-- Popular Destinations Section --> <section>...</section> <!-- Request a Quote Section --> <section>...</section> </main> <footer>...</footer>
2. Define Some Basic Styles
Before having a closer look at the individual parts of our page, let’s first define some CSS styles. These are mostly reset rules along with a few helper classes which we’ll append to the target elements later on:
:root { --lightblue: #F6F9FC; --red: #d64041; } a, a:hover { color: inherit; } a:hover { text-decoration: none; } .bg-lightblue { background: var(--lightblue); } .bg-red { background: var(--red); } .text-red { color: var(--red); } .container-fluid-max { max-width: 1440px; } .cover { background: no-repeat center/cover; } .p-15 { padding: 15px; }
Note: we’ll try to keep our CSS as lightweight as possible and take advantage of Bootstrap 4’s built-in classes.
3. Build the Header
The page header includes:
- The logo
- The navigation
- The contact info
Using Bootstrap’s defined breakpoints, on extra large screens it should look like this:
On large screens, like this:
On smaller screens it will have a slightly different appearance:
Header HTML
To build the header markup, we’ll take advantage of the navbar component that Bootstrap provides.
Here’s what that looks like:
<header class="fixed-top page-header"> <div class="container-fluid container-fluid-max"> <nav id="navbar" class="navbar navbar-expand-lg navbar-dark"> <a class="navbar-brand" href="#home">...</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse justify-content-lg-between" id="navbarNav"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="">...</a> </li> <!-- more list items here --> </ul> <div class="text-white"> <a href="" class="mr-2"> <i class="fas fa-phone"></i> <div class="d-none d-xl-inline">...</div> </a> <a href=""> <i class="fas fa-envelope"></i> <div class="d-none d-xl-inline">...</div> </a> </div> </div> </nav> </div> </header>
Header CSS
By default, only the mobile header (off-canvas menu) will have a background color.
However, in an upcoming section, we’ll discuss how to add a background color to the desktop header whenever the page is scrolled.
.scroll .page-header { background: var(--red); } .page-header { transition: background 0.5s ease-in-out; } .page-header .navbar { padding: 1rem 0; } .page-header .navbar-toggler { border-color: var(--white); } @media screen and (max-width: 991px) { .page-header { background: var(--red); } }
4. Build the Hero Section
The first section of our page includes:
- A full-screen background image
- A heading and two call-to-action buttons which are vertically centered over that image.
Here’s what it looks like:
Section #1 HTML
<section id="home" class="d-flex align-items-center position-relative vh-100 cover hero" style="background-image:url(IMG_SRC);"> <div class="container-fluid container-fluid-max"> <div class="row"> <div class="col-12 col-md-8 col-lg-6 col-xl-5"> <h1 class="text-white">...</h1> <div class="mt-3"> <a class="btn bg-red text-white mr-2" href="" role="button">...</a> <a class="btn bg-red text-white" href="" role="button">...</a> </div> </div> </div> </div> </section>
Section #1 CSS
For readability reasons, we’ll create an overlay on top of the background. We’ll then ensure that the text is placed over that overlay.
Similarly to the header, later we’ll discuss how to scale this section, each time the page is scrolled.
.scroll .hero { transform: scale(0.98); } .hero { background-attachment: fixed; transition: transform 0.5s ease-in-out; } .hero::after { content: ’’; position: absolute; top: 0; right: 0; bottom: 0; left: 0; background: linear-gradient( rgba(0, 0, 0, 0.5) 0, rgba(0, 0, 0, 0.3) 50%, rgba(0, 0, 0, 0.1) 100% ); } .hero .container-fluid { z-index: 10; }
5. Build the Overview Section
The second section of our page includes some details which provide a quick overview once our visitors have absorbed the hero:
- A heading
- Four text blocks with their icons
- A call-to-action button
On large screens and above, it should look like this:
On small and medium screens, like this:
Finally on extra small screens, all columns are stacked:
Section #2 HTML
<section id="process" class="process"> <div class="container-fluid container-fluid-max"> <div class="row text-center py-5"> <div class="col-12 pb-4"> <h2 class="text-red">...</h2> </div> <div class="col-12 col-sm-6 col-lg-3">...</div> <div class="col-12 col-sm-6 col-lg-3">...</div> <div class="col-12 col-sm-6 col-lg-3">...</div> <div class="col-12 col-sm-6 col-lg-3">...</div> <div class="col-12 pt-3"> <a class="btn bg-red text-white" target="_blank" href="" role="button">...</a> </div> </div> </div> </section>
Stacking Icons
To stack multiple icons in our columns, we’ll take advantage of the styles bundled with Font Awesome. This will allow us to stack a white icon on top of a colored circle icon.
For example, below you can see the markup used for the first column. The two <i>
elements are inline, next to one another, but with the fa-stack
classes they become stacked.
<div class="col-12 col-sm-6 col-lg-3"> <span class="fa-stack fa-2x"> <i class="fas fa-circle fa-stack-2x text-red"></i> <i class="fas fa-map-marked fa-stack-1x text-white"></i> </span> <h3 class="mt-3 text-red h4">...</h3> <p>...</p> </div>
6. Build the Split Blocks Section
The third section of our page includes two full-screen rows. Each row is split, containing an image column and a text column. The contents inside the text columns have to be vertically centered.
On medium screens and above, the section layout will look like this:
On narrow screens, they should be as follows:
Section #3 HTML
You’ll notice the order of the blocks above. On narrow screens the text and image blocks must alternate; image, text, image, text. This wouldn’t happen without the flexbox order-
classes you’ll see used below:
<section id="featured-destinations" class="featured-destinations bg-lightblue"> <div class="row no-gutters"> <div class="col-12 col-md-6 d-flex align-items-center order-1 order-md-0"> <div class="p-15">...</div> </div> <div class="col-12 col-md-6 order-0 order-md-1"> <div class="vh-100 cover" style="bakground-image:url(IMG_SRC);">...</div> </div> <div class="col-12 col-md-6 order-2"> <div class="vh-100 cover" style="bakground-image:url(IMG_SRC);">...</div> </div> <div class="col-12 col-md-6 d-flex align-items-center order-3"> <div class="p-15">...</div> </div> </div> </section>
7. Build the Image Gallery Section
The fourth section of our page includes:
- A heading
- Five image columns along with their description
- A call-to-action button
On medium screens and above, it’ll look like this:
On small screens, the layout changes as follows:
On extra small screens, all image columns are stacked:
Section #4 HTML
<section id="popular-destinations" class="popular-destinations py-5"> <div class="container-fluid container-fluid-max"> <div class="row"> <div class="col-12"> <h2 class="pb-3 text-red">...</h2> </div> <div class="col-12 col-sm-6 col-md-4">...</div> <div class="col-12 col-sm-6 col-md-4">...</div> <div class="col-12 col-sm-6 col-md-4">...</div> <div class="col-12 col-sm-6">...</div> <div class="col-12 col-md-6">...</div> </div> <div class="row"> <div class="col text-center"> <a class="btn bg-red text-white" href="" role="button">...</a> </div> </div> </div> </section>
The markup responsible for setting the columns’ content looks like this:
<div class="col-12 col-sm-6 col-md-4"> <a href="" class="text-white"> <figure class="position-relative overflow-hidden"> <img class="img-fluid" src="IMG_SRC" alt=""> <figcaption class="d-flex align-items-center justify-content-center position-absolute"> <h3>...</h3> </figcaption> </figure> </a> </div>
Section #4 CSS
Initially all images are blurry and grayscale. Each time we hover over an image, the image scales and its default filters are removed.
These are the styles to achieve that:
.popular-destinations figure { margin-bottom: 30px; } .popular-destinations figcaption { top: 0; right: 0; bottom: 0; left: 0; background: rgba(0, 0, 0, 0.3); } .popular-destinations img { filter: grayscale(100%) blur(3px); transition: transform 0.5s, filter 0.75s; } .popular-destinations a:hover img { transform: scale(1.25); filter: none; }
8. Build the Call to Action Section
The fifth section of our page includes:
- A text block
- A call-to-action button
Calls to action are vital on landing pages as they encourage visitors to do something instead of leaving. The pointing icon we’ve used makes the CTA particularly compelling. On medium screens and above, its appearance looks as follows:
On smaller screens though, all elements are stacked:
<section id="request-quote" class="py-5 request-quote bg-lightblue"> <div class="container-fluid container-fluid-max"> <div class="row justify-content-center"> <div class="col-12 col-md-auto py-3 text-center"> <h2 class="mb-0 text-red">...</h2> <p class="mb-0 h4 text-red font-weight-normal">...</p> <div> <div class="col-12 col-md-auto d-flex justify-content-center align-items-center"> <a class="btn bg-red text-white font-weight-bold" href="" role="button"> ... <i class="ml-1 fas fa-hand-point-right"></i> </a> </div> </div> </div> </section>
9. Build the Footer
We’ve reached the end of our landing page template! The page footer includes:
- An element with copyright information
- An element with links to different pages
On medium screens and above, it should look like this:
On smaller screens, the layout changes as follows:
<footer class="py-5 page-footer"> <div class="container-fluid container-fluid-max"> <div class="row"> <div class="col-12 col-md-6 footer-child copyright">...</div> <div class="col-12 col-md-6 footer-child footer-links"> <a href="" class="mr-3">...</a> <a href="">...</a> <div> <small>...</small> </div> </div> </div> </div> </footer>
Footer CSS
The alignment of the footer links will change depending on the viewport size. Here are the rules determining that behavior:
.page-footer .footer-links { text-align: right; } @media screen and (max-width: 767px) { .page-footer .footer-child { text-align: center; } }
At this point, let’s have a look at our page:
10. Add Some JavaScript Actions
It’s time now to write some JavaScript that will enhance the experience of our page.
On Scroll Animations
When the page is scrolled, the body
element should receive the scroll
class. This class will be responsible for the following things:
- Adding a background color to the header. Note that behavior should happen only on medium screens and above. Remember we’ve already set a background color for the mobile menu.
- Scaling the first section.
Let’s quickly revisit the corresponding styles:
.scroll .page-header { background: var(--red); } .scroll .hero { transform: scale(0.98); } .page-header { transition: background 0.5s ease-in-out; } .hero { transition: transform 0.5s ease-in-out; } @media screen and (max-width: 991px) { .page-header { background: var(--red); } }
And here is the required JavaScript code:
const $body = $("body"); const $header = $(".page-header"); const scrollClass = "scroll"; $(window).on("scroll", () => { if (this.matchMedia("(min-width: 992px)").matches) { const scrollY = $(this).scrollTop(); scrollY > 0 ? $body.addClass(scrollClass) : $body.removeClass(scrollClass); } else { $body.removeClass(scrollClass); } });
Firing Bootstrap’s Scrollspy
As a next step we want to automatically update the active menu link depending on the scroll position.
To do this, we’ll take advantage of Bootstrap’s Scrollspy plugin.
Following the documentation, to trigger scrollspy behavior to the navigation items, we’ll have to adjust the body
element. More specifically:
- Give it
position:relative
- Add
data-spy="scroll"
- Add
data-target="#navbar"
where#navbar
is the ID of ournavbar
element. Inside that element there are the menu links that should receive Scrollspy’sactive
class. - Add
data-offset="72"
where 72 is the height of the desktop header as well as the height of the mobile header when the menu is closed. This option determines the menu link that will become active as soon as its corresponding section is 72 pixels from the top of the viewport.
Here are the required page structure changes:
<body data-spy="scroll" data-target="#navbar" data-offset="72" position-relative> ... <nav id="navbar" class="navbar navbar-expand-lg navbar-dark"> ... </nav> ... </body>
One thing to note is that things becomes tricky when responsive offsets are required. That said, when the header has a different height depending on the screen (due to the font sizing). In such a case, giving a static value to the data-offset
attribute won’t work and initializing the plugin through JavaScript (along with some custom code) is the only choice. Saying that, this is beyond the scope of our tutorial at this point.
Add Smooth Scrolling to Logo & Menu Links
Lastly, each time we click on the logo or a menu link, the browser should smoothly scroll to the appropriate section.
Thanks to jQuery’s animate method, we’re able to easily achieve this functionality. Here’s the required JavaScript code:
$(".page-header .nav-link, .navbar-brand").on("click", function(e) { e.preventDefault(); const href = $(this).attr("href"); $("html, body").animate({ scrollTop: $(href).offset().top - 71 }, 600); });
Notice the number 71 inside the code. This number is derived by subtracting 1 from 72 (remember that’s the header height).
My initial attempt was to put the number 72 inside the code above. However, I encountered a problem in a few browsers (e.g. Firefox–Chrome worked though). Specifically, each time a header menu link was clicked, that link didn’t immediately receive the expected active
class (which comes from the Scrollspy component). That worked as soon as I scrolled down around one pixel. With that in mind, a simple fix was just to decrease the initial number by one.
Conclusion
That’s all folks! This has been a long journey, but hopefully you will have found it worth the effort. I really hope this exercise gave you enough knowledge and inspiration for building awesome landing pages with Bootstrap 4. Don’t forget to check the full screen version and make sure it matches your work.
With regards to this demo, a next step might be to make it dynamic by connecting it to a server-side language. For example, it would be great to build a WordPress theme based on this layout.
Thanks a lot for reading!