Сделаем анимированное старинное письмо. Перо скользит по бумаге, оставляя на ней бессмертные строки. Когда чернила заканчиваются, перо ныряет в чернильницу. иногда случаются ошибки, перо само исправит их.
Разметка
Для письма делаем пустой контейнер, в который будет помещаться текст, и два изображения (для чернильницы и процесса обмакивания пера).
<div id="letter"></div>
<img id="inkwell1" src="inkwell1.gif" alt="inkwell1" />
<img id="inkwell2" src="inkwell2.gif" alt="inkwell2" />
<div id="letter_src">
Цыганы шумною толпой<br>
По биссарбии|||||||||Бессарабии кочуют.<br>
Они сегодня над рекой<br>
В шатрах изодранных ночуют.<br><br>
Как вольность, весел их ночлег<br>
И мирный сон под небесами;<br>
Между кал|||колесами телег,<br>
Полузавешанных коврами,<br><br>
Горит огонь; семья кругом<br>
Готовит усин||||ужин; в чистом поле<br>
Пасутся кони; за шатром<br>
Ручной медведь лежит на воле.<br><br>
Всё живо посреди степей:<br>
Заботы мирные семей,<br>
Готовых с утром в путь недальний,<br>
И песни жен, и хрик||||крик детей,<br><br>
И звон походной наковальни.<br>
Но вот на табор кочевой<br>
Нисходит зонное||||||сонное молчанье,<br>
И слышно в тишине степной<br><br>
Лишь лай собак да каней|||||коней ржанье.<br>
Огни везде погашены,<br>
Спокойно всё, луна сияет<br>
Одна с небесной вышины<br>
И тихий табор озаряет.<br>
</div>
CSS
Зададим стили для нашего письма. Источник текста по умолчанию скрыт.
body {
background: url('bg.jpg') no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
#inkwell1 {
bottom: 100px;
left: 140px;
position: fixed;
}
#inkwell2 {
bottom: 100px;
left: 140px;
position: fixed;
visibility: hidden;
}
#letter {
font-family: Comic Sans MS;
font-size: 18px;
font-weight: bold;
margin: 50px auto;
position: relative;
width: 75%;
}
#letter_src {
display: none;
}
JavaScript
Основная идея - выводить символы один за другим. В зависимости от текущего символа можно устанавливать различные задержки и имитировать ошибки письма. Для отображения расхода чернил используется символ пробела, поэтому каждое слово имеет свой цвет (градацию серого). Как только цвет станет совсем белым, запускаем 'обмакивание пера в чернильницу'.
window.onload = function(){
// Публичные переменные
var vLetter = document.getElementById('letter');
var iSpeedInk = 5;
// Остальные перменные
var sText = document.getElementById('letter_src').innerHTML;
var iCurChar = 0;
var sChars = '<span>';
var iCurInk = 0;
var sCurCaret = '';
var sCaret = " <img src='pen.gif' style='position:absolute' />";
var doStep = function () {
// Текуший символ
var sChar = sText.charAt(iCurChar);
// Задержка символа по умолчанию
var iDelay = 32;
if (sChar == '') {
sCurCaret = '';
} else if (sChar == '|') { // Используем символ | для имитации 'ошибки'
sChar = '';
sChars = sChars.substring(0, sChars.length-1);
iDelay = 64;
} else if (sChar == '<') { // Передаем теги
var iPos = sText.indexOf('>', iCurChar);
sChar = sText.substring(iCurChar, iPos + 1);
iCurChar = iPos;
} else if (sChar == '&') { // Передаем атрибуты html
var iPos = sText.indexOf(';', iCurChar);
sChar = sText.substring(iCurChar, iPos + 1);
iCurChar = iPos;
} else if (sChar == '.') { // Пользовательская задержка для символа .
iDelay = 300;
} else if (sChar == ',') { // Пользовательская задержка для символа ,
iDelay = 100;
} else if (sChar == ' ') { // Пользовательская задержка для пробела
iDelay = 32;
} else if (iCurChar > 5) {
sCurCaret = sCaret;
}
// Расходование чернил
if (sChar == ' ') {
iCurInk += iSpeedInk;
sChar = '</span><span style="color:RGB(' + (iCurInk) + ',' + (iCurInk) + ',' + (iCurInk) + ')">' + sChar;
}
if (document.getElementById('inkwell2').style.visibility == 'visible') {
sCurCaret = sCaret;
document.getElementById('inkwell2').style.visibility = 'hidden';
sChar = '</span><span style="color:RGB(0,0,0)">' + sChar;
}
// Обновление чернил
if (iCurInk > 160) {
iCurInk = 0;
document.getElementById('inkwell2').style.visibility = 'visible';
iDelay = 1000;
sCurCaret = '';
}
// Добавляем текущий символ в строку
sChars += sChar;
// Скрываем каретку после символа
if (iCurChar == sText.length - 1)
sCurCaret = '';
// Обновляем письмо с новыми символами
vLetter.innerHTML = sChars + sCurCaret;
// Переходим к следующему символу
iCurChar++;
// Следующий шаг
if (iCurChar < sText.length) {
setTimeout(doStep, 20 + iDelay);
}
}
doStep();
};