If we start by accepting that:
- HTML is for structure
- CSS is for presentation
- JS is for behaviour
N.B. We can debate whether presentation which responds to user interaction is simply another way to say behaviour. That's certainly one view.
However, the vast array of interactive visual effects around the web declared entirely in CSS and initiated by
:hover
and:focus
and:focus-within
etc. pseudo-class states suggests another view is widely shared that CSS is a legitimate technology for handling what we might call interactive presentation.
I want to ask (because I can find nothing) if, for all the many and varied ways CSS is deployed to handle interactive visual presentation it is ever deployed to handle interactive aural presentation?
Have there been attempts to introduce aural presentation to CSS?
Is there a proposal to introduce aural presentation to CSS?
Is there any sort of official approach at all (even if never or not yet implemented by browsers) to achieve what the following demo does, using the following (made-up) CSS properties:
audio
audio-duration
audio-play
Working Example:
Please humour me and pretend that the hastily written javascript below isn't there and that it's as if CSS styles like:
.square:unhover {
audio: url(//cdn.freesound.org/previews/628/628357_1486333-lq.mp3);
audio-duration: 1.776s;
audio-play: 2;
}
just work, as-is.
// BUILD STYLESHEET ARRAY
const stylesheet = document.head.querySelector('style');
let stylesheetText = stylesheet.textContent.replace(/\s/g, '');
let stylesheetArray = stylesheetText.split('}');
stylesheetArray.pop();
// BUILD SELECTORS ARRAY
let selectorsArray = [];
for (let i = 0; i < stylesheetArray.length; i++) {
selectorsArray[i] = {
selector: stylesheetArray[i].split('{')[0],
styles: {}
};
let selectorRules = stylesheetArray[i].split('{')[1].split(';')
selectorRules.pop();
for (let j = 0; j < selectorRules.length; j++) {
selectorsArray[i].styles[selectorRules[j].split(':')[0]] = selectorRules[j].split(':')[1];
}
}
// BUILD TARGET QUERIES ARRAY
let targetQueriesArray = [];
for (let i = 0; i < selectorsArray.length; i++) {
if ((/:hover|:unhover/).test(selectorsArray[i].selector)) {
if (Object.keys(selectorsArray[i].styles).includes('audio')) {
let targetQuery = selectorsArray[i];
switch (true) {
case (targetQuery.selector.includes(':hover')): targetQuery.event = 'mouseover'; break;
case (targetQuery.selector.includes(':unhover')): targetQuery.event = 'mouseout'; break;
}
targetQueriesArray.push(targetQuery);
}
}
}
// DECLARE playAudioViaCSS FUNCTION
const playAudioViaCSS = (audioURL, audioDuration, audioPlays) => {
let soundEffectViaCSS = new Audio(audioURL);
soundEffectViaCSS.loop = true;
soundEffectViaCSS.play();
setTimeout(() => soundEffectViaCSS.loop = false, (audioDuration * audioPlays));
}
// ATTACH AUDIO EVENTS TO TARGET ELEMENTS
for (let i = 0; i < targetQueriesArray.length; i++) {
let targetAudio = targetQueriesArray[i].styles.audio.replace('url(', '').replace(')', '');
let targetAudioDuration = (targetQueriesArray[i].styles['audio-duration'].replace('s', '') * 1000) || 1000;
let targetAudioPlays = targetQueriesArray[i].styles['audio-play'] || 1;
let targetEvent = targetQueriesArray[i].event;
let targetQuery = targetQueriesArray[i].selector.replace(/:hover|:unhover/g, '');
let targetElements = [...document.querySelectorAll(targetQuery)];
targetElements.forEach((element) => element.addEventListener(targetEvent, () => playAudioViaCSS(targetAudio, targetAudioDuration, targetAudioPlays), false));
};
:root {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.square {
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
color: rgb(255, 255, 255);
background-color: rgb(255, 0, 0);
border-radius: 50%;
cursor: pointer;
transform: scale(1);
transition: all 0.9s ease-out;
}
.square:hover {
border-radius: 0;
transform: scale(1.5);
audio: url(//cdn.freesound.org/previews/354/354062_1490240-lq.mp3);
audio-duration: 2.304s;
audio-play: 3;
}
.square:unhover {
audio: url(//cdn.freesound.org/previews/628/628357_1486333-lq.mp3);
audio-duration: 1.776s;
audio-play: 2;
}
<div class="square">
Hover me
</div>