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, let us add Bootstrap's JavaScript library. Bootstrap's JS relies upon jQuery UI, so let us add that too. Note that Bootstrap JS is not required for all the components we are going to use here, but it is best to get the setup out of the way. Install jQuery using Bower:

    bower install jquery

Add the following code to the head of your page:

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

With that, we're ready to use any Bootstrap component in our page.

Jumbotron

The first component we are going to integrate is Bootstrap's jumbotron.

The jumbotron component is essentially a very simple visual cue to 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 class="jumbotron">
                <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:

Jumbotron

Figure 3.4: The Bootstrap jumbotron class to create a banner welcoming the user to MyPhoto

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 as 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 class="jumbotron jumbotron-welcome">

Take a look at the following screenshot:

Jumbotron

Figure 3.5: Using Sao Paulo's skyline as a background image for MyPhoto's welcome banner

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 class="jumbotron">
                <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.

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 build the services into three separate interfaces, we are going to 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:

    <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" class="nav-
            link">
            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 element (ul) 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 a 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 instead appear next to one another). 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:

Tabs

Figure 3.6: Using tabs components to build out the MyPhoto's Services section

Note

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 element (ul) 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 a href to the relevant tab content.

The active class is applied to the default selected list item:

<ul class="nav nav-tabs nav-justified" role="tablist">   
<li role="presentation" class="active"><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" id="services-prints">
        <div class="m-x-auto" style="width:50%">
          <h1 class="bg-primary text-xs-center">Special Offers</h1>
        </div>
        <div class="container">
          <h1 class="hidden-lg-down">Our Print Sizes</h1>
            <div class="row">
              <div class="col-xs-6 col-sm-3 push-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 push-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-xs-6 col-sm-3 push-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-xs-6 col-sm-3 pull-sm-9">
                <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 pull-xs-right">
         <p class="label">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 the Prints tab will surface Our Print Sizes chart. We have modified the print sizes chart for its new context within the tabs component. Take a look at the following screenshot:

Tabs

Figure 3.7: Adding tab content using the tab-pane class

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 like the following:

Tabs

Figure 3.8: Improving the look and feel of our tabs by setting the tab title color to white

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 are going to 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">
        <div class="row">
          <h3>Gallery</h3>
          <div id="gallery-carousel" class="carousel slide"
          data-ride="carousel" data-interval="3000">
            <div class="carousel-inner" role="listbox">
              <div style="height: 400px" class="carousel-item active">
                <img src="images/brazil.png">
                <div class="carousel-caption">
                  Brazil
                </div>
              </div>
              <div style="height: 400px" class="carousel-item">
                <img src="images/datsun.png">
                <div class="carousel-caption">
                  Datsun 260Z
                </div>
              </div>
              <div style="height: 400px" class="carousel-item">
                <img 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" class="active"></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>
    </div>

Take a look at the following screenshot:

Carousel

Figure 3.9: Using the Bootstrap carousel to display a gallery of images. Note the arrows at both sides of the images. These are the carousel controls that allow users to navigate the image gallery.

Now, we have a fully functioning, three-slide gallery. Let's breakdown what is happening here.

Note

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 class="left carousel-control" href="#gallery- carousel" role="button" data-slide="prev">   
  <span class="glyphicon glyphicon-chevron-left" aria-   hidden="true"></span> </a> 
  <a class="right carousel-control" href="#gallery- carousel" role="button" data-slide="next">   
  <span class="glyphicon glyphicon-chevron-right" aria-   hidden="true"></span> 
</a>

First, we declare the carousel parent tag:

    <div id="gallery-carousel" class="carousel slide" 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 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 src="images/image1.png">
        <div class="carousel-caption">
          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 class="icon-prev" aria-hidden="true"></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 class as a directional indicator.

Finally, we declare the carousel-indicators:

    <ol class="carousel-indicators">
      <li data-target="#gallery-carousel" data-slide-to="0" 
      class="active"></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 circles layered on the slideshow, indicating which slide is currently active. For example, if the second slide is active, then the second circle will be filled. It is mandatory to indicate which slide is active on initialization by setting class="active" on that element. The data-slide-to attribute indicates which slide the circle relates to, so if a user clicks a circle 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, with very little markup, thanks to the power of Bootstrap.

Cards

The final section we are going to look at in this chapter is the About section. Here, we are going to 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 class="card-block">
          <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>

Take a look at the following screenshot:

Cards

Figure 3.10: Using Bootstrap cards to display About information

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:

  • 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-block to provide larger padding around the content area. The card is as effective as it is simple, and complements the content nicely.

Now that our sections have some content, we need to add some navigation and branding. To do this, we are going to leverage Bootstrap's navbar component.

Note

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 would use the well and well-lg classes:

    
<div class="container-fluid myphoto-section bg-
    myphoto-dark">       
	<div class="container">         
	 <div class="row">           
	   <h3>About</h3>           
	   <div class="well well-lg bg-myphoto-light">             
	      <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 it to our page and see what happens:

    <nav class="navbar navbar-light">
      <a class="navbar-brand" href="#">MyPhoto</a>
      <ul class="nav navbar-nav">
        <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 class="nav-link" href="#contact">
        Contact Us</a></li>
      </ul>
    </nav>

Take a look at the following screenshot:

Navbar

Figure 3.11: Using Bootstrap's navbar to provide navigational links to MyPhoto's Welcome, Services, Gallery, About, and Contact Us sections

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 could use the role="navigation" attribute on a div element, but using nav is semantically clearer. 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.

We then have a ul element as a sibling to navbar-brand. 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 id="services" to the Welcome section:

    <div class="container-fluid myphoto-section bg-myphoto-
    welcome" id="services">

Now, if we click on Services in the nav, the browser scrolls us down to the Services section.

Note

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 exist in Bootstrap 3.

Take a look at the following screenshot:

Navbar

Figure 3.12: 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.

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:

Navbar

Figure 3.13: The navbar items wrapping onto a new line on smaller resolutions

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, we add the following code:

    <button class="navbar-toggler hidden-sm-up pull-xs-right" 
    type="button" data-toggle="collapse" data-target="#navigation">
    ☰
    </button>

Take a look at the following screenshot:

Navbar

Figure 3.14: Adding a hamburger button to our navigation bar

Note

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 navigations on small displays.

At lower resolutions, the hamburger now appears on the right-hand side. However, our list of sections still wraps onto a new line and the hamburger button has no effect. In order to hook the hamburger and the links together, first we 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. We also apply 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" id="navigation">
      <button type="button" class="navbar-toggle collapsed" 
      data-toggle="collapse" data-target="#navigation" 
      aria-expanded="false">

Take a look at the following screenshot:

Navbar

Figure 3.15: Making the navigation links disappear on smaller resolutions

When a user clicks on the hamburger, the navigation menu will be surfaced. Take a look at the following screenshot:

Navbar

Figure 3.16: Making the navigation links visible on smaller resolutions by clicking the hamburger menu

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 are going to use Bootstrap's dropdown 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 and pull-xs-right class (recall that the latter aligns the list item element to the right of the container). Within the list element, we include an anchor tag, responsible for surfacing the drop-down navigation:

    <li class="nav-item dropdown pull-xs-right">
      <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="#" data-toggle="modal" 
        data-target="#profile-modal">
          Profile
        </a>
      </div>
    </li>

Take a look at the following screenshot:

Navbar

Figure 3.17: A drop-down menu item

Great, it looks nice and neat on the right-hand side of our page. 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, this time with Bootstrap's dropdown-menu class, to denote this is the element we want the dropdown to surface, with four list elements:

    <li class="nav-item dropdown pull-xs-right">
      <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="#" data-toggle="modal"
        data-target="#profile-modal">
          Profile
        </a>
        <a class="dropdown-item" href="#" data-toggle="modal" data-target=
        "#settings-modal">
          Settings
        </a>
        <div class="dropdown-divider"></div>
        <a class="dropdown-item" href="#">
          Logout
        </a>
      </div>
    </li>

Take a look at the following screenshot:

Navbar

Figure 3.18: The expanded drop-down menu item, listing three sub-items

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've 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 dropdown 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 dropdown library at bower_components/bootstrap/js/dist/dropdown.js.

Note

Drop-down menus in Bootstrap 3

Notice the difference in how drop-down menus are created in Bootstrap 4. To implement the same drop-down menu functionality using Bootstrap 3, we would need another unordered-list element as a child of the Profile anchor tag. We would then only apply the dropdown-menu class. The individual menu items would 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 Profile functionality, and logging out of the site.

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

Note

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.

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.

First, let's update the Profile and Settings element with the data-toggle and data-target attributes:

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

We set data-toggle="modal" to tell Bootstrap 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 modals.

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" id="settings-modal-label">Settings</h4>
          </div>
          <div class="modal-body">
            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:

Navbar

Figure 3.19: Using Bootstrap's modal to display an empty dialog

Pretty nice, considering 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 could 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 bad practice. For instance, we use Bower 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 Bower, 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 are going to apply the changes to the MyPhoto stylesheet. Add the following rules to myphoto.css:

    .navbar-myphoto {
      background-color: #2A2A2C;
      border-color: black;
      border-radius: 0;
      margin-bottom: 0px;
    }
    .navbar-myphoto.navbar-brand {
      color: white;
      font-weight: bold;
    }
    .navbar-myphoto.navbar-nav > li > a {
      color: white;
    }
    .navbar-myphoto.navbar-nav > li > a:hover {
      background-color: #2A2A2C;
      color: gray;
    }
    .navbar-myphoto.navbar-nav > li > a:focus {
      background-color: #504747;
      color: gray;
    }
    .navbar-myphoto.navbar-nav > 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;
    }

We have added a new class, navbar-myphoto. The navbar-myphoto 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 inline with the general style of MyPhoto. These rules could be made more succinct using a preprocessor, but we are not going to add that complexity to this project.

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

Styling

Figure 3.20: The custom-styled navigation bar with drop-down

With these new styles, we now have a style-appropriate navbar for MyPhoto. 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="http://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 following screenshot:

Styling

Figure 3.21: MyPhoto styled using Google Fonts: Poiret One and Lato

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset