Bootstrap 4 – Adding Bootstrap components

MyPhoto is looking pretty bare right now, so let’s take a look at integrating some Bootstrap components into our sections. First, ensure that as per the setup instructions in Chapter 1, Revving up Bootstrap, you have added Bootstrap’s JavaScript library and its dependency, jQuery:

<script src="node_modules/jquery/dist/jquery.min.js"></script>
<script src="node_modules/bootstrap/dist/js/bootstrap.min.js">
</script>

Jumbotron

The first component we will integrate is Bootstrap’s jumbotron.

The jumbotron component is essentially a very simple visual cue that helps draw attention to certain content. It is generally used as a splash to offer immediate information to the user. That is exactly what we will be doing with it.

In the Welcome section of our page, nest a jumbotron element into the container element:

<div class="container-fluid myphoto-section bg-myphoto-light">
    <div class="container">
        <div >
            <h1>Welcome to MyPhoto</h1>
            <p>Photographs you can cherish!</p>
        </div>
    </div>
</div>

We have nested a container element in the container-fluid Welcome element. We do this so that our content is centered within the section, allowing for gutter space on the left and right. Within that container, we add a jumbotron element. The jumbotron class simply gives its element a hero-banner type style to attract the eye. The jumbotron itself acts in a similar way to a container, encompassing its own content. Here, we add a header and a paragraph to provide some context to the user. Take a look at the following screenshot:

Figure 3.4: The Bootstrap jumbotron class to create a banner welcoming the user to MyPhoto (example04.html)

Oh, not great. The jumbotron has worked as expected, but it is not grabbing our attention as we would hope against a light background. Being a photographer’s page, maybe we should add some pictorial content here? We can use jumbotron to display a hero-image. Add a new class to myphoto.css:

.jumbotron-welcome {
    background-image: url('/images/skyline.png');
    background-size: cover;
    color: white;
}

This class will simply apply a background image and a light font color to an element. Apply the class to our jumbotron element:

<div >

Take a look at figure 3.5:

Figure 3.5: Using Sao Paulo’s skyline as a background image for MyPhoto’s welcome banner (example05.html)

Pretty nice. Let’s flip that and apply the background image to the Welcome section container element, removing the bg-myphoto-light class. Add the following class to myphoto.css:

.bg-myphoto-welcome {
    background-image: url('/images/skyline.png');
    background-size: cover;
    color: #504747;
}

Then, update the Welcome section to the following:

<div class="container-fluid myphoto-section bg-myphoto-welcome">
    <div class="container">
        <div >
            <h1>Welcome to MyPhoto</h1>
            <p>Photographs you can cherish!</p>
        </div>
    </div>
</div>

Our new class again applies the background image. It also applies a dark font color, which will be inherited by the jumbotron. We have removed the jumbotron-welcome class from the jumbotron element.

Excellent! We have added some photographic content and our jumbotron attracts attention; refer to figure 3.6:

Figure 3.6: Using São Paulo’s skyline as a background image for MyPhoto’s welcome banner (example06.html)

Tabs

MyPhoto offers a trio of services. We built the UI for one of these: the Print service, in Chapter 2, Making a Style Statement. The UI displayed the prices for various print sizes. Obviously, we will want to integrate the Print service into the Services section of the MyPhoto page. We also need to include the other two services, namely, Events, where a photographer may take photographs of a customer’s event such as a wedding or a conference, and Personal, where a photographer may take family photos and so on.

Rather than building the services into three separate pages, we will develop them using Bootstrap’s tabs component.

Tabs are a part of Bootstrap’s nav family of components. Tabs provide an elegant way of displaying and grouping related content. Under the surface, tabs are simply list elements linked to div elements, representing the tab contents, with some nice styling applied. Tabs are one of the Bootstrap components that require jQuery and bootstrap.js to function correctly.

First, we will add the tab list to the Services section (that is, below <div ><h3>Services</h3></div>):

ormatted HTML:
<ul class="nav nav-tabs nav-justified">
   <li class="nav-item">
      <a href="#services-events" data-toggle="tab" class="nav-link
         active">Events
      </a>
   </li>
   <li class="nav-item">
      <a href="#services-personal" data-toggle="tab" class="nav- 
         link">Personal</a>
   </li>
   <li class="nav-item">
      <a href="#services-prints" data-toggle="tab"
         >
      Prints
      </a>
   </li>
</ul>

We’re wrapping the Services header in a container element, so we follow the same convention as the Welcome section and leave gutter space around the content. Within that container, we also include the tabs. We create an unordered list (ulelement with the nav base class and the nav-tabs class to apply the tab styling. The list elements are then created, with the tab heading text and an href to the relevant tab content. The nav-item class is applied to each list item to denote that the item is indeed a navigation item (the nav-item class adjusts the margin and float of the list item and ensures that the list items are not stacked on top of each other, but appear next to one another instead). The anchor element that is used to reference the tab’s corresponding section is given a nav-link class. This nav-link class adjusts the following:

  • The anchor’s padding so that it displays nicely as a tab link.
  • It removes the default anchor focus and hover text decoration.
  • It changes the anchor’s display to inline-block. This has two important effects on the element:
    • The browser renders any white space contained within the element.
    • The element is placed inline but maintains the properties of a block-level element.

The active class is applied to the default selected list item’s anchor element. Last but not least, the anchor’s data-toggle attribute is set to tab. Our Services section now looks like this:

Figure 3.7: Using tabs components to build out the MyPhoto’s Services section (example07.html)
Navigation tabs in Bootstrap 3

Nav tabs in Bootstrap 3 require slightly more work than when using Bootstrap 4. For one, Bootstrap 3 does not have the nav-item and nav-link classes. Instead, we create an unordered-list (ulelement with the nav base class, namely, nav-tabs class, to apply the tab styling and nav- justified to center the text within the tab headings. The list elements are then created with the tab heading text and an href to the relevant tab content. The active class is applied to the default selected list item:

<ul role="tablist">
<li role="presentation" ><a href= "#services-events" role="tab" data- toggle="tab">Events</a></li>
<li role="presentation"><a href="#services-personal" role="tab" data-toggle="tab">Personal</a></li>
<li role="presentation"><a href="#services-prints" role="tab" data-toggle="tab">Prints</a></li>
</ul>
Note that the nav-justified class has been removed from Bootstrap 4.

We now have some selectable tabs with inappropriate styling and no content. Let’s resolve the content issue first. We will add Lorem Ipsum text to the Events and Personal tab content, and we will use an Our Print Sizes table for the Prints tab content:

<div class="tab-content bg-myphoto-light">
   <div role="tabpanel" class="tab-pane active" id="services-events">
      <div class="container">
         <div class="row">
            <p>Lorem Ipsum</p>
         </div>
      </div>
   </div>
   <div role="tabpanel" class="tab-pane" id="services-personal">
      <div class="container">
         <div class="row">
            <p>Lorem Ipsum</p>
         </div>
      </div>
   </div>
   <div role="tabpanel" class="tab-pane" >
      <div class="m-x-auto" style="width:50%">
         <h1 class="bg-primary text-center">Special Offers</h1>
      </div>
      <div class="container">
         <h1 class="hidden-lg-down">Our Print Sizes</h1>
         <div class="row">
            <div class="col-sm-3">
               <h5 class="text-hide">Small</h5>
               <div class="row">
                  <div class="col-sm-4 bg-info">
                     6x5
                     <div class="row">
                        <div class="col-sm-3 text-muted">€15</div>
                        <div class="col-sm-3 text-success">€8</div>
                     </div>
                  </div>
                  <div class="col-sm-4">
                     8x10
                     <div class="row">
                        <div class="col-sm-3 text-muted">€18</div>
                        <div class="col-sm-3 text-success">€11</div>
                     </div>
                  </div>
                  <div class="col-sm-4">
                     11x17
                     <div class="row">
                        <div class="col-sm-3 text-muted">€25</div>
                        <div class="col-sm-3 text-success">€20</div>
                     </div>
                  </div>
               </div>
            </div>
            <div class="col-xs-6 col-sm-3">
               <h5 class="text-hide">Medium</h5>
               <div class="row">
                  <div class="col-sm-4">
                     12x18
                     <div class="row">
                        <div class="col-sm-3 text-muted">€28</div>
                        <div class="col-sm-3 text-success">€23</div>
                     </div>
                  </div>
                  <div class="col-sm-4 bg-info">
                     16x20
                     <div class="row">
                        <div class="col-sm-3 text-muted">€35</div>
                        <div class="col-sm-3 text-success">€25</div>
                     </div>
                  </div>
                  <div class="col-sm-4">
                     18x24
                     <div class="row">
                        <div class="col-sm-3 text-muted">€40</div>
                        <div class="col-sm-3 text-success">€32</div>
                     </div>
                  </div>
               </div>
            </div>
            <div class="col-sm-3">
               <h5 class="text-hide">Large</h5>
               <div class="row">
                  <div class="col-sm-4 bg-info">
                     19x27
                     <div class="row">
                        <div class="col-sm-3 text-muted">€45</div>
                        <div class="col-sm-3 text-success">€30</div>
                     </div>
                  </div>
                  <div class="col-sm-4">
                     20x30
                     <div class="row">
                        <div class="col-sm-3 text-muted">€48</div>
                        <div class="col-sm-3 text-success">€40</div>
                     </div>
                  </div>
                  <div class="col-md-4 bg-info">
                     22x28
                     <div class="row">
                        <div class="col-sm-3 text-muted">€55</div>
                        <div class="col-sm-3 text-success">€40</div>
                     </div>
                  </div>
               </div>
            </div>
            <div class="col-sm-3">
               <h5 class="text-hide">Extra Large</h5>
               <div class="row">
                  <div class="col-md-4">
                     24x36
                     <div class="row">
                        <div class="col-sm-3 text-muted">€60</div>
                        <div class="col-sm-3 text-success">€55</div>
                     </div>
                  </div>
                  <div class="col-md-4 bg-info">
                     27x39
                     <div class="row">
                        <div class="col-sm-3 text-muted">€75</div>
                        <div class="col-sm-3 text-success">€60</div>
                     </div>
                  </div>
                  <div class="col-md-4 bg-info">
                     27x40
                     <div class="row">
                        <div class="col-sm-3 text-muted">€75</div>
                        <div class="col-sm-3 text-success">€60</div>
                     </div>
                  </div>
               </div>
            </div>
         </div>
         <div class="bg-danger">
            <p >Terms and Conditions Apply</p>
         </div>
      </div>
   </div>
</div>

We add a tab-content element to wrap the three services, which are declared with a tab- pane class. The tab-pane classes have an id attribute matching the href attribute of the corresponding tab heading, and each of the tab-pane elements has a container element for the contents of the pane. Now, clicking on the Prints tab will surface the  Our Print Sizes chart. We have modified the print sizes chart for its new context within the tabs component. Take a look at figure 3.8:

Figure 3.8: Adding tab content using the tab-pane class (example08.html)

Let’s quickly add some styling to the tab headings and panels to make them slightly more readable. Add the following classes to myphoto.css:

.bg-myphoto-dark .nav-tabs a {
color: white;
}

Save and refresh; our Services section now looks as follows:

Figure 3.9: Improving the look and feel of our tabs by setting the tab title color to white (example08.html)

With those changes, our Services tabs are a little more pleasing to the eye. The contents of the tabs can now be fleshed out within their own specific container elements.

Carousel

To exhibit the photographic wares, we need a gallery. To implement the gallery feature, we will integrate Bootstrap’s carousel component. The carousel acts as a slideshow, with a list of nested elements as the slides.

Let’s add a carousel, with three slides, to the Gallery section:

<div class="container-fluid myphoto-section bg-myphoto-light">
   <div class="container">
      <h3>Gallery</h3>
      <div  class="carousel slide" data-
         ride="carousel" data-interval="3000">
         <div class="carousel-inner" role="listbox">
            <div style="height: 400px" class="carousel-item 
               active">
               <img 
                  class="d-block img-fluid"
                  src="images/brazil.png">
               <div class="carousel-caption"> Brazil
               </div>
            </div>
            <div style="height: 400px" class="carousel-item">
               <img
                  class="d-block img-fluid"
                  src="images/datsun.png">
               <div class="carousel-caption"> Datsun 260Z
               </div>
            </div>
            <div style="height: 400px" class="carousel-item">
               <img
                  class="d-block img-fluid"
                  src="images/skydive.png">
               <div class="carousel-caption"> Skydive</div>
            </div>
         </div>
         <a class="left carousel-control" href="#gallery-carousel" 
         role="button" data-slide="prev">
         <span class="icon-prev" aria-hidden="true"></span>
         </a>
         <a class="right carousel-control" href="#gallery-carousel" 
         role="button" data-slide="next">
         <span class="icon-next" aria-hidden="true"></span>
         </a>
         <ol class="carousel-indicators">
            <li data-target="#gallery-carousel" data-slide-to="0" 
             ></li>
            <li data-target="#gallery-carousel" data-slide-to="1"></li>
            <li data-target="#gallery-carousel" data-slide-to="2"></li>
         </ol>
      </div>
   </div>
</div>

Take a look at figure 3.10:

Figure 3.10: Using the Bootstrap carousel to display a gallery of images. Note the arrows on both sides of the images; these are the carousel controls that allow users to navigate the image gallery (example09.html)

Now, we have a fully functioning, three-slide gallery. Let’s break down what is happening here.

The carousel in Bootstrap 3
When using the carousel feature after switching to Bootstrap 4, having used Bootstrap 3, there are two changes to be wary of. The first is that the carousel-item class was just called item class in Bootstrap 3. The second is that Bootstrap 4 comes with the icon-next and icon-prev classes that should be used with the carousel controls. A typical Bootstrap 3 carousel control may look as follows:

<a href="#gallery- carousel" role="button" data-slide="prev">
<span aria- hidden="true"></span>
</a>
<a href="#gallery- carousel" role="button" data-slide="next">
<span aria- hidden="true"></span>
</a> 

First, we declare the carousel parent tag:

<div   data-ride= "carousel" data-interval="4000"></div>

We give the div an id that can be referenced by its nested elements, such as the carousel indicators. We use Bootstrap’s carousel and slide classes. The data-ride="carousel" attribute indicates that the carousel is to automatically initialize on page load. The data- interval attribute indicates that the slides should change every 4000 ms. There are other options such as data-pause, which will indicate whether or not the carousel should pause on hover. The default value is hover; to prevent pausing, set this option to false. The data-wrap is a Boolean attribute to indicate whether the carousel should be a continuous loop or should end once the last slide has been reached. The default value for data-wrap is true. The data-keyboard is also a Boolean attribute to indicate whether or not the carousel is keyboard-controllable. The default value for data-keyboard is true.

Then, we add the actual slides. The slides are nested within a carousel-inner element, to contain the slides. The slides are also div elements, with the carousel-item class, and the active class to indicate which slide to show on initialization:

<div style="height: 400px" class="carousel-item active">
   <img class="d-block img-fluid" src="images/image1.png">
   <div > Skydiving </div>
</div>

Within the div, we have an image element to act as the main content for the slide, and it has a sibling carousel-caption element, which is exactly what it sounds like—a caption for the slide. The carousel-caption element can contain nested elements.

Next, we add the right and left arrows for navigating through the slides:

<a class="left carousel-control" href="#gallery-carousel" role="button" data-slide="prev">
    <span  aria-hidden="true"></span>
</a>

Note that, optionally, we can include a string in order to make the control for showing the previous image more accessible:

<a class="left carousel-control" href="#gallery-carousel" role="button" data-slide="prev">
    <span  aria-hidden="true">Previous</span>
</a>

These are simple anchor tags leveraging Bootstrap’s directional and carousel-control classes. The data-slide attribute indicates whether we want to cycle backward or forward through the list of slides. The data-slide can take the value prev for previous, or next. Nested within the anchor tag is a span simply applying the icon-prev and icon-next classes as directional indicators.

Finally, we declare the carousel-indicators:

<ol class="carousel-indicators">
   <li
      data-target="#gallery-carousel"
      data-slide-to="0"
      >
   </li>
   <li data-target="#gallery-carousel" data-slide-to="1"></li>
   <li data-target="#gallery-carousel" data-slide-to="2"></li>
</ol>

The indicators are bars layered on the slideshow, indicating which slide is currently active. For example, if the second slide is active, then the second bar will be filled. It is mandatory to indicate which slide is active on initialization by setting on that element. The data-slide-to attribute indicates which slide the bar relates to, so if a user clicks on a bar with data-slide-to="2", the third slide becomes active, as the count for the slides begins at 0. Some Bootstrap framework ports—for example, Angular Bootstrap, will automatically generate the carousel indicators based on the number of slides the carousel contains, but using vanilla Bootstrap, the list has to be created and maintained manually.

With that, we now have a fully-functioning carousel as our Gallery, requiring very little markup, thanks to the power of Bootstrap.

Cards

The final section we will look at in this chapter is the About section. Here, we will use Bootstrap’s card component to highlight our MyPhoto marketing blurb. Take a look at the following code:

<div class="container-fluid myphoto-section bg-myphoto-dark">
   <div class="container">
      <div class="row">
         <h3>About</h3>
         <div class="card bg-myphoto-light">
            <div >
               <p>
                  The style of photography will be customised to your 
                  personal preference, as if being shot from your own 
                  eyes. You will be part of every step of the 
                  photography process, to ensure these photos feel 
                  like your own.
               </p>
               <p>
                  Our excellent photographers have many years of 
                  experience, capturing moments from weddings to 
                  sporting events of absolute quality.
               </p>
               <p>
                  MyPhoto also provides superb printing 
                  options of all shapes and sizes, on any 
                  canvas, in any form. From large canvas 
                  prints to personalised photo albums, 
                  MyPhoto provides it all.
               </p>
               <p>
                  MyPhoto provides a full, holistic solution for all 
                  your photography needs.
               </p>
            </div>
         </div>
      </div>
   </div>
</div>

Now consider the screenshot in figure 3.11:

Figure 3.11: Using Bootstrap cards to display About information (example10.html)

There isn’t much to say about cards. The card class gives an impression of an element being inset, to draw the eye of the user and to provide a visual cue of relatively important content. It achieves this effect by the following:

  • Giving the element a 1 px border, along with a 0.25 rem border-radius to which it is applied
  • Adjusting the element’s bottom margin, forcing some space between the card element and any subsequent elements
  • Ensuring that the element’s position is relative and making the element behave as a block-level element (that is, forcing the element onto a row of its own)

Along with a card, we use card-body to provide larger padding around the content area. The card is as effective as it is simple and complements the content nicely. A card’s content can be styled using the card-text, card-title, and card-subtitle classes:

<div class="card bg-myphoto-light">
   <div class="card-body">
      <h5 class="card-title">About us</h5>
      <h6 class="card-subtitle mb-2 text-muted">
         Learn more about our website
      </h6>
      <p >
         The style of photography will be customised to your 
         personal preference, as if being shot from your own 
         eyes. You will be part of every step of the photography 
         process, to ensure these photos feel like your own.
      </p>
   </div>
</div>

Furthermore, the card-link class can be used to style links contained inside the card-body, while an image can be above the card title using the card-img-top class:

<div class="card">
    <img class="card-img-top" src="some-image.png">
    <div class="card-body">
        <h4 >About us</h4>
        ...
    </div>
</div>

Last but not least, cards can contain headers and footers:

<div class="card">
<div class="card-header">
   The About Us Header
</div>
<div class="card-body">
   <h4 class=“card-title”>About us</h4>
   ...
</div>
<div >
   Footer text
</div>
Cards in Bootstrap 3

Cards are a new concept introduced with Bootstrap 4. Prior to Bootstrap 4, cards did not exist. The feature replaced Bootstrap 3’s wells, thumbnails, and panels. To achieve a similar effect to the one demonstrated in Figure 3.10, we will use the well and well-lg classes:
<div >
<div >
<div >
<h3>About</h3>
<div >
<p>....</p>
<p>...</p>
</div>
</div>
</div>
</div>

Navbar

Bootstrap’s navbar is a powerful, responsive component to provide sensible navigation around a website. Before getting into the details, let’s add the navbar to the top of our page (right below the body tag) and see what happens:

<nav class="navbar navbar-expand navbar-light">
   <a class="navbar-brand" href="#">MyPhoto</a>
   <div class="collapse navbar-collapse">
      <ul class="navbar-nav mr-auto">
         <li class="nav-item">
            <a class="nav-link" href="#welcome"> Welcome</a>
         </li>
         <li class="nav-item"><a class="nav-link" 
            href="#services"> Services</a></li>
         <li class="nav-item"><a class="nav-link" 
            href="#gallery"> Gallery</a></li>
         <li class="nav-item"><a class="nav-link" 
            href="#about"> About</a></li>
         <li class="nav-item"><a  
            href="#contact"> Contact Us</a></li>
      </ul>
   </div>
</nav>

Take a look at the screenshot in figure 3.12:

Figure 3.12: Using Bootstrap’s navbar to provide navigational links to MyPhoto’s Welcome, Services, Gallery, About, and Contact Us sections (example11.html)

With that, we have a navigation for our single page site. Let’s break it down.

For accessibility and semantic purposes, we use the nav tag as the parent element. We can use the role="navigation" attribute on a div element, but using nav is semantically clearer (note that using both nav and role="navigation" is redundant and hence discouraged). We apply the navbar class, which is where Bootstrap starts its magic. The navbar class sets the dimensions and positioning of the navigation bar. The navbar-light property applies some styling to keep in line with Bootstrap’s default style guide.

The first element in the nav family is a navbar-brand element. This element is used to apply styling to differentiate the brand of the page, such as a specific logo or font style, to the other elements within the nav.

Inside a div with the collapse navbar-collapse classes applied (these classes allow us to hide the navbar contents using the parent breakpoint), we have a ul element. Within this ul, we nest a list of list item elements that contain the anchors to various sections on our page. Each list item element has a nav-item class applied to it; each anchor has a nav-link class. The former adjusts the element’s margin and ensures the element’s positioning within the container by setting its float property. The latter adjusts the anchor element’s styling, removing its text decoration and default colors.

If you click on Services, nothing happens. This is because we also need to update the sections with the corresponding id for each section. Let’s do that now. For example, add to the Welcome section (example12.html):

<div  >

Now, if we click on Services in the nav, the browser switches focus on the Services section.

Navigation in Bootstrap 3

The entire navbar component has been rewritten in Bootstrap 4 in an effort to make the navbar simpler and easier to use. Bootstrap 4 introduced the nav-item class for use on the list items and added the nav-link class for use with the anchor element. Neither of these two aforementioned classes exists in Bootstrap 3.

Take a look at the following screenshot:

Figure 3.13: Clicking on Services in the nav, the browser scrolls us down to the Services section. Observe how the string “#services” is appended to the URL in the address bar (example11.html)

In its current state, the navigation list wraps onto a new line, which wraps when the list is too long for the given resolution. Take a look at the following screenshot:

Figure 3.14: The navbar items wrapping onto a new line of smaller resolutions (example11.html)

This is not very Bootstrap-like. Of course, Bootstrap provides a straightforward solution for this. Bootstrap’s solution is to use the hamburger interface at lower resolutions. First, let’s add the hamburger. Within the nav element—right after the navbar-brand anchor tag—we add the following code:

<button
   class="navbar-toggler"
   type="button"
   data-toggle="collapse">
    <span ></span>
</button>

Then, replace the navbar-expand class with navbar-expand-lg. The navbar-expand-* classes use the usual (sm, md, lg, and xl) break points to show or hide the contents of the navbar, replacing it with a hamburger as shown in figure 3.15:

Figure 3.15: Adding a hamburger button to our navigation bar (example12.html)
What is a hamburger?

A hamburger, in web development, refers to a specific style of button or icon representing a list item. Represented as three horizontal and parallel lines (resembling a hamburger), a hamburger button generally surfaces navigation options when selected. The hamburger has become popular and useful for condensing navigation on small displays.

At lower resolutions, the hamburger now appears on the right-hand side. However, clicking on the hamburger button has no effect. In order to hook the hamburger and the links together, we first add an id attribute to the parent div of the links and then reference that id in a data-target attribute in the hamburger button element. Note how we also previously applied the collapse and navbar-collapse classes to the link’s parent element. These classes effectively make the navigation links disappear at smaller resolutions:

<div class="collapse navbar-collapse" >
   <button
      type="button"
      class="navbar-toggle collapsed"
      data-toggle="collapse"
      data-target="#navigation"
      aria-expanded="false">
       <span ></span>
   </button>
</div>

For accessibility purposes, we can also add aria-controls="navigation" and aria-label="Toggle navigation":

<button
    type="button"
    class="navbar-toggler"
    data-toggle="collapse"
    data-target="#navigation"
    aria-expanded="false"
    aria-controls="navigation" aria-label="Toggle navigation">
        <span ></span>
</button>

Take a look at the screenshot in figure 3.16:

Figure 3.16: Making the navigation links disappear on smaller resolutions (example12.html)

Now, on smaller viewports, the list of links is no longer visible; the hamburger icon appears, and the list of links appears once the button has been activated. This provides a much better experience on smaller resolutions.

Now that we have our sections and navigation working, let’s add a drop-down menu to our navigation to provide the user with the secondary features:  Profile, Settings, and Log Out.

To do this, we will use Bootstrap’s drop-down class. As a child of the list of section links, create a new list item element with Bootstrap’s nav-item class. As previously noted, this defines the element as a Bootstrap navigation item and renders it alongside the other items within our navbar. To the same list item, we also apply the dropdown class. Within the list element, we include an anchor tag responsible for surfacing the drop-down navigation:

<div class="collapse navbar-collapse" >
   <button
      type="button"
      class="navbar-toggle collapsed"
      data-toggle="collapse"
      data-target="#navigation"
      aria-expanded="false">
          <span ></span>
   </button>
</div>

Refer to figure 3.17:

Figure 3.17: A drop-down menu item (example13.html)

Great, it looks nice and neat. Of course, it doesn’t do anything yet. We need to create the menu we want it to surface. As a child of the Profile anchor tag, add a div element̵;;2;this time with Bootstrap’s dropdown-menu class, to denote that this is the element we want the drop-down to surface, with four list elements:

<li class="nav-item dropdown">
   <a
      href="#"
      class="nav-link dropdown-toggle"
      data-toggle="dropdown"
      role="button"
      aria-haspopup="true"
      aria-expanded="false">
          Profile <span class="caret"></span>
   </a>
   <div class="dropdown-menu dropdown-menu-right">
      <a class="dropdown-item" href="#">
          Profile
      </a>
      <a class="dropdown-item" href="#">
          Settings
      </a>
      <div class="dropdown-divider"></div>
      <a  href="#">
          Logout
      </a>
   </div>
</li>

Take a look at the screenshot in figure 3.19:

Figure 3.19: The expanded drop-down menu item, listing three subitems (example13.html)

We also add a dropdown-menu-right class to align the drop-down menu to the right. Now we have a list of links in a drop-down menu, and as you can see, we leveraged Bootstrap’s dropdown-divider class to provide a visual cue to the separation between Profile functionality and logging out of the site.

The dropdown class itself simply sets the CSS position property to relative. There are several other classes specifying how the drop-down menu, and other items within the drop-down such as the divider, look and behave. All these style definitions can be found in bootstrap/scss/_dropdown.scss. The interactions and behaviors of the drop-down component are actually handled and triggered by an out-of-the-box Bootstrap library—dropdown.js. The dropdown.js uses CSS selectors to hook into dropdown-specific elements and toggles CSS classes to execute certain behaviors. You can find the drop-down library at node_modules/bootstrap/js/dist/dropdown.js.

Drop-down menus in Bootstrap 3

Note the difference in how drop-down menus are created in Bootstrap 4. To implement the same drop-down menu functionality using Bootstrap 3, we will need another unordered-list element as a child of the Profile anchor tag. We will then only apply the dropdown-menu class. The individual menu items will be represented as list items.
Furthermore, Bootstrap 4 introduced the dropdown-divider class, replacing the Bootstrap 3 divider class. The appearance of the two is the same, however, and both serve as a visual cue to the separation between the  Profile functionality and logging out of the site.

While we have the drop-down menu entry itself working, the profile menu entry will only be visible to logged-in users, and following popular UI conventions, should be aligned to the right. To achieve this, we create a separate ul navbar for it, and pull this navbar to the right:

<ul class="navbar-nav pull-right">
    <li class="nav-item dropdown ">
        <a href="#"
            class="nav-link dropdown-toggle"
            data-toggle="dropdown"
            role="button"
            aria-haspopup="true"
            aria-expanded="false">
                Profile <span class="caret"></span>
        </a>
       <div class="dropdown-menu dropdown-menu-right">
           <a class="dropdown-item" href="#">
               Profile
           </a>
           <a class="dropdown-item" href="#">
               Settings
           </a>
           <div class="dropdown-divider"></div>
           <a  href="#">
               Logout
           </a>
       </div>
   </li>
</ul>
Figure 3.20: The expanded drop-down menu item, listing three subitems, aligned to the right (example14.html)

As nice as the dropdown is, it doesn’t actually do anything. Rather than having the user leave the page to use secondary functionality, let’s render the functionality in modal windows instead.

Modals

Bootstrap makes surfacing modal windows extraordinarily simple. It is simply a case of creating the modal markup, using Bootstrap’s modal classes, and using HTML attributes, data-toggle, data-target, and data-dismiss, to surface and remove the modal.

What is a modal window?
A modal window in web development is an element that is layered on top of the main webpage content to give the impression of a separate window, which requires user interaction and prevents the user from using the main content.

First, let’s update the profile and settings elements with the data-toggle and data-target attributes:

<a
    class="dropdown-item"
    href="#"
    data-toggle="modal"
    data-target="#profile-modal">
        Profile
</a>
<a
    
    href="#"
    data-toggle="modal"
    data-target="#settings-modal">
        Settings
</a>

We set data-toggle="modal" to tell Bootstrap that we want to open a modal, and data-target is a reference to the id of the modal we want to surface. Let’s go ahead and create these models.

As a sibling to the nav element, we add the following modal markup:

    <div class="modal" id="profile-modal" role="dialog">
   <div class="modal-dialog" role="document">
      <div class="modal-content">
         <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal"
             aria-label="Close"><span aria-hidden="true">&times;</span>
            </button>
            <h4 class="modal-title" id="profile-modal-
               label">Profile</h4>
         </div>
         <div class="modal-body">
            Profile
         </div>
      </div>
   </div>
</div>
<div class="modal" id="settings-modal" role="dialog">
   <div class="modal-dialog" role="document">
      <div class="modal-content">
         <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" 
             aria-label="Close"><span aria-hidden="true">&times;</span>
            </button>
            <h4 class="modal-title" >Settings</h4>
         </div>
         <div >
            Settings
         </div>
      </div>
   </div>
</div>

Let’s explain what is happening in this piece of code. We apply the modal class to the parent element. The ID of the element corresponds to the value of the data-target attribute of the element we want to use to surface the modal. Within that div, we use Bootstrap’s modal classes to define nested elements to represent the modal itself (modal-dialog), the content of the modal (modal-content), the header of the modal (modal-header), and the body of the modal (modal-body). We also define the title of the modal using modal-title and a Close button. The Close button includes a data-dismiss="modal" attribute, which allows the user to close the modal just by clicking anywhere off the modal. Let’s take a look at how the Profile modal renders. Take a look at the following screenshot:

Figure 3.20: Using Bootstrap’s modal to display an empty dialog (example15.html)

That’s pretty nice, considering that it required very little markup.

We have a pretty nice navigation in place now; well, a functional navigation. It does not really fit in well with the rest of our site, though. Let’s create our own custom navigation style for MyPhoto.

Styling

Bootstrap’s navbar comes with two built-in styles: navbar-light, which we currently use, and navbar-dark. To add a new style, we can add a new class to _navbar.scss, add new color variables to _variables.scss, recompile Bootstrap, and then apply the class to our navbar element. However, applying changes directly to Bootstrap source files is a bad practice. For instance, we use Node to add Bootstrap, along with other third-party components, to our project. If we were to add new styles to Bootstrap source files, we would need to add Bootstrap to our repository and use that version, instead of Node, or else other developers on your team would not get the changes. Also, if we wanted to use a new version of Bootstrap, even a minor or patch release, it would force us to reapply all our custom changes to that new version of Bootstrap.

Instead, we will apply the changes to the MyPhoto style sheet. Add the following rules to myphoto.css:

.navbar-myphoto {
    background-color: #504747;
    border-color: black;
    border-radius: 0;
    margin-bottom: 0px;
}
.navbar-myphoto .navbar-brand {
    color: white;
    font-weight: bold;
}
.navbar-myphoto .nav-item > .nav-link {
    color: white;
}
.navbar-myphoto .nav-item > .nav-link:hover {
    background-color: #504747;
    color: gray;
}
.navbar-myphoto .nav-pills > li.active > a {
    background-color: #504747;
    color: gray;
}
.navbar-myphoto .dropdown-menu {
    background-color: #504747;
    border-color: black;
}
.navbar-myphoto .dropdown-menu > a {
    color: white;
    background-color: #504747;
}
.navbar-myphoto .dropdown-menu > a:hover {
    color: gray;
    background-color: #504747;
}
.navbar-myphoto .dropdown-menu > a:focus {
    color: gray;
    background-color: #504747;
}
.navbar-myphoto .dropdown-menu > .active > a:focus {
    color: gray;
    background-color: #504747;
}
.navbar-myphoto > .navbar-toggler {
    color: white;
}
.nav-pills > .active > a, .nav-pills > .active > a:hover {
    background-color: grey;
}
.nav-pills .nav-link.active, .nav-pills .nav-link.active:focus, .nav-pills .nav-link.active:hover,
.nav-pills .nav-item.open .nav-link,
.nav-pills .nav-item.open .nav-link:focus,
.nav-pills .nav-item.open .nav-link:hover {
    background-color: grey;
}
.navbar-myphoto>.navbar-toggler {
    color: white;
    border: 1px solid rgba(255, 255, 255, 0.5);
}
.navbar-myphoto .navbar-toggler-icon {
    background-image: url("data:image/svg+xml;charset=utf8,
        <svg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'>
            <path stroke='rgba(255, 255, 255, 0.5)' stroke-width='2'             stroke- linecap='round' stroke-miterlimit='10' d='M4 7h22M4             15h22M423h22'/>
        </svg>
    ");
}

We have added a new class, navbar-myphoto. The navbar-myphoto class uses the same dark background as bg-myphoto-dark and removes the margin-bottom navbar applied by default. We then have to apply rules for the classes that are usually nested within a navbar element. We apply font and background rules across these classes, in their various states, to keep in line with the general style of MyPhoto. These rules can be made more succinct using a preprocessor, but we will not add that complexity to this project. Last but not least, we have added styles to prevent the hamburger icon from becoming invisible.

In the markup, replace navbar-light with navbar-myphoto. Take a look at the screenshot in figure 3.21:

Figure 3.21: The custom-styled navigation bar with drop-down (example16.html)

With these new styles, we now have a style-appropriate navbar for MyPhoto; that’s pretty neat.

Last but not least, let’s try and improve the overall look and feel of our website by adding some nice fonts. We will use two freely available Google Fonts. Specifically, we will use Poiret One (https://www.google.com/fonts/specimen/Poiret+One) for our navbar and headers and Lato (https://www.google.com/fonts/specimen/Lato) for everything else. To be able to use these fonts, we must first include them. Insert the following two lines into the head of our index.html:

<link href="https://fonts.googleapis.com/css?family=Poiret+One" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Lato& subset=latin,latin-ext" rel="stylesheet" type="text/css">

Then, insert the following lines of code into myphoto.css:

h1, h2, h3, h4, h5, h6, .nav, .navbar { 
    font-family: 'Poiret One', cursive;
}
body {
    font-family: 'Lato', cursive;
}

Take a look at the screenshot in figure 3.22:

Figure 3.22: MyPhoto styled using Google Fonts: Poiret One and Lato (example16.html)

Comments are closed.