Where to Discuss?

Local Group

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.

Bootstrap5: Native Progressbar

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:

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

Bootstrap5: Javascript Assets

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

Bootstrap5: Stylesheet Assets

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

Bootstrap5: Nunjucks NERDTree

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>

Bootstrap5: Nunjucks: Heads: Meta

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>

Bootstrap5: Nunjucks: Heads: Assets Links

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.

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">

Bootstrap5: Nunjucks: Heads: Assets Links

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>

Bootstrap5: Nunjucks: Contents: Main

That’s all.

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.

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>

Bootstrap5: Nunjucks: Heads: Assets Links

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>

Bootstrap5: Nunjucks: Contents: 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);
  });
});

Bootstrap5: Javascript: Observer Bounce

The Issue

This approach has a few issue. I should write this long procedure for each effect. And the javascript become unbearable longer.

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.

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>

Bootstrap5: Nunjucks: Heads: Assets Links

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>

Bootstrap5: Nunjucks: Contents: 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);
  });
});

Bootstrap5: Javascript: Observer Bounce

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.

  1. slideInLeft for blog content.
  2. slideInRight for widget.
  3. 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>

Bootstrap5: Nunjucks: Contents: 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>

Bootstrap5: Nunjucks: Contents: Aside

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.

  1. Javascript only, no stylesheet.
  2. 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.

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>

Bootstrap5: Nunjucks: Heads: Assets Links

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>

Bootstrap5: Nunjucks: Contents: Chunks

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.

Bootstrap5: Javascript: Numerator

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.

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

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>

Bootstrap5: Nunjucks: Heads: Assets Links

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;
}

Bootstrap5: Stylesheet: Progressbar

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.

Bootstrap5: Nunjucks: Contents: Chunks

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.

Bootstrap5: Javascript: Progressbar

Preview in Browser

Enjoy the result.

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 ].