Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Letter-by-letter text appearance animation with CSS

I have a <div> with text.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, 
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

I'd like the text in this <div> to appear on page one character at a time:

L

Lo

Lor

... and so on, until the full text is visible

Acceptable alternative: do that one word at a time, to avoid problems with HTML entities and jumpy words due to soft hyphenation.

If user clicks on the <div>, it should cancel the animation and display the full text instantly.

In short, I want to imitate an animation that is frequently seen in Japanese-style adventure games. (I think that this is sometimes called a typewriter or teletype effect.) Here is a good example:

http://www.youtube.com/watch?feature=player_detailpage&v=SasgN0lim7M#t=418

Obviously, I can script the animation using JavaScript — just set up a timer and append letters (or words) one-by-one.

But is it possible to do what I need with CSS in modern browsers? (Of course, I'd need to at least change element class in the onclick with JS, but that's OK.)

Update: To clarify on characters vs. letters and problems with HTML entities:

My text is littered with the HTML:

Lo&shy;rem <i>ip&shy;sum</i>.

Naïve approach with appending text to the innerHTML character-by-character wouldn't work:

L

Lo

Lo&

...Doh!
like image 288
Alexander Gladysh Avatar asked Nov 04 '13 11:11

Alexander Gladysh


3 Answers

You can achieve this with a bit of jQuery.

Check out my fiddle: http://jsfiddle.net/kA8G8/7/

HTML

<p class="typewriter">Nullam id dolor id nibh ultricies vehicula ut id elit. Maecenas faucibus mollis interdum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p>

JS

var text = $('.typewriter').text();

var length = text.length;
var timeOut;
var character = 0;


(function typeWriter() { 
    timeOut = setTimeout(function() {
        character++;
        var type = text.substring(0, character);
        $('.typewriter').text(type);
        typeWriter();

        if (character == length) {
            clearTimeout(timeOut);
        }

    }, 150);
}());
like image 112
Charles Ingalls Avatar answered Oct 13 '22 02:10

Charles Ingalls


Unfortunately you cannot do this with CSS so you will have to revert to a pure JS approach.

As your comments have explained, you require your text to contain some HTML markup so I would suggest a word-by-word animation being the easiest way to handle that. Something like this:

var timer, fullText, currentOffset, onComplete, wordSet;

function Speak(person, text, callback) {
    $("#name").html(person);
    fullText = text;
    wordSet = text.split(" ");
    currentOffset = 0;
    onComplete = callback;
    timer = setInterval(onTick, 300);
}

function onTick() {
    currentOffset++;
    if (currentOffset == wordSet.length) {
        complete();
        return;
    }
    var text = "";
    for(var i = 0; i < currentOffset; i++){
     text += wordSet[i] + " ";   
    }
    text.trim();
    $("#message").html(text);
}

function complete() {
    clearInterval(timer);
    timer = null;
    $("#message").html(fullText);
    if (onComplete) onComplete();
}

$(".box").click(function () {
    complete();
});

Speak("Simon",
    "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",

function () {
    setTimeout(function () {
        Speak("Javascript", "Simon has finished speaking!");
    }, 2000);
});

Here is a working example

NOTE: This code can likely be vastly re-factored to be more efficient and concise, but it should demonstrate the concept in full.


I also created a letter-by-letter example. Although it doesn't support you html markup needs, it does look nicer so perhaps you can adapt it to work for you.

like image 27
musefan Avatar answered Oct 13 '22 01:10

musefan


There is a pure CSS trick to do this.

Use a mask element, even a pseudo element p:before or p:after with a higher z-index than your text element. Give it the same color as the text background and the height of a line. Place it with absolute position just above the text.

Then you just have to animate it to make it move to the right, unmasking letter by letter. It's just a workaround, because if you have a complex background under the text, like an image, then this trick is difficult to reproduce because you will have to map the background image on the masking element.

like image 37
user2451013 Avatar answered Oct 13 '22 02:10

user2451013