【CSS&jQuery】タイプエフェクトでテキストを変更していくCSSアニメーション

こんにちは。
もうそろそろ2014年終わりますね。ほんとあっという間でびっくりします。

さて、今回はCSSアニメーション(動作の指示にJSも入ってきます)でタイプエフェクトのようなものを実装します。といってもよくわからないのでまずは出来上がりのイメージをどうぞ。

See the Pen ByLwvG by Tsukasa Nagata (@nt-uni) on CodePen.0

CSSアニメーションの設定

さっそくCSSを見ていきましょう。
カーソルのバーが.cd-headline.type .cd-words-wrapper::afterで表現されていますね。

※サンプルには各ブラウザ用のベンダープレフィックスを省略しています

/* --------------------------------

xtype

-------------------------------- */
.cd-headline.type .cd-words-wrapper {
  vertical-align: top;
  overflow: hidden;
}
.cd-headline.type .cd-words-wrapper::after {
  /* vertical bar */
  content: '';
  position: absolute;
  right: 0;
  top: 50%;
  bottom: auto;
  transform: translateY(-50%);
  height: 90%;
  width: 1px;
  background-color: #aebcb9;
}
.cd-headline.type .cd-words-wrapper.waiting::after {
  animation: cd-pulse 1s infinite;
}
.cd-headline.type .cd-words-wrapper.selected {
  background-color: #aebcb9;
}
.cd-headline.type .cd-words-wrapper.selected::after {
  visibility: hidden;
}
.cd-headline.type .cd-words-wrapper.selected b {
  color: #0d0d0d;
}
.cd-headline.type b {
  visibility: hidden;
}
.cd-headline.type b.is-visible {
  visibility: visible;
}
.cd-headline.type i {
  position: absolute;
  visibility: hidden;
}
.cd-headline.type i.in {
  position: relative;
  visibility: visible;
}

@keyframes cd-pulse {
  0% {
    transform: translateY(-50%) scale(1);
    opacity: 1;
  }
  40% {
    transform: translateY(-50%) scale(0.9);
    opacity: 0;
  }
  100% {
    transform: translateY(-50%) scale(0);
    opacity: 0;
  }
}

ここで重要なのは、animation: cd-pulse 1s infinite;ですね。
これで@keyframes cd-pulseを実行しています。

JSでクラスの付け替え

jQueryでクラスを付け替えています。

$(document).ready(

function($){
  var animationDelay = 2500;
  var typeLettersDelay = 150;
  var selectionDuration = 300;
  var typeAnimationDelay = 1100;

     initHeadline();


     function initHeadline() {
          //initialise headline animation
          singleLetters($('.cd-headline').find('b'));
          animateHeadline($('.cd-headline'));
     }

     function singleLetters($words) {
          $words.each(function(){
               var word = $(this),
                    letters = word.text().split(''),
                    selected = word.hasClass('is-visible');
               for (i in letters) {
                    if(word.parents('.rotate-2').length > 0) letters[i] = '<em>' + letters[i] + '</em>';
                    letters[i] = (selected) ? '<i class="in">' + letters[i] + '</i>': '<i>' + letters[i] + '</i>';
               }
              var newLetters = letters.join('');
              word.html(newLetters);
          });
     }

     function animateHeadline($headlines) {
          var duration = animationDelay;
          $headlines.each(function(){
               var headline = $(this);
               if(headline.hasClass('loading-bar')) {
                    duration = barAnimationDelay;
                    setTimeout(function(){ headline.find('.cd-words-wrapper').addClass('is-loading') }, barWaiting);
               } else if (headline.hasClass('clip')){
                    var spanWrapper = headline.find('.cd-words-wrapper'),
                         newWidth = spanWrapper.width() + 10
                    spanWrapper.css('width', newWidth);
               } else if (!headline.hasClass('type') ) {
                    //assign to .cd-words-wrapper the width of its longest word
                    var words = headline.find('.cd-words-wrapper b'),
                         width = 0;
                    words.each(function(){
                         var wordWidth = $(this).width();
                        if (wordWidth > width) width = wordWidth;
                    });
                    headline.find('.cd-words-wrapper').css('width', width);
               };

               //trigger animation
               setTimeout(function(){ hideWord( headline.find('.is-visible').eq(0) ) }, duration);
          });
     }

     function hideWord($word) {
          var nextWord = takeNext($word);

          if($word.parents('.cd-headline').hasClass('type')) {
               var parentSpan = $word.parent('.cd-words-wrapper');
               parentSpan.addClass('selected').removeClass('waiting');    
               setTimeout(function(){
                    parentSpan.removeClass('selected');
                    $word.removeClass('is-visible').addClass('is-hidden').children('i').removeClass('in').addClass('out');
               }, selectionDuration);
               setTimeout(function(){ showWord(nextWord, typeLettersDelay) }, typeAnimationDelay);

          } else if($word.parents('.cd-headline').hasClass('letters')) {
               var bool = ($word.children('i').length >= nextWord.children('i').length) ? true : false;
               hideLetter($word.find('i').eq(0), $word, bool, lettersDelay);
               showLetter(nextWord.find('i').eq(0), nextWord, bool, lettersDelay);

          }  else if($word.parents('.cd-headline').hasClass('clip')) {
               $word.parents('.cd-words-wrapper').animate({ width : '2px' }, revealDuration, function(){
                    switchWord($word, nextWord);
                    showWord(nextWord);
               });

          } else if ($word.parents('.cd-headline').hasClass('loading-bar')){
               $word.parents('.cd-words-wrapper').removeClass('is-loading');
               switchWord($word, nextWord);
               setTimeout(function(){ hideWord(nextWord) }, barAnimationDelay);
               setTimeout(function(){ $word.parents('.cd-words-wrapper').addClass('is-loading') }, barWaiting);

          } else {
               switchWord($word, nextWord);
               setTimeout(function(){ hideWord(nextWord) }, animationDelay);
          }
     }

     function showWord($word, $duration) {
          if($word.parents('.cd-headline').hasClass('type')) {
               showLetter($word.find('i').eq(0), $word, false, $duration);
               $word.addClass('is-visible').removeClass('is-hidden');

          }  else if($word.parents('.cd-headline').hasClass('clip')) {
               $word.parents('.cd-words-wrapper').animate({ 'width' : $word.width() + 10 }, revealDuration, function(){
                    setTimeout(function(){ hideWord($word) }, revealAnimationDelay);
               });
          }
     }
});

is-visibleの付け替えで次々と文字を入れ替えてます。その前後のアニメーションも見事に連携してます。

まとめ

以前ご紹介した@keyframesの応用ですね。
ここまでいくとコードの量もそれなりに多くなってきます。
@keyframesについての解説はこちらを → 【CSS】@keyframesって何?CSSのアニメーションを知る | unitopi

CSSのアニメーションによる効果が大きいのでブラウザの対応は気にしてみてくださいね!

参考:CSS Animated Headlines | CodyHouse

フォローして続編をチェック

@universionsをフォロー