On the main page of 404wolf.com I have it set up so that
various elements’ text ‘types’ into their respective boxes. It’s a neat
animation that I achieve using the typewriter-effect
package
that can be found here. It
works great out of the box, but since I have unique title styles that I wanted
to keep consistent, I ran into a problem.
For titles on my website that are type-written after loading, I wanted the backgrounds to already exist, and then for the typewriter to type into them. Without any special configuration, the boxes load without a background, and as the typewriter types the boxes expand (since they use fitting width).
To solve this issue, I originally tried to compute the width by using a basic
document.createElement
method that I wrote (with some GPT help—I didn’t know
about .offsetWidth
before this!).
function getDummyAreaWidth(
styles: string,
classes: string,
type: string,
text: string,
) {
const dummyArea = document.createElement(type)
dummyArea.textContent = text
dummyArea.setAttribute('style', styles)
dummyArea.className = classes
document.body.appendChild(dummyArea)
const width = dummyArea.offsetWidth
document.body.removeChild(dummyArea)
return width
}
Basically, we create an element, set the styles and classes that would cause the
width to change, and then yoink it’s width. The idea is that I’d then use this
function for the title components to give them fixed predetermined widths.
However, since typewriter-effect
uses some wrapper classes and I’m using
tailwind
, it wasn’t computing the widths properly. I might have been able to
troubleshoot and fix it, but instead I opted for a simpler solution.
Instead of using a computed width value, I figured out that it’d be easier to just have the width be computed as if the text were actually there from the start. I realized that if the text were loaded initially without a typewriter, that the width would (expectedly) be correct. So, what I decided to do was make it so that the text did preload into the box, but the text itself was transparent. This would cause the box to fill properly as if there were complex-ly styled variable-width text in it, but appear to be empty while the typewriter were to type into the box. I then made the typewriter text absolute, so that it could type on top of the invisible text that was already in the box.
The actual code for my homepage’s main header was super simple to update with this idea, and worked right away!
import Typewriter from "typewriter-effect";
const Greeter = () => {
return (
<div className="relative">
<span className="text-transparent"> {"Hi! I'm Wolf Mermelstein"} </span>
<span className="absolute left-0" style={{ whiteSpace: "nowrap" }}>
<Typewriter
onInit={(typewriter) => {
typewriter
.typeString("Hi! ")
.pauseFor(700)
.typeString("I'm Wolf Mermelstein")
.start();
}}
options={{ delay: 70, cursor: "", autoStart: true }}
/>
</span>
</div>
);
};
export default Greeter;