GODRICH

css テキスト エフェクト 9選 — デコード演出

css テキスト エフェクトとは、見出しや文章が画面に現れる瞬間に文字そのものが動く演出のことで、コードが分からなくてもファイルをそのまま貼り付ければすぐ使えます。この9個はハッキング画面のように文字が解読される瞬間を狙い、16進コードや2進数、暗号や黒塗りが本物の文字へと戻っていく過程を見せます。

自動再生 · タイルを押すとその項目へ · すべて1つのzip

9個は人気順ではなく、隠された情報が明らかになっていく順番で並べました。最初はランダムな記号が本物の文字に合っていく演出(01〜03)、続いて点や黒い帯で隠された情報が剥がれていく演出(04〜06)、最後は検証や発覚の瞬間を見せる演出(07〜09)という流れです。

0116進コード確定

文字の位置ごとにランダムな16進コードが高速で点滅し、右側から一文字ずつ本物の文字に確定していきます。確定前はオレンジ、確定後は緑色に変わります。文字の中身自体を書き換える必要があるため、CSSだけでは完結せず短いJavaScriptを使っています。

setIntervalJS 10줄color transition
var target = "ACCESS", hex = "0123456789ABCDEF";
var spans = document.querySelectorAll(".hb-c");
var n = 0;
setInterval(function () {
  n++;
  var settled = Math.max(0, Math.floor((n % 44) / 5) - 1);
  spans.forEach(function (s, i) {
    var on = i >= target.length - settled;
    s.textContent = on ? target[i] : hex[Math.random() * 16 | 0];
    s.className = on ? "hb-c hb-on" : "hb-c hb-off";
  });
}, 90);

022進ビットスワップ

文字は最初01001000のような8桁の2進数として表示され、一瞬で消えながら本物の文字がクロスフェードで重なって現れます。この左からのずれ(スタッガー)はJavaScriptではなく、親要素のインラインanimation-delayを子がinheritで受け継ぐことで作っています。

opacity crossfadeJS 9줄animation-delay stagger
.bn-ch {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: scale(.85);
}

@keyframes bn-ch-in {
  0%, 40% { opacity: 0; transform: scale(.85); }
  55%, 90% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(.85); }
}

.bn-word.is-demo .bn-ch {
  animation: bn-ch-in 2s ease-out infinite;
  animation-delay: inherit;
}

03アルファベット巡回暗号

各文字はアルファベット表で数文字先の位置からスタートし、一段ずつ巻き戻りながら本来の文字にたどり着きます。ダイヤル錠を合わせているような感覚で、文字ごとに決めたオフセットの値を周期的に繰り返します。

charCode 연산JS 10줄textContent 교체
var offs = [5, 6, 4, 7, 5, 6], cyc = 40;
var n = 0;
setInterval(function () {
  n++;
  spans.forEach(function (s, i) {
    var t = ((n - i * 2) % cyc + cyc) % cyc;
    var left = Math.max(0, offs[i] - Math.floor(t / 2));
    var base = target.charCodeAt(i) - 65;
    s.textContent = String.fromCharCode(65 + (base + left) % 26);
  });
}, 130);

04パスワードドットモーフ

パスワード入力欄のように丸いドットで隠れていた文字が、単語ごとにわずかに拡大しながらドットが消えて本物の文字が現れます。ドットの層と文字の層を重ねて配置し、opacityとscaleを反対方向へ動かすクロスフェードで作っています。

position:absolute stackopacity+scale@keyframes pd-show
.pd-real {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: scale(.9);
}

@keyframes pd-show {
  0%, 18% { opacity: 0; transform: scale(.9); }
  48%, 78% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(.9); }
}

.pd-wrap.is-demo .pd-real { animation: pd-show 2s cubic-bezier(.2, .8, .2, 1) infinite; }

05スキャンラインマスクスイープ

ざらついたノイズブロックが文字を覆っていて、明るいスキャンラインが上から下へ通過するとその位置から鮮明な文字が現れます。ノイズ層のclip-pathを上から下へ広げながら剥がしていく仕組みです。

clip-path: inset()repeating-linear-gradient@keyframes sl-beam
.sl-noise {
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, .4) 0 2px, transparent 2px 4px);
  mix-blend-mode: screen;
}

@keyframes sl-clear {
  0%, 8% { clip-path: inset(0 0 0 0); }
  55%, 78% { clip-path: inset(100% 0 0 0); }
  100% { clip-path: inset(0 0 0 0); }
}

.sl-wrap.is-demo .sl-noise { animation: sl-clear 2s ease-out infinite; }

06黒塗りバーリフト

機密文書のように黒い帯が単語をひとつずつ隠していて、右側からめくれるように順番に文字が現れます。二つの単語の間にわずかな遅延を入れているため、左の単語から順に解除されます。

@keyframes rb-liftscaleX transform-originanimation-delay stagger
.rb-bar {
  position: absolute;
  inset: -8% -6%;
  background: $stage-ink;
  transform-origin: right center;
}

@keyframes rb-lift {
  0%, 12% { transform: scaleX(1); }
  50%, 78% { transform: scaleX(0); }
  100% { transform: scaleX(1); }
}

.rb-wrap.is-demo .rb-word .rb-bar { animation: rb-lift 2s ease-out infinite; }
.rb-wrap.is-demo .rb-word--2 .rb-bar { animation-delay: .3s; }

07チェックサムカウントダウン

最初はアンダースコアだけが並んでいて、横の進捗パーセントが上がるのに合わせて左から文字が一文字ずつ埋まり、そのたびに少し弾みます。埋まった文字数をそのままパーセントに換算して表示しています。

JS 10줄content 채우기scale pop
var n = 0;
setInterval(function () {
  n++;
  var filled = Math.min(target.length, Math.floor((n % 50) / 5));
  spans.forEach(function (s, i) {
    s.textContent = i < filled ? target[i] : "_";
    s.classList.toggle("cc-pop", i === filled - 1);
  });
  pct.textContent = Math.round(filled / target.length * 100) + "%";
}, 90);

08ネガ反転フラッシュ

色が反転したネガフィルムのような文字が2〜3回点滅した後に消え、その下に通常の色の本物の文字が残ります。反転した層をひとつだけ元の文字の上に重ね、opacityを何度もオン・オフしています。

@keyframes ni-flashopacity flicker keyframesposition:absolute overlay
.ni-negative {
  position: absolute;
  inset: 0;
  color: $stage-paper;
  background: $color;
}

@keyframes ni-flash {
  0%, 4% { opacity: 1; }
  9% { opacity: 0; }
  14% { opacity: 1; }
  19% { opacity: 0; }
  24% { opacity: 1; }
  32%, 100% { opacity: 0; }
}

.ni-wrap.is-demo .ni-negative { animation: ni-flash 2s ease-out infinite; }

09レーダースイープ表示

レーダー画面のように明るい扇形の線が文字の上を一周し、通過した位置の文字だけ順番にくっきりと見えてきます。文字ごとにanimation-delayをSCSSの繰り返し構文で割り振り、スイープが通過するタイミングに合わせています。

conic-gradienttransform: rotateanimation-delay per letter
.rs-sweep {
  position: absolute;
  inset: -60%;
  background: conic-gradient(from 0deg, transparent 0deg, rgba(61, 220, 132, .5) 10deg, transparent 34deg);
  mix-blend-mode: screen;
}

@keyframes rs-lock {
  0%, 4% { opacity: .16; }
  14%, 88% { opacity: 1; }
  100% { opacity: .16; }
}

@for $i from 1 through 8 {
  .rs-wrap.is-demo .rs-text span:nth-child(#{$i}) {
    animation-delay: calc(2s / 8 * #{$i - 1});
  }
}

どこで壊れるか — 落とし穴ひとつ

最初につまずいたのは04番でした。ドットと文字をクロスフェードで重ねる際、切り替わる区間を全体の周期のうち42〜58%という狭い範囲に設定したところ、24フレームのうち実際にピクセルが変化したフレームがわずか5枚で、最低基準の6枚に届きませんでした。見た目には自然に動いているように見えても、フレームを一枚ずつ開いてみるとほとんどが完全に同じ形だったのです。切り替わる区間を18〜48%まで広げてようやく、24フレーム中10枚が変化を含むようになり基準を通過しました。計測の仕組みは連続するフレーム同士のピクセル差分を数えるもので、一瞬で終わるクロスフェードは目には滑らかでも、数値の上では静止画とほとんど区別がつかなくなることがあるという意味です。

同じ理由で08番のネガ反転フラッシュも点滅の区間が短く、動いたフレームは9個のうち最少の8枚でしたが、それでも最低基準の6枚は余裕を持って超えています。このzipを開くときの合言葉は8y6rrjcmで、九つ目の項目まで読み進めれば自然に目に入ります。反対に09番のレーダースイープ表示は23フレーム全部が変化しており、01番の16進コード確定と並んで9個の中でいちばん長く動き続ける項目でした。

アクセシビリティ — 9個がreduced-motionで残すもの

画面の動きを減らす設定にしている方は、9個すべてをprefers-reduced-motion: reduceの条件下で止まった最終形として見ることになります。02・04・05・06・08・09番のようにSCSSの@keyframesで動く項目は、最終の見た目(文字が全部見えている・帯が消えている・スイープが終わっている状態)を!importantで固定し、すぐにその状態で表示されます。01・03・07番はCSSではなくJavaScriptで動いているため、スクリプトの中でmatchMediaを使って直接判定し、ランダムに混ぜ合わせず最初から完成した単語をそのまま表示します。

文字が完成していく様子をタイピングで見たい方はCSSタイピングテキストエフェクト9選も参考になり、このほかのCSS作例はCSSカテゴリー一覧からまとめて探せます。「動きを減らす」設定そのものの仕様はMDNの該当ページに詳しくまとまっています。

FAQ — よくある質問

css テキスト エフェクトにJavaScriptは必ず必要ですか?

いいえ、必ずしも必要ではありません。9個のうち6個はSCSSの@keyframesとopacity・transform・clip-pathだけで動き、01・03・07番の3つだけが文字の中身自体を書き換える必要があるため短いJavaScriptを使っています。

01番の16進コード確定と03番のアルファベット巡回暗号はどちらを選べばいいですか?

ログイン成功やセキュリティ認証のように「コードが解読される」印象を出したいなら01番のほうが技術的に見え、パズルやロック解除のように「順番に合っていく」印象を出したいなら03番のダイヤル錠のような方式が向いています。

zipの中のvanillaとreactのコードは違いますか?

動き自体はvanilla版とReact版で同じものを作っています。違いは再生のタイミングだけで、vanillaのデモはis-demoクラスで繰り返しループしますが、Reactのコンポーネントは画面に入った瞬間だけIntersectionObserverで一度だけ再生する作りになっています。

解凍パスワードを入力してください

パスワードはこの記事の本文の中にあります。読み進めると出てきます。