var typewrite = function(str) { var p, nChar, strStyle, d = 2; var arrP = document.querySelectorAll(str); var style = document.documentElement.appendChild(document.createElement("style")); for (var i = 0; i < arrP.length; i++) { p = arrP[i]; p.className += " typewrite "; nChar = p.textContent.length; // 1 // set @keyframes using CSSOM: "from" and "to" derived from <p> offsetWidth var rule = p.id + "_typing {from {width: 0} to {width: " + p.offsetWidth + "px}}"; if (CSSRule.KEYFRAMES_RULE) // W3C style.sheet.insertRule("@keyframes " + rule, 0); else if (CSSRule.WEBKIT_KEYFRAMES_RULE) // WebKit style.sheet.insertRule("@-webkit-keyframes " + rule, 0); else if (CSSRule.MOZ_KEYFRAMES_RULE) // Moz style.sheet.insertRule("@-moz-keyframes " + rule, 0); // 2 // define animation end rule = "{width: auto;}"; style.sheet.insertRule("#" + p.id + ".end" + rule, 0); // 3 // set animation: steps # is derived from text length inside <p> strStyle = p.id + "_typing " + d + "s steps(" + nChar + ", end) " + i * d + "s"; p.style["animation"] = strStyle; p.style["-webkit-animation"] = strStyle; p.style["MozAnimation"] = strStyle; p.style["-ms-animation"] = strStyle; // 4 // start animation p.className += " startTypewrite "; // 5 // animation event handlers p.addEventListener("animationend", typewrite_cb, false); p.addEventListener("webkitAnimationEnd", typewrite_cb, false); } }; // 6 // callback function: set .end class on <p> var typewrite_cb = function(e) { e.target.className += " end "; }; // 7 // start typing animation typewrite("#text1, #text2, #text3");
<ul> <li><p id="text1">Text one...</p></li> <li><p id="text2">Text two...</p></li> <li><p id="text3">Text three...</p></li> </ul>
body { font-family: Consolas, monospace; font-size: 1.2em; } ul { list-style: none; } p.typewrite { display: inline-block; white-space: nowrap; overflow: hidden; } p.startTypewrite { width: 0; }