| title |
before |
folders |
after |
notes |
Set up project |
Before we get started, create some files and get ready.
|
| label |
type |
bubble-popper |
folder |
|
| label |
indent |
index.html |
1 |
|
| label |
type |
indent |
css |
folder |
1 |
|
|
| label |
type |
indent |
js |
folder |
1 |
|
|
|
1. Make an `index.html` & add the boilerplate code.
2. Make a `main.css` in your `css` folder & add the boilerplate code.
3. Make an empty `main.js` in your `js` folder & connect it to your HTML.
4. Connect jQuery to your website, with the URL from [cdnjs]( https://cdnjs.cloudflare.com/).
|
| label |
text |
Naming conventions |
Don’t forget to follow the [naming conventions](/topics/naming-paths-cheat-sheet/#naming-conventions). |
|
|
|
| title |
before |
code_lang |
code_file |
code |
lines |
notes |
HTML setup |
We’re not going to need any HTML elements to make this work, so the `<body>` can stay empty except for the `<script>` tags.
|
html |
index.html |
|
| num |
text |
11 |
Don’t forget to hook up jQuery. |
|
|
| label |
text |
HTML snippets |
Create the boilerplate with `html5`, `viewport`, `css` & `jss` |
|
|
|
| title |
before |
code_lang |
code_file |
code |
lines |
notes |
Styling the bubbles |
With a touch of CSS we can transform any `<div>` into a bubble.
|
css |
css/main.css |
html {
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}
.bubble {
left: 0;
top: 0;
position: absolute;
height: 50px;
width: 50px;
border-radius: 50%;
background-color: lightblue;
}
|
| num |
text |
10-12 |
Using `position: absolute` is really important here because we want to be able to the move the circle around the screen with coordinates. |
|
|
| label |
text |
CSS snippets |
Create the boilerplate with `borderbox` |
|
|
|
| title |
before |
code_lang |
code_file |
code |
lines |
after |
Add random bubbles to the screen |
When the `Space` key is pressed on the keyboard, we’re going to create a new `<div>` tag, with the class of bubble, and place it on the screen in a random location.
|
js |
js/main.js |
var $body = $('body');
$('html').on('keydown', function (e) {
var $bubble;
if (e.key == ' ') {
$bubble = $('<div>');
$bubble.addClass('bubble');
$bubble.css({
'top': Math.random() * (document.documentElement.clientHeight - 100),
'left': Math.random() * (document.documentElement.clientWidth - 100)
});
$body.append($bubble);
}
});
|
|
| num |
text |
9 |
If we want to change multiple CSS properties at the same time we can pass and object to the `.css()` function instead of calling it multiple times. |
|
| num |
text |
10-11 |
We can use `document.documentElement.clientWidth` & `height` to constrain the random coordinates to the dimensions of the window.
The `- 100` here is subtracting the width of the circle so they don’t appear slightly off the screen.
|
|
|
At this point, pressing the `Space` key should create a random bubble on the screen.

|
|
| title |
before |
code_lang |
code_file |
code |
lines |
after |
Make the bubbles grow |
When the bubbles appear on the screen, it’d be neat if they grew into place. With some CSS animations we can do that.
|
css |
css/main.css |
.bubble {
⋮
border-radius: 50%;
background-color: lightblue;
animation: bounce .5s cubic-bezier(.5, -.9, .6, 1.9) forwards;
transform: translate(-50%, -50%);
}
@keyframes bounce {
0% {
height: 50px;
width: 50px;
}
100% {
height: 100px;
width: 100px;
}
}
|
|
| num |
text |
5 |
Add an `animation` to the bubble that makes a bounce effect.
Notice in the keyframes that the bubble is just being scaled from `50px` to `100px`. The bouncing comes from the custom easing: `cubic-bezier()`
With the `cubic-bezier()` function we can make any kind of easing we want. I didn’t magically come up with these numbers I used a [cubic bezier generator]( http://cubic-bezier.com/).
We’re using `forwards` here to keep the bubble at its bigger size when it’s done animating, otherwise it would snap back to the smaller size.
|
|
| num |
text |
6 |
The `transform` is here so the bubble scales from the centre, because we’re adjusting the width and height it will naturally scale from the top-left corner, so we’re changing the anchor point.
Of course, I could have used `transform: scale()` inside `@keyframes` instead of `width` & `height` to acheive the same results.
|
|
|
With a refresh in your browser, pressing `Space` now should drop a bubble on the screen and it should animate.

|
|
| title |
before |
code_lang |
code_file |
code |
lines |
Click to pop |
The next piece of code we’re going to write is to make the bubbles “pop” when they are clicked.
To start, let’s write some JavaScript that will add a class to the bubble when it’s clicked:
|
js |
js/main.js |
⋮
$body.append($bubble);
}
});
$body.on('click', '.bubble', function () {
$(this).addClass('is-popping');
});
|
|
| num |
text |
6 |
We’re using event delegation here: listening for clicks on the `<body>`, but only activating the event handler when a `.bubble` is called upon.
We need to use event delegation because we don’t know how many bubbles there are and we don’t want to add an event listener to every single one.
|
|
|
|
| title |
before |
code_lang |
code_file |
code |
lines |
after |
Popping CSS |
The new `.is-popping` class will change the `width` & `height` to `0`, making the bubble shrink & set the `opacity` to `0` to fade the bubble away.
We also need to add a transition to the `.bubble` to create the easing effect.
|
css |
css/main.css |
.bubble {
⋮
animation: bounce .5s cubic-bezier(.5, -.9, .6, 1.9) forwards;
transform: translate(-50%, -50%);
transition:
width .3s cubic-bezier(.7, -.6, .4, 1.5),
height .3s cubic-bezier(.7, -.6, .4, 1.5),
opacity .3s ease-out
;
}
.is-popping {
height: 0;
width: 0;
opacity: 0;
animation-name: none;
}
@keyframes bounce {
0% {
height: 50px;
⋮
|
|
|
| num |
text |
5-9 |
The `transition` is written on multiple lines because certain properties are going to have different easing than others—and one line is difficult to read.
The 3 different transitions:
- The `width` & `height` should have a bouncing effect
- The `opactiy` should just `ease-out`
|
|
| num |
text |
16 |
It’s very important that we remove the `animation` at this point. Because the `forwards` in the animation forces the element to stay at its largest size after the animation is completed.
Without removing the animation from the element we wouldn’t see it shrink.
|
|
|
When clicking on each of the bubbles now they should shrink and fade away.

|
|
| title |
before |
code_lang |
code_file |
code |
lines |
Removing the element when completed |
Even though the bubble shrinks and fades away there’s still an invisible `<div>` in the HTML.
*Let’s use JavaScript to remove the `<div>` from the `<body>` after its animation has finished:*
|
js |
js/main.js |
⋮
$(this).addClass('is-popping');
});
$body.on('transitionend', '.bubble', function () {
$(this).remove();
});
|
|
| num |
text |
5 |
The code is listening for the `transitionend` event that will be triggered whenever the `.bubble` has finished its shrinking-fading transition.
|
|
| num |
text |
6 |
We then target `$(this)`—which represents the single ball that finished—and remove it from the `<body>`
|
|
|
|