The biggest accomplishment of the inaugural version, aside from completing it, was modifying it to exclude having to ask the question, albeit what I came up with wasn’t very elegant, to put it politely. In the spirit of “you have to start somewhere”, this was a decent start.
In 2019 I made some refinements to the Javascript, which felt like an accomplishment as I had a better understanding of what was happening rather than just poking at it with no real clue like I had done in the first version. I also made a few CSS and design refinements but the JavaScript was the biggest improvement.
The original version used if/else statements and innerHTML
to swap out the placeholder “8” and display the randomized answer.
document.getElementById('answerButton').onclick = function () {var x = document.getElementById("eight");
if (x.innerHTML === "8") {
x.innerHTML = "";
} else {
x.innerHTML = "";
}
var answer = answers[Math.floor(Math.random() * answers.length)];
document.getElementById('answerContainer').innerHTML = answer;
};
I changed it use getElementById
to manipulate the style of the container (applying the style directly in JavaScript) and then writing the answer using textContent
.
document.getElementById('answerButton').onclick = function () {
let resizeAnswer = document.getElementById("answerContainer").style.fontSize = '2rem';
let derbyWinner = contenders[Math.floor(Math.random() * contenders.length)];
document.getElementById('answerContainer').textContent = derbyWinner;
};
I’m guessing the updated approach is better than the previous. If nothing else I found the new approach easier to write and understand.
This version took a few steps forward with more JavaScript refinements as well as some CSS and accessibility improvements. I simplified the JavaScript even further by using getElementById
with classList.remove
and classList.add
to swap the “8” and the answer, moving the styling to CSS.
document.getElementById('answer-button').onclick = function () {
document.getElementById('answer-container').classList.remove('eight');
document.getElementById('answer-container').classList.add('reveal');
let derbyWinner = contenders[Math.floor(Math.random() * contenders.length)];
document.getElementById('answer-container').textContent = derbyWinner;
};
The CSS improvements were mostly general clean-up, like moving from fixed sizes to relative. I also included a couple of nice enhancements found in articles. I used this by Håvard Brynjulfsen to spiff up the focus styles on the button and add a nice drop shadow and the squishy button active state came from a Piccalilli Quick Tip.
For accessibility I tested using Mac OS VoiceOver and it announced properly in Safari and Chrome, but not Firefox.
This version added some 8 ball-esque animation, improved accessibility and updated design. I might have gone a little overboard with the existing JavaScript approach, but I used the existing getElementById
DOM manipulation approach to add animation styles and change the aria-hidden
attribute.
document.getElementById('answer-button').onclick = function () {
document.getElementById('answer-container').classList.remove('eight');
document.getElementById('answer-container').classList.add('reveal');
document.getElementById('answer-container').setAttribute("aria-hidden", false); // remove aria-hidden attribute so the answer is read
document.getElementById('answer').classList.add('answer');
document.getElementById('eight-ball').classList.add('shake');
let derbyWinner = contenders[Math.floor(Math.random() * contenders.length)];
document.getElementById('answer-container').textContent = derbyWinner;
};
The first two lines within the function are the existing swap of the placeholder “8” and styling for the randomized answer. The container is set to aria-hidden=“true”
by default to keep screen readers from announcing the placeholder “8”. When the answer is added aria-hidden is changed “false”, allowing the answer to announced. This worked in VoiceOver, and I’m hoping it works in other screen readers. The next two additions apply the animations.
I also made a bit of an effort to make it look more like an 8 ball. I wrote a detailed account of the 2021 changes, including more about the accessibility of the animations and some details about the design if you’re interested.
This version moved from Glitch to Netlify, mostly to improve my workflow. I also added a dark theme and dropped the media queries.
The media queries were mainly used to control the size of the eight ball. I changed that to use clamp()
with a fallback, which gives the eight ball a better size and screen usage across devices.
Original sizing
.eight-ball {
background-color: black;
border-radius: 50%;
width: 22rem;
height: 22rem;
font-size: 2.2rem;
}
@media only screen and (max-width: 800px) {
.eight-ball {
width: 18rem;
height: 18rem;
}
}
Updated sizing
.eight-ball {
background-color: var(--color-darkest);
border-radius: 50%;
border: 1px solid var(--color-grey-mid);
width: 18rem;
width: clamp(18rem, 30vw, 36rem);
height: 18rem;
height: clamp(18rem, 30vw, 36rem);
font-size: 2.2rem;
}
I updated the answer background to a blue gradient to give it a bit more of an original 8 ball vibe without trying to figure out how to put the potentially long answers in a triangle.
I’d like to think I could improve the animation, but overall I’m happy with the current state.
View all versions…