CSS and JavaScript effects: object effervescence

A couple of years ago I made this thing, not because I needed it and as far as I can tell neither has anyone else, but like a lot of things I do that have no purpose. It uses a small amount of CSS and some JS to make any object – text; a div, whatever – emit bubbles. The size, amount and colour of the bubbles can be easily changed and I guess the emitter could be used to emit any element.

Part 1: CSS

The first thing to do is make the CSS. The only CSS I am adding is for the container and the text. Neither of these are required for the bubbles to work, they are just there to make the example work.

The .container class will position the container in the centre of the page and the style on the h1 control the style of the text. You can safely omit this CSS as the JavaScript I am going to write will add it’s own CSS to the DOM at runtime. Nonetheless I am including the CSS here for instructional purposes:

.container {
  display: flex;
  width: 100%;
  height: 100vh;
  align-items: center;
  justify-content: center;
}
h1 {
  font-size: 100px;
  color: #ff0099;
  font-weight: bold;
  font-family: sans-serif;
}

Part 2: JavaScript

I have created the class Bubbles which can be instantiated with code anywhere on the page. I’m not sure if explaining how the script works is of any importance, but nonetheless:

The code starts by declaring the class Bubbles. The constructor function starts the code by initiating itself in the constructor. The constructor also sets default values for the variables, to prevent any “undefined” errors.

The init() function then creates the new element bubbles and adds it to the DOM. Then it calls the generateBubble() function for each new bubble. The generateBubble function sets the visual parameters of each bubble and adds it as a child element.

class Bubbles {
  constructor(id, options) {
    this.options = {
      density: options.density,
      color: options.color,
      size: options.size,
      borderColor: options.borderColor,
      blurFilter: options.blurFilter
    };
    this.id = id;
    this.width = 0;
    this.height = 0;
    this.elem = null;
    this.init();
  }
  init() {
    this.elem = document.getElementById(this.id);
    this.width = this.elem.offsetWidth;
    this.height = this.elem.offsetHeight;
    this.elem.style.position = "relative";
    for (var i = 0; i < this.options.density; i++) {
      var dot = document.createElement("span");
      this.elem.appendChild(dot);
    }
    var spans = this.elem.querySelectorAll("span");
    spans.forEach((el) => {
      this.generateBubble(el);
    });
  }
  getRGBA(hex) {
    var c;
    if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) {
      c = hex.substring(1).split("");
      if (c.length == 3) {
        c = [c[0], c[0], c[1], c[1], c[2], c[2]];
      }
      c = "0x" + c.join("");
      return (
        "rgba(" +
        [(c >> 16) & 255, (c >> 8) & 255, c & 255].join(",") +
        "," +
        Math.random() +
        ")"
      );
    }
    throw new Error("Bad Hex");
  }
  generateBubble(bubble) {
    var that = this;
    var tspan = bubble;
    var randomSize = Math.random() * this.options.size;
    tspan.style.position = "absolute";
    tspan.style.width = randomSize + "px";
    tspan.style.height = randomSize + "px";
    tspan.style.top = Math.random() * this.height + "px";
    tspan.style.left = Math.random() * this.width + "px";
    tspan.style.borderRadius = "50%";
    tspan.style.border = "solid " + this.options.borderColor + " 1px";
    tspan.style.opacity = Math.random();
    tspan.style.display = "block";
    if (this.options.color.indexOf("gradient") == -1) {
      tspan.style.backgroundColor = this.getRGBA(this.options.color);
    } else {
      tspan.style.backgroundImage = this.options.color;
    }
    if (this.options.blurFilter) {
      tspan.style.backdropFilter = "blur(4px)";
    }
    var maxSteps = 100;
    var cstep = 0;
    var startOpacity = 100;
    var bubbleSpeed = Math.random() * 100;
    var animTimer = setInterval(function () {
      if (cstep < maxSteps) {
        cstep++;
        startOpacity--;
        tspan.style.top =
          parseFloat(tspan.style.top.replace("px", "")) - 1 + "px";
        tspan.style.opacity = startOpacity / 100;
      } else {
        clearInterval(animTimer);
        tspan.remove();
        var newspan = document.createElement("span");
        that.elem.appendChild(newspan);
        that.generateBubble(newspan);
      }
    }, bubbleSpeed);
  }
}

Save the file as a .js file eg: bubbles.js, and link it anywhere in your html.

<script src="bubbles.js"></script>

Part 3: adding it to the page

This code should be added below the bubbles.js code.

<script>
var b = new Bubbles('myItem', {
   density: 100,
   color: 'radial-gradient(farthest-corner at 10% 10%, #ffffff 0, #ff0099 100%)',
   size: 20,
   borderColor: '#ffffff',
   blurFilter: true
 });
</script>
<div class="container">
  <h1 class="bubbles" id="myItem">Bubbles</h1>
</div>

This creates a new element of the class Bubbles with the added attributes. ‘myItem’ is the ID of the element you want to make bubble. density is the amount of bubbles that will exist at any time. color Determines the colour of each bubble and borderColor the border colour. size is the max size of each bubble and blurFilter will add an effect to each bubble that blurs the objects beneath it – this will likely affect browser speed if you create lots of bubbles.

When you open your page in a browser your object should bubble like this: https://codepen.io/pieisdead/pen/QWQPbJJ

Bubbles

Leave a Reply

Your email address will not be published. Required fields are marked *

Comment Rules

  • No rude or lascivious behavior will be tolerated.
  • Beans contain the souls of the dead – do not eat them.
  • All the other obvious ones.