Preface
Step Eight: Numerator and Progress Bar using Bootstrap Class.
One simple thing you can do to enhance your simple blog is animation. Doing this with tailor made class is relatively easy. But integrating using native bootstrap require an extra miles.
In real life web development, we need to combine bootstrap with other method, such custom javascript, custom component and stuff.
1: Chapter Overview
We have to know how animation works, before combine it with bootstrap class.
Source Code: Step-08
The source code for this chapter is, available for download at the following link:
Related Articles
This bootstrap specific class article is based on, animation observer article series.
That article above is Bulma based, and I found out that migrating into using Bootstrap classes, require a lot of changes. So I decide to create an article for this, specifically for bootstrap.
Intersection Observer
Required knowledge
In addition with the animation, I also automate the animation using observer.
The method has an API called intersection observer
The MDN explanation is good. But when I need a real life example I search.
After duckduckwent for a while, I found this simple, but good example.
And that’s it!
Javascript Assets
We have a bunch of additional javascript. I invite you to inspect the code yourself on my GitHub repository.
❯ tree js
js
├── animate-observer.js
├── animate-observer.md
├── bootstrap.min.js
├── custom-toggler.js
├── numerator.js
├── numerator.md
├── observer-bounce.js
├── popper.min.js
└── progressbar.js
1 directory, 9 files
Stylesheet Assets
And each javascript have their related stylesheet. You can examine the code yourself from my github repository.
❯ tree css
css
├── animate.css
├── animate-zoom.css
├── bootstrap.css
├── bootstrap.css.map
├── helper.css
├── helper.css.map
├── hover-buzz.css
├── hover.css
├── main.css
├── main.css.map
└── progressbar.css
1 directory, 11 files
Note that I do not use SASS here. Just plain stylesheet for simplicity reason.
Nunjucks Directory Structure
We are going to use the javascript and stylesheet, in different article step by step.
Rather than providing an exhaustive analysis of each file, I invite you to inspect the code yourself on my GitHub repository
❯ tree -C views
views
├── 081-custom.njk
├── 082-library.njk
├── 083-observe.njk
├── 084-widget.njk
├── 085-numerator.njk
├── 086-progressbar.njk
├── aside
│ ├── 084-widget-01.njk
│ └── 084-widget-02.njk
├── chunks
│ ├── 085-numerator.njk
│ └── 086-progressbar.njk
├── contents
│ ├── 081-main.njk
│ ├── 082-main.njk
│ ├── 083-main.njk
│ ├── 084-main.njk
│ ├── 085-main.njk
│ └── 086-main.njk
├── heads
│ ├── 081-links.njk
│ ├── 082-links.njk
│ ├── 083-links.njk
│ ├── 084-links.njk
│ ├── 085-links.njk
│ ├── 086-links.njk
│ ├── common-links.njk
│ └── common-meta.njk
├── layouts
│ └── base.njk
└── shared
├── footer.njk
├── navbar-button.njk
├── navbar-collapse.njk
├── navbar-dropdown.njk
└── navbar.njk
7 directories, 30 files
Reusable Templates
For this section, we have some reusable nunjucks templates.
- Layout: Parent Template
- HTML Head: Meta and Links
- Header and Footer
The parent template, header and footer, has been discussed many times. No need to touch these files over and over again. But I need to show the common HTML head.
Nunjucks: Common Meta
HTML Head: Reusable Meta
For this section we have the same HTML meta. All we need is just title.
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,
initial-scale=1, shrink-to-fit=no">
<title>I Won't Be On Holiday.</title>
Nunjucks: Common Assets Links
Also from the previous post, we have this link setup:
<link rel="stylesheet" type="text/css"
href="assets/css/bootstrap.css">
<link rel="stylesheet" type="text/css"
href="assets/css/main.css">
<link rel="stylesheet" type="text/css"
href="assets/css/helper.css">
<script src="assets/js/popper.min.js"></script>
<script src="assets/js/bootstrap.min.js"></script>
Now we are ready to enhance each step with additional assets and stuff.
2: Custom
Your own stylesheet
Animation can be made using CSS only, to make simple animation. And you can make your own tailor made stylesheet, without any third party library.
Preview in Browser
This is what javascript animate observer that we want to achieve. To make it easier for you to get the idea, you can examine the video below.
Nunjucks: Links
This is our additional assets.
<link rel="stylesheet" type="text/css"
href="assets/css/hover-buzz.css">
<link rel="stylesheet" type="text/css"
href="assets/css/animate-zoom.css">
Nunjucks: Main Content
Using the stylesheet in HTML document can be shown as below:
<main class="col px-0">
<div class="zoomOut"
id="sitedesc_image"></div>
<section class="main-wrapper single blue">
<div class="blog white z-depth-3 hoverable">
...
<img src="assets/images/one-page.png"
class="zoomIn_hover"
alt="business card">
...
</div>
</section>
</main>
That’s all.
Related Articles
This animation is using custom tailor made library. There is another article that discuss, how to set up this animation.
I don’t think that I need to go in detail for this section. You can examine the check the article below as a guidance.
We need to move on to use animation library.
3: Library
With Specific Observer
Instead of reinventing the wheel, we can utilize a ready to use animation library.
So how to bind the observer script to animation style class? We can modify the example above and apply to our simple need.
Preview in Browser
Here is the desired output of our Javascript animate observer. To assist you in understanding the concept, you may refer to the video provided below.
Nunjucks: Links
This is our additional assets.
<link rel="stylesheet" type="text/css"
href="assets/css/hover.css">
<link rel="stylesheet" type="text/css"
href="assets/css/animate.css">
<script src="assets/js/observer-bounce.js"></script>
Nunjucks: Main Content
Using the stylesheet in HTML document can be shown as below:
<main class="col px-0">
<div class="animate__animated animate__rubberBand"
id="sitedesc_image"></div>
<section class="main-wrapper single blue">
<div class="blog white z-depth-3 hoverable">
...
<img src="assets/images/one-page.png"
class="animate__animated animate__bounce
animate__observe__bounce"
alt="business card">
...
</div>
</section>
</main>
Javascript: Custom Observe
The issue with above example is, the animation is show once and then stop. We can make it better by repeat the animation, if the element displayed by scrolling.
To trigger this, we need to use intersection observe method.
I’m using native javascript.
document.addEventListener(
"DOMContentLoaded", function(event) {
let bounceObserver =
new IntersectionObserver( (entries) => {
entries.forEach((entry) => {
const cl = entry.target.classList;
if (entry.intersectionRatio > 0) {
cl.add('animate__bounce');
} else {
cl.remove('animate__bounce');
}
});
});
const bouncesToObserve = document
.querySelectorAll(".animate__observe__bounce");
bouncesToObserve.forEach((element) => {
bounceObserver.observe(element);
});
});
The Issue
This approach has a few issue. I should write this long procedure for each effect. And the javascript become unbearable longer.
Related Articles
This animation is using third party library. There is another article that discuss, how to set up this animation.
Again, I don’t think that I need to go in detail for this section. You can examine the check the article below as a guidance.
4: Observer
Generic Observer
We can make the observer more generic, so that we can glue the observer with animation library.
Preview in Browser
The preview is almost the same.
The difference is the code inside.
Nunjucks: Links
This is our additional assets.
<link rel="stylesheet" type="text/css"
href="assets/css/hover.css">
<link rel="stylesheet" type="text/css"
href="assets/css/animate.css">
<script src="assets/js/animate-observer.js"></script>
Nunjucks: Main Content
Instead of class, I store the animation name in dataset. So we can have different effect freely.
For example, this use rubberBand
animation.
And this one use bounce
animation.
<main class="col px-0">
<div class="animate__animated animate__observe"
data-animate="rubberBand"
id="sitedesc_image"></div>
<section class="main-wrapper single blue">
<div class="blog white z-depth-3 hoverable">
...
<article
class="blog-body text-center"
itemprop="articleBody">
...
<img src="assets/images/one-page.png"
class="animate__animated animate__observe"
data-animate="bounce"
alt="business card">
...
</article>
</div>
</section>
</main>
Note that I still need to add this animate__observe
class.
Javascript: Generic Observe
First to do is to write down all selected effect in an array. Only what I might need, and exclude the rest. This means you can write down your own effect.
I’m still using native javascript, as usual.
document.addEventListener(
"DOMContentLoaded", function(event) {
// only what I might need, and exclude the rest.
const effects = [
'bounce', 'rubberBand', 'wobble', 'swing',
'rollIn', 'zoomIn', 'flash', 'flip', 'pulse',
'slideInLeft', 'slideInRight', 'headShake'
];
let elementObserver =
new IntersectionObserver( (entries) => {
entries.forEach((entry) => {
const el = entry.target;
const animate = el.dataset.animate;
if (effects.includes(animate)) {
const effect = 'animate__' + animate;
if (entry.intersectionRatio > 0) {
el.classList.add(effect);
} else {
el.classList.remove(effect);
}
}
});
});
const elementsToObserve = document
.querySelectorAll(".animate__observe");
elementsToObserve.forEach((element) => {
elementObserver.observe(element);
});
});
Related Articles
Rather than providing an exhaustive analysis of each file, I invite you to inspect the code yourself on article below:
5: Animating Widget
Apply to other page as well.
Once we settle with triggering animation sing animate observer, we can apply to any animation.
One of my favorite is animating the whole blog page. A blog page consist of the content and the widget.
I usually use zoomIn
effect,
but for this tutorial purpose,
I will use slide-in effect.
- slideInLeft for blog content.
- slideInRight for widget.
- Addtional hover effect.
Preview in Browser
Enjoy the result
This is the result that we want to achieve.
Nunjucks: Main Content
Using the stylesheet in HTML document can be shown as below:
<main class="col-md-8 px-0
animate__animated animate__observe"
data-animate="slideInLeft">
...
</main>
Nunjucks: Aside
Using the stylesheet in HTML document can be shown as below:
<section class="aside-wrapper green
animate__animated animate__observe"
data-animate="slideInRight">
<...
</section>
This is all we need to know.
6: Numerator
Goal: Trigger animation on scroll using intersection observer.
Instead of using ready made animation, we can be brave enough to make our own custom animation. Such as this two cases.
- Javascript only, no stylesheet.
- Animation in stylesheet.
Preview in Browser
This is the result that we want to achieve.
It is always nice to animate statistic in your blog.
Original Source
Javascript only, no stylesheet.
I have seen jquery
numerator,
and I want the native one.
Luckily I found this one.
I use this source code, with a simple modification, to suit my need.
Nunjucks: Links
This is our additional assets.
<link rel="stylesheet" type="text/css"
href="assets/css/hover.css">
<link rel="stylesheet" type="text/css"
href="assets/css/animate.css">
<script src="assets/js/animate-observer.js"></script>
<script src="assets/js/numerator.js"></script>
Nunjucks: Numerator
The numerator is a pure bootstrap row
and cols
classes.
<div class="container">
<div class="row">
<div class="col-sm">
<p class="text-muted text-uppercase"
><small>Code</small></p>
<p class="h3 numerator"
data-number="8"
>0</p>
</div>
...
</div>
</div>
Javascript: Numerator
First to do is to write down all selected effect in an array. Only what I might need, and exclude the rest. This means you can write down your own effect.
I’m still using native javascript, as usual.
document.addEventListener(
"DOMContentLoaded", function(event) {
const ...
let counterObserver =
new IntersectionObserver( (entries) => {
entries.forEach((entry) => {
if (entry.intersectionRatio > 0) {
const ...
const animate = () => {...}
animate();
}
});
});
countersToObserve.forEach((element) => {
counterObserver.observe(element);
});
});
I know this is a long script.
It is home made. And I open for better enhancement.
Preview in Browser
Again, enjoy the result. We can see the result in a wider view.
Related Articles
But how does it works?
The detail of how it works can be read in this article below:
7: Progressbar
Animation in stylesheet: Franken Component
I grab other html code from w3school, then rewrite using bootstrap class. But I wrote the javascript myself. I know it is rather a frankenstein, but it works, at least for me.
Preview in Browser
Nunjucks: Links
This is our additional assets.
<link rel="stylesheet" type="text/css"
href="assets/css/hover.css">
<link rel="stylesheet" type="text/css"
href="assets/css/animate.css">
<link rel="stylesheet" type="text/css"
href="assets/css/progressbar.css">
<script src="assets/js/animate-observer.js"></script>
<script src="assets/js/numerator.js"></script>
<script src="assets/js/progressbar.js"></script>
Stylesheet: Progress Bar Animation
We can breakdown each stylesheet.
The keyframes is very simple.
@keyframes my__progress__frames {
from { width: 0%; }
to { width: 100%; }
}
The animation is
.progress-bar {
animation-duration: 5s;
animation-fill-mode: both;
animation-name: my__progress__frames;
animation-iteration-count: 1;
animation-timing-function: ease;
animation-direction: normal;
}
And additional cosmetics.
.my__progressbar_text {
white-space: nowrap;
}
.progress {
height: 13px;
border-radius: 7px;
}
Nunjucks: Progressbar
The progressbar is a pure bootstrap progress-bar
class.
- [gitlab.com/…/views/chunks/086-progressbar.njk][njk-086-c-progressbar]
<div class="my__progressbar" data-count="8">
<div class="my__progressbar_text"
>Code: <span class="my__progressbar_perc"
></span></div>
<div class="progress hoverable">
<div class="progress-bar progress-bar-striped
progress-bar-animated blue"
role="progressbar"></div>
</div>
</div>
<div class="my__progressbar" data-count="3">
...
</div>
<div class="my__progressbar" data-count="15">
<...
</div>
<div class="my__progressbar" data-count="82">
...
</div>
<div class="my__progressbar" data-count="3">
...
</div>
Note that I also set the total count. Sum of all element, on the first place.
It become complex, because we have to combine with bootstrap class.
Javascript: Progressbar
We need to make custom javascript:
document.addEventListener(
"DOMContentLoaded", function(event) {
const progressbars = document
.querySelectorAll(".my__progressbar");
const myBars = document
.querySelectorAll(".progress-bar");
const containerBar = document
.getElementById("container__bar");
const total = containerBar.dataset.count;
let containerBarObserver =
new IntersectionObserver( (entries) => {
entries.forEach((entry) => {
...
});
});
containerBarObserver.observe(containerBar);
});
I know this is script is longer.
Preview in Browser
Enjoy the result.
Related Articles
For a more in-depth understanding of how it operates, please refer to the article provided below:
What is Next 🤔?
After playing with static page such as blog, we are ready to grow our site. We need to prepare front end part of dynamic page, such as dashboard, form, tables and chart.
Consider continue reading [ Bootstrap - Form ].