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!).
1function getDummyAreaWidth(styles: string, classes: string, type: string, text: string) { 2 const dummyArea = document.createElement(type); 3 dummyArea.textContent = text; 4 dummyArea.setAttribute("style", styles); 5 dummyArea.className = classes; 6 document.body.appendChild(dummyArea); 7 const width = dummyArea.offsetWidth; 8 document.body.removeChild(dummyArea); 9 return width; 10};
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!
1import Typewriter from "typewriter-effect"; 2 3const Greeter = () => { 4 return ( 5 <div className="relative"> 6 <span className="text-transparent"> {"Hi! I'm Wolf Mermelstein"} </span> 7 <span className="absolute left-0" style={{ whiteSpace: "nowrap" }}> 8 <Typewriter 9 onInit={(typewriter) => { 10 typewriter 11 .typeString("Hi! ") 12 .pauseFor(700) 13 .typeString("I'm Wolf Mermelstein") 14 .start(); 15 }} 16 options={{ delay: 70, cursor: "", autoStart: true }} 17 /> 18 </span> 19 </div> 20 ); 21}; 22 23export default Greeter;