Work Text:
Click the speech bubbles to shout! (Plays audio when clicked.)
Phoenix Wright's 'Objection!':

Apollo Justice's 'Take that!':

How does it work?
There are three components to the clickable bubble:
- An HTML5 <audio> player element
- A looping gif of the shout animation
- A still frame image that hides the looping .gif
- A "coverup" element that overlays a change to the button border and background color to give the impression of a click
All three of these are contained inside a div of the custom class "shoutcontainer"
HTML:
<div class="shoutcontainer">
<p>
<audio class="shoutaudio" src="https://ferdielance.com/mus/pwobject.mp3" controls="controls" crossorigin="anonymous" preload="metadata"></audio>
<img class="shoutanim" src="https://ferdielance.com/mus/aniobject.gif" />
<img class="stillimage" src="https://ferdielance.com/mus/object.gif" />
<span class="coverup"></span>
</p>
</div>
The real heavy lifiting is done in CSS, though.
CSS:
#workskin .shoutcontainer {
position: relative;
top: 0;
left: 0;
background-color: white;
border-radius: 10px;
box-shadow: 0px 0px 3px;
overflow: hidden;
width: 298px;
height: 196 px;
}
#workskin .shoutcontainer > p {
background-color: white;
margin: 0px;
padding: 20px;
}
#workskin .shoutaudio {
position: absolute;
transform: scale(22,14);
transform-origin: top left;
left: -500px;
top: -150px;
z-index: 31;
opacity: 0;
}
#workskin .shoutaudio:active ~ .stillimage {
opacity: 0;
transition: 0s;
}
#workskin .backupaudio {
z-index: 40;
}
#workskin .shoutaudio:active ~ .coverup {
border: 3px solid #888888;
background-color: #EEEEEE;
}
#workskin .stillimage {
position: relative;
transition: opacity 0s 2s;
border: 3px solid white;
top: 0px;
left: 0px;
z-index: 25;
background-color: inherit;
}
#workskin .shoutanim {
position: absolute;
top: 20px;
left: 20px;
z-index: 20;
}
#workskin .coverup {
position: absolute;
left: 0px;
top: 0px;
opacity: 0.5;
box-sizing: border-box;
width: 100%;
height: 100%;
z-index: 19;
border: 5px solid #AAAAAA;
border-radius: 10px;
}
Breaking down the CSS:
The container div is sized to match the animation (258 x 196 pixels) and given the "overflow: hidden" property. This ensures that any elements that 'spill out' of its boundaries get cropped off. That's crucial!
AO3 does not allow Javascript or custom audio players, so we need to use the default HTML5 audio player. We're going to make its controls so huge that the play button covers up the entire animation! The overflow property will stop it from extending beyond. Then we'll make it invisible (opacity: 0), so it looks like the reader is just clicking the gif.
I apply a transform to scale the audio element's width 22x and its height 14x, numbers determined by extensive trial and error. I anchor it using transform-origin so it only "expands" down and to the right. I also set its z-index to 31 -- that tells the browser to layer it on TOP of everything else so we can click it. Why 31? It's an arbitrary biggish number, that's all.
One challenge: the built-in HTML5 audio player looks different on every browser! The clickable area of the play button has different shapes and positions. My clumsy solution was to find a 'sweet spot' where the audio control bar's scaling and position would place part of the play button under the speech bubble across all tested browsers. Some browsers allow a click anywhere on the controls to trigger the audio, which helps, but if you use a different-sized animation, prepare to do some tinkering! I suggest temporarily setting the audio player's opacity to 0.5 when experimenting so you can see what you're doing. I tested in mobile Safari, desktop Firefox, and desktop Chrome, and all positioned the play button a little differently.
I advise you not to try to get too clever with hidden -webkit pseudoclasses. (If you don't know what that means, ignore this paragraph.) I tried to do sneaky things with CSS to the audio control elements, and it did not work at all outside of Chrome. It barely worked in Chrome!
The animation is a more standard CSS effect. Before you click the shout, what you're seeing is a still "cover" image. When you click the audio player, this cover disappears, revealing an animated gif underneath. Since we want the gif to keep going for a second or two, we use a transition that holds the still image's opacity at zero for that long.
If you use these balloons, you may directly link these files for audio and images for use on AO3 only. However, you'll probably want your own wbhost for to customize them. Be careful that your webhost allows cross-site linking to the audio files via the audio tag! I configured my webhost to specifically allow AO3 pages to link to these.
Things that could be improved:
- Changes to how browsers show their audio bars could break this. Because there's no real agreement on how to style audio bars, it's entirely possible that Chrome could end up with the play button in the wrong place someday. You could include a normal set of backup audio controls below, but this also blunts the impact of the button.
- Comments are welcome.
