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.
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:
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:
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.
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:
inline-block
. This has two important effects on the 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:
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:
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:
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.
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:
Now, we have a fully functioning, three-slide gallery. Let's breakdown 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 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.
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:
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:
card
element and any subsequent elementsAlong 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.
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>
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:
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.
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:
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:
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:
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:
When a user clicks on the hamburger, the navigation menu will be surfaced. Take a look at the following screenshot:
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:
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:
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
.
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.
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">×</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">×</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:
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
.
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:
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: