{"id":344497,"date":"2021-07-20T08:03:40","date_gmt":"2021-07-20T15:03:40","guid":{"rendered":"https:\/\/css-tricks.com\/?p=344497"},"modified":"2021-07-20T08:03:43","modified_gmt":"2021-07-20T15:03:43","slug":"typewriter-animation-that-handles-anything-you-throw-at-it","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/typewriter-animation-that-handles-anything-you-throw-at-it\/","title":{"rendered":"Typewriter Animation That Handles Anything You Throw at It"},"content":{"rendered":"\n
I watched Kevin Powell\u2019s video<\/a> where he was able to recreate a nice typewriter-like animation using CSS. It\u2019s neat and you should definitely check it out because there are bonafide CSS tricks in there. I\u2019m sure you\u2019ve seen other CSS attempts at this, including this site\u2019s very own snippet<\/a>.<\/p>\n\n\n\n Like Kevin, I decided to recreate the animation, but open it up to JavaScript. That way, we have a few extra tools that can make the typing feel a little more natural and even more dynamic. Many of the CSS solutions rely on magic numbers based on the length of the text, but with JavaScript, we can make something that\u2019s capable of taking any text we throw at it.<\/p>\n\n\n\n So, let\u2019s do that. In this tutorial, I\u2019m going to show that we can animate multiple words just by changing the actual text. No need to modify the code every time you add a new word because JavaScript will do that for you!<\/p>\n\n\n\n\n\n\n Let\u2019s start with text. We are using a monospace font to achieve the effect. Why? Because each character or letter occupies an equal amount of horizontal space in a monospaced font, which will come handy when we\u2019ll use the concept of We have three elements placed inside a container: one element for the actual text, one for hiding the text, and one for animating the cursor.<\/p>\n\n\n\n We could use We\u2019re completely hiding the text behind the In order to cover the entire text element, position the Next, let\u2019s make that little cursor thing that blinks as the text is being typed. We\u2019ll hold off on the blinking part for just a moment and focus just on the cursor itself.<\/p>\n\n\n\n Let\u2019s make another element with class Now we get something that looks like a cursor that\u2019s ready to move as the text moves:<\/p>\n\n\n\n Now comes the super fun part\u2014let\u2019s animate this stuff with JavaScript! We\u2019ll start by wrapping everything inside a function called Next task is to store each and every character of text in a single array using the For example, if we take \u201cTyping Animation\u201d as a string, then the output is:<\/p>\n\n\n\n We can also determine the total number of characters in the string. In order to get just the words in the string, we replace For example, for a string \u2018Typing Animation\u2019, the output will be,<\/p>\n\n\n\n Now, let\u2019s calculate the length of the entire string as well as the length of each and every individual word.<\/p>\n\n\n\n To get the length of the entire string, we have to access the length of the array containing all the characters as individual elements. If we\u2019re talking about the length of a single word, then we can use the Starting with the text<\/h3>\n\n\n
steps()<\/code> while animating the text. Things are much more predictable when we already know the exact width of a character and all characters share the same width.<\/p>\n\n\n\n
<div class=\"container\">\n <div class=\"text_hide\"><\/div>\n <div class=\"text\">Typing Animation<\/div>\n <div class=\"text_cursor\"><\/div>\n<\/div><\/code><\/pre>\n\n\n\n
::before<\/code> and
::after<\/code> pseudo-elements here, but they aren\u2019t great for JavaScript. Pseudo-elements are not part of the DOM, but instead are used as extra hooks for styling an element in CSS. It\u2019d be better to work with real elements.<\/p>\n\n\n\n
.text_hide<\/code> element. That\u2019s key. It\u2019s an empty div that stretches the width of the text and blocks it out until the animation starts\u2014that\u2019s when we start to see the text move out from behind the element.<\/p>\n\n\n\n
<\/figure>\n\n\n\n
.text_hide<\/code> element on top of the text element having the same height and width as that of the text element. Remember to set the
background-color<\/code> of the
.text_hide<\/code> element exactly same as that of the background surrounding the text so everything blends in together.<\/p>\n\n\n\n
.container {\n position: relative;\n}\n.text {\n font-family: 'Roboto Mono', monospace;\n font-size: 2rem;\n}\n.text_hide {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n background-color: white;\n}<\/code><\/pre>\n\n\n
The cursor<\/h3>\n\n\n
.text_cursor<\/code>. The properties are going to be similar to the
.text_hide<\/code> element with a minor difference: instead of setting a
background-color<\/code>, we will keep the
background-color transparent<\/code> (since its technically unnecessary, then add a border to the left edge of the new
.text_cursor<\/code> element.<\/p>\n\n\n\n
.text_cursor{\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n background-color: transparent;\n border-left: 3px solid black;\n}<\/code><\/pre>\n\n\n\n
<\/figure>\n\n\n
JavaScript animation<\/h3>\n\n\n
typing_animation()<\/code>.<\/p>\n\n\n\n
function typing_animation(){\n \/\/ code here\n}\ntyping_animation();<\/code><\/pre>\n\n\n\n
split()<\/code> method. This divides the string into a substring that has only one character and an array containing all the substrings is returned.<\/p>\n\n\n\n
function typing_animation(){\n let text_element = document.querySelector(\".text\");\n let text_array = text_element.innerHTML.split(\"\");\n}<\/code><\/pre>\n\n\n\n
<\/figure>\n\n\n\n
split(\"\")<\/code> with
split(\" \")<\/code>. Note that there is a difference between the two. Here,
\" \"<\/code> acts as a separator. Whenever we encounter a single space, it will terminate the substring and store it as an array element. Then the process goes on for the entire string.<\/p>\n\n\n\n
function typing_animation(){\n let text_element = document.querySelector(\".text\");\n let text_array = text_element.innerHTML.split(\"\");\n let all_words = text_element.innerHTML.split(\" \");\n}<\/code><\/pre>\n\n\n\n
<\/figure>\n\n\n\n
function typing_animation() {\n let text_element = document.querySelector(\".text\");\n let text_array = text_element.innerHTML.split(\"\");\n let all_words = text_element.innerHTML.split(\" \");\n let text_len = text_array.length;\n\n const word_len = all_words.map((word) => {\n return word.length;\n });\n}<\/code><\/pre>\n\n\n\n
map()<\/code> method, which accesses one word at a time from the
all_words<\/code> array and then stores the length of the word into a new array called
word_len<\/code>. Both the arrays have the same number of elements, but one contains the actual word<\/em> as an element, and the other has the length of the word<\/em> as an element.<\/p>\n\n\n\n