What I built
My Digital Ocean / DEV hackathon submission is focused breathing a CSS animation to help with meditation and focused breathing exercises.
Category Submission
Program for the People
App Link
focused-breathing-ogh7t.ondigitalocean.app/ or shannoncrabill.com/focused-breathing which redirects to the app hosted on Digital Ocean.
Screenshots
Screenshot of focused breathing in its default state.
The timing of the animation (expanding, holding, and contracting) is set to 8 seconds by default. The timing can be changed using the input field.
Here's a gif of the app in action.
Description
focused breathing includes a circle div that expands for 2 seconds, holds it's shape for 2 seconds, then contracts to its original size for 4 seconds. The breathing exercise involves inhaling through the nose as the circle expands. Holding the breath. Then exhaling through the mouth as the circle contracts.
Link to Source Code
scrabill / focused-breathing
A CSS Animation to help with focused breathing exercises
Permissive License
Background
I recently learned about focused breathing exercises as part of a meditation or calming routine. I kept forgetting the timing of how long to inhale, hold long do I hold, etc. So, I decided to make a little app to help me with the pacing.
I've been having fun experimenting with CSS animations and thought this would be an excellent opportunity to learn about the animation
property, transitions, and @keyframes
.
How I built it
I built *focused breathing*
in two parts. The first version was an experiment with CSS animations and @keyframes
. I wanted to see if I could achieve the transitions and cadence I wanted with only HTML and CSS. It was possible! No Javascript was needed for the original version, which can be found on CodePen.
For the second part, I wanted to see if I change the duration of the animation (which is in the CSS file) based on input from the user. I know I could get input values from the HTML file with Javascript, but could I pass those updated variables back to the CSS and render it to the page. It turns out this was possible too!
Here's how I approached building parts one and two and what I learned along the way.
Part One - HTML & CSS
Before I started coding, I was helpful for me to write down high-level steps of the focused breathing technique I had been taught.
It goes like this.
- Inhale through the nose
- Hold the breath
- Exhale through the mouth for 4 seconds
The amount of time to inhale of hold the breath may not matter, but to make it easier from a coding perspective, 2 seconds to inhale and 2 seconds to hold a breath seemed reasonable.
Visually, there would be a small to medium-sized circle that would expand, cueing you inhale and contract when it was time to exhale.
Visualizing the Animation
Using @keyframes
was the best want to handle the expanding and contracting of the circle so that I control the timing and pacing of each step. With @keyframes
the stops or offsets range between 0% and 100%. The beginning or start of the animation would be 0% stop and the end would be 100%. Or, any number in between.
I've worked with @keyframes
on other projects and had a difficult time visualizing what code I needed to write to achieve what I visualized in my mind.
It makes sense to map out what I wanted to happen like a timeline. A line segment with two endpoints could represent the timeline of the animation. The left endpoint would be the beginning of the animation cycle and the right, the end.
Some quick labels, notes and visuals and I have a timeline that looks like this.
https://i1.wp.com/shannoncrabill.com/blog/wp-content/uploads/2020/12/step3.png?resize=640%2C86&ssl=1
Translating the Timeline to @keyframes
Looking at the timeline above, it may look like we need 8 or 4 steps in the animation, but this is not the case. Each offset point in a @keyframe
animation is a point where properties can be changed from their original values.
The circle starts small, then it’s changed to be larger than it was originally, then it holds that size, then it shrinks down to the size it was originally and the animation starts over. The @keyframe
only needs 2 offset points (at the 25%
and 50%
marks) and the original styling of the circle handles the starting (and ending) visuals.
Similar to grouping other CSS attributes, multiple properties and offsets can be set at one time within the @keyframe
declaration.
@keyframes breath {
25%, 50% {
background-color: lightpink;
width: 200px;
height: 200px;
border-radius: 100px;
}
}
And, to make it a bit easier on ourselves, let’s divide the line into 8 even parts (1 part for each second of the animation).
The timing of the changes and width and height of the circle meant that I couldn't
The expanding and contracting of the circle can be handled with @keyframes
.
Part 2 - Javascript
For the second part of this project, I wanted to add some customization. To start, I wanted to see if I could change the duration of the animation—which was 8s to start—to another value. Building an input field was straight forward, but how could that value get updated in the animation
property?
In doing some Googling, I was reminded that CSS variables could be accessed and updated with Javascript using getComputedStyle
and getPropertyValue
. I was already using CSS variables for colors and sizes, so created a new one for timing
.
:root {
--timing: 8s;
}
And updated my animation
property to include that variable (var(--timing)
) instead of the hardcoded value (8s)
div {
animation: breath var(--timing) ease infinite none running
}
Visually, nothing changed, which meant it worked! I could double-check the value of --timing
by running the following in the Console.
getComputedStyle(document.documentElement).getPropertyValue('--timing') // 8s
And I could change it with the following and see the animation speed up dramatically.
document.documentElement.style.setProperty('--timing', '1s');
Then, by adding an input field onto the page, I could grab the value of that input, pass it into .setProperty
and update the CSS.
Wrap Up
Overall, I learned a lot about @keyframes
with this project! Drawing out what I had in mind made coding go smoother with less trial and error.
Looking back at this project, I tried for the first time, or became more comfortable with:
- CSS Grid (centering things, amiright?)
- CSS Animations (the
animation
and@keyframes
property) - Manipulating CSS variables with Javascript (
getComputedStyle
andgetPropertyValue
) - Continuous deployment (yikes to manually copy and pasting files like I usually do)
For future enhancements, some thoughts are:
- The ability to change other variables (hold time is longer, shorter, etc)
- The ability to start and stop (or, incorporate a timer for 5 mins of focused breathing, etc)
- Sounds or music so accompany to indicate when you breathe in, breath out, etc.
- A detailed tutorial on how to build your own focused breathing animation/app from scratch
Additional Resources/Info
- https://ggia.berkeley.edu/practice/mindful_breathing
- https://www.tckpublishing.com/reduce-stress-with-focused-breathing/
- https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations
- https://davidwalsh.name/css-variables-javascript
- https://css-tricks.com/updating-a-css-variable-with-javascript/
Top comments (9)
Water Breathing, Eleventh Form: Dead Calm.....
No on a serious note it's a very clean animation I think you could add a small setting to let people define colors or to have random sets of colors for a little flare
Thank you! Random colors would be a nice add. I did that for another project so it would be easy to implement here.
That and a dark mode variation.
I love this! Really satisfying animation :)
Great job!
That is pretty cool! Great job!
I just did a quick mindful breathing session!
Haha love this!
Thank you. That is very cool!
This is superb.
It means a lot to hear you say that. Thank you.