Our next section, named Impact, presents reviews from happy customers. In this section, we see smiling faces of happy customers with excerpts of their commentary about our client's product. The initial markup starts as follows:
<!-- IMPACT SECTION --> <section id="impact"> <div class="container"> <h1>Impact</h1> <div class="reviews">
Each review is marked up as follows using the hreview
microformat:
<div class="hreview review-item-1 thumbnail"> <img src="img/smiling1-by-RomainGuy-600x900.jpg" alt="Customer Photo1"> <div class="caption"> <blockquote class="description"><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, nulla pretium commodo ultricies</p></blockquote> <p class="reviewer">Smiling Customer1</p> </div><!-- /.caption --> </div><!-- /.hreview -->
You may read about the hreview
microformat at http://microformats.org/wiki/hreview-examples.
For purposes of layout and style, we've employed Bootstrap's thumbnail class structure. This structure offers us the following benefits:
This thumbnail and caption structure provides an overall wrapper for each review. Bootstrap's thumbnail styles are designed to constrain the proportions of images and captions within our desired layout.
Both in terms of semantics and presentational starting points, we're off to a good start.
Because we want to arrive at a masonry layout, our images are a mixture of portrait and landscape aspect ratios. We've made them all of equal width in order to provide enough room for bright faces and textual overlays with short laudatory statements.
Without Bootstrap layout classes, the images simply flow vertically, one after another. If you constrain your window width to a value approximately in the range of 320 to 400px, you can see how they will look as one narrow vertical column, as shown in the following screenshot:
Before addressing the layout for larger viewports, let's start by tackling the captions.
Let's begin by positioning our captions as overlays atop their respective customer photos:
_page-contents.less
file, add a new comment and selector for the #impact
section:// Impact Section #impact { }
.hreview
class element. We'll apply relative positioning, add padding, and remove the default Bootstrap thumbnail border:#impact { .hreview { position: relative; padding: 0 10px; border: none; } }
absolute
at the bottom of each image:.hreview { ... .caption { position: absolute; top: auto; left: 10px; right: 10px; bottom: 0; line-height: 1.1; background: hsla(0,0,10%,0.55); }
blockquote
and .reviewer
elements, specifying just what we need:#impact .hreview { ... .caption { ... blockquote, .reviewer { margin: 0 6px; padding: 0; }
blockquote { margin-top: 4px; border: none; font-family: @font-family-serif; font-size: @font-size-large; color: #fff; }
... .reviewer { margin-top: 2px; margin-bottom: 4px; text-align: right; color: @gray-lighter; }
Scroll down and see how the results look in the other review items.
Looking carefully at the available open space in the preceding images and examining the overlap variations at various viewport widths in your responsive grid, you may want to position each caption in a way that works best for each customer's photo.
This is where the review-item-1
, review-item-2
, and so on classes become relevant and helpful, as we may use these specific classes to position each caption in a way that fits best with its image. I've added the following lines in the _page-contents.less
file:
#impact { .review-item-4 .caption { top: 0; left: 62%; right: 10px; bottom: auto; .reviewer { margin-top: 6px; text-align: left; } } .review-item-5 .caption { top: 0; left: 17%; right: 10px; bottom: auto; } }
The preceding markup adjusts the absolute positioning of each specific caption, which yields results as shown in the following screenshot:
You'll see that I've applied specific positioning values from lines 132 and onwards in the less/_page-contents.less
file in the 06_Code_END
folder in this chapter's exercise files. As you survey the results, you may disagree with my judgment calls—about positioning, styling, or both. That's fine. Take over and fine-tune from here!
Meanwhile, let's move on toward our masonry layout. The first step will be to specify the widths of our elements. Let's utilize Bootstrap's grid classes for this.
By utilizing Bootstrap's responsive grid classes, we can prepare a two-column layout for small screens using the col-sm-6
class. For medium screens and up, we can shift to a three-column layout using the col-md-4
class.
The resulting class structure for each hreview
element will look like the following line:
<div class="hreview review-item-1 thumbnail col-sm-6 col-md-4">
Add these two column classes to each review item.
Save the file, refresh your browser, and expand your window across the small and medium breakpoints. You'll see a result similar to the following screenshot for small viewports:
For medium viewports and higher, you'll see a result similar to the following screenshot:
In the features section discussed earlier, we discovered that when we have grid items of varying heights, they bump into one another and do not automatically create a cohesive grid. We fixed this by giving each element a set height value. But in this section, we want our items to have varying heights. We want a masonry layout, and this requires a bit of JavaScript.
A masonry layout utilizes JavaScript to assess available spaces and fill those spaces with the elements that fit them best, with the goal of producing nicely tiled columns from building blocks of varying heights.
To implement masonry in this design, we'll utilize the excellent JavaScript plugin named Masonry, which has been developed and maintained by David DeSandro:
masonry.pkgd.min.js
.masonry.pkgd.min.js
in your editor and copy its entire contents.js/plugins.js
. Paste the masonry code with its opening comments just after the end of Bootstrap's JavaScript lines.Recall that the plugins.js
file is already linked to your index.html
file. Similarly, we've added masonry to our page's available scripts! (While we've added some file size, we have not added any new HTTP requests.)
We'll now initialize masonry in our page using HTML attributes.
For Masonry documentation, check http://masonry.desandro.com/#getting-started.
In the index.html
file, perform the following steps:
js-masonry
class to div class="reviews"
, which is the parent of all of our review items. This lets masonry know where to do its work.<div class="reviews js-masonry" data-masonry-options='{"itemSelector": ".hreview" }'
>
This tells masonry which elements to arrange in the masonry layout. We've specified the hreview
class (though we could have used thumbnail
).
index.html
and refresh your browser. You can see that the gaps that existed earlier disappeared as soon as the masonry filled them in.The result for a small viewport (for which we've specified a two-column layout using col-sm-6
) is shown in the following screenshot:
And the following is the result in a medium or large viewport:
Take a geek break by resizing your browser window back and forth across the small and medium breakpoints. Watch the review items reorganize themselves into two or three columns with the animation provided by Masonry.js
!
We're very close to accomplishing our client's desired result. However, one of our remaining problems is that we've possibly mismeasured the size of our images. In a small two-column layout, the image that says Smiling Customer5 sticks out just a bit. In the medium and large three-column layout, the image sticks out even more. We could take the image out, but the review of the customer in that image is one of our client's favorites, and she loves this image. So, we're going to make this image fit properly in the viewport.
Thankfully, we have been given permission to do some trimming. And if push comes to shove, other customers are expendable. This gives us something to work with. Let's begin by fixing the three-column layout:
_page-contents.less
open in your editor, begin a new section with a comment at the top:// Cutting and trimming for masonry layout
#impact
section. Within the first query, we'll remove the image that says Smiling Customer4 from the layout, as shown in the following lines of code:#impact { @media (min-width: @screen-md-min) { .review-item-4 { display: none; } } }
Now let's adjust the image in the two-column layout.
We need to slice these pixels only for the small layout—not extra-small and not medium or large. Thus, we'll need both minimum and maximum values in our media query. Adding this media query below the first query, we can accomplish our goals as shown in the following lines of code:
@media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) { .review-item-5 { height: 474px; overflow: hidden; img { width: 100%; } } }
By adding these lines, we have performed the following:
review-item-5
div to precisely 474 pixels so that it will share the same bottom edge with its neighboring itemThe result works nicely! The following screenshot shows the desired result:
We're looking great!
It seems that Bootstrap's responsive grid and masonry's layout magic has combined to form a nasty concoction for tiny viewports—at least in some browsers. In my browser, images grow huge and no longer stay constrained.
This is because Bootstrap's col-sm-
and col-lg-
classes no longer apply at this tiny dimension. As a result, our hreview
thumbnails and their images have gone completely unconstrained by any specification of width.
At this point, we could do one of the following two things:
col-12
to each review itemThe choice is up to you. As for me, at this point in the flow of things, I'd rather take the second option.
To do so, I'll simply add one more media query in the _page-contents.less
file:
@media (max-width: @screen-xs-max) {
Within this media query, let's limit the max-width
property of div class="reviews"
to 400px—a width that leaves our images large enough without allowing them to expand too large. Then, let's use the .center-block()
mixin to center align the reviews using auto
left and right margins as shown in the following lines of code:
#impact { @media (max-width: @screen-xs-max) { .reviews { max-width: 400px; .center-block(); } } }
Save the file and then refresh your browser.
Voila! The customer reviews are now performing exactly according to our client's desires.
Now to take care of the last major item in our client's desired home page design: the pricing tables.