CSS and HTML have opened a rich playing field for adding multimedia content to your web page, web app, and e-book projects. One innovative way of combining these two technologies is adding sound effects to your CSS animations using <audio> elements and triggering them with a little bit of JavaScript.
Although sound on the web isn’t universally welcome, there are cases when it can enrich the user experience without being an unnecessary annoyance. Examples are artist and gaming websites or content for children. Sound can even be useful in certain cases to visitors with disabilities.
The most important part of the sound animation process is adjusting your CSS animation to the audio to achieve an accurate in-sync audio-visual experience. In this article I’ll go through the steps of syncing animation keyframes to audio timing data using an interesting example of a beating stylized heart.
See the Pen CSS Animation with Sound: Heartbeat by SitePoint (@SitePoint) on CodePen.
Constructing the Heart
The first ingredient we need is a heart we want to animate. We will construct one using CSS pseudo-elements. Having it constructed in HTML rather than using an image, even if only through pseudo-elements, gives us the opportunity to animate various CSS properties to create a more interesting animation.
We can often find more than one way to build a shape this way, but if we plan to animate it it’s worth thinking about geometry and how different structural choices affect movement and simplify the keyframes code.
In this case the simplest technique is to use two vertical rectangles rounded on top, rotated, and positioned to overlap to form a heart shape. Their size is set using percentages and they’re absolutely positioned with a bit of geometry consideration so it’s easy to scale the original shape by changing the container size. The rectangles are rotated 45 degrees clockwise and counterclockwise to form the left and right parts of the heart.
[code language="css"]
.heart::before,
.heart::after {
background-color: red;
content: "";
height: 80%;
left: 25%;
position: absolute;
top: 2%;
transform: translateZ(0) rotate(-45deg);
width: 50%;
}
.heart::after {
transform: translateZ(0) rotate(45deg);
}
[/code]
Rounded sides are set with two radii values to get an elliptic rather than circular curve, and therefore a more natural heart shape. Because rectangle side lengths have a 5/8 ratio, the ellipsis radii calculate to 50%/37.5% to round off only the corners that don’t overlap.
[code language="css"]
.heart::before,
.heart::after {
border-radius: 50% 50% 0 0 / 37.5% 37.5% 0 0;
}
[/code]
Now what remains is to adjust the transform-origin point for the rectangles so the points line up at the center of the square area where the rectangles do overlap. The same look can be achieved by adjusting the absolute position declarations instead of using the transform-origin approach. But that would later complicate the keyframes code because it would force us to control the position in more detail instead of relying on the transform scale function to do the work for us.
The transform-origin point should be calculated with regards to the coordinate system before any transforms are applied (because transforms can affect the coordinate system, for example, the rotate() function rotates the coordinate system along with the element it is applied to). Again the sides length ratio dictates the position of that point: it is easy to see that the X position is at 50%, at the center of the rectangles, but the Y position is calculated at 68.75% of the rectangle height measured from the top (55*100%/80=68.75%). Going with the specific symmetry approach pays off here too, as both rectangles share the same transform-origin point position.
[code language="css"]
.heart::before,
.heart::after {
transform-origin: 50% 68.75% 0;
}
[/code]
And now we have a beautiful symmetric heart shape. We can add an inset box-shadow, different for each rectangle, to make it all plump and 3D.
[code language="css"]
.heart::before {
box-shadow: -8px -14px 10px 0 black inset;
}
.heart::after {
box-shadow: -15px 10px 14px 0 black inset;
}
[/code]
The Sound of the Heart
To introduce audio into the page, we use the <audio> element with the path to the audio file and without the controls attribute because we don’t want the internal browser audio player to appear (read more in Using HTML5 audio and video on MDN).
[code language="html"]
<audio id="heartbeat" src="heartbeat.mp3" preload="auto">
Your browser does not support the <code>audio</code> element.
</audio>
[/code]
Instead of the controls, we use JavaScript to manipulate the playback. This example uses buttons to start and reset the track, but with a little bit more work we could do without the buttons and start and reset the audio when the heart element is clicked or hovered.
Our sound is the sound of a heartbeat repeated four times and it will serve as the sound our CSS animation will follow.
Flex that Muscle
To make our heart tick, we need to change its shape from original, resting heart, to the state when the muscle is flexed. To flex the heart we scale it down a bit and change its shape with border-radius.
Here is how the flexed styles would read if we needed them static, outside of the animation:
Continue reading %Syncing CSS Animations with HTML5 Audio%
by Mihaela Jurkovic via SitePoint
No comments:
Post a Comment