Scroll Text Highlighter Reveal スクロールハイライトテキストリビール
Words illuminate progressively line by line in response to scroll progression. ユーザーのスクロールリズムに合わせて単語が次々と光を帯びて浮かび上がる読書体験向上演出。
ライブデモ Live Demo
概要・用途・特徴Overview, Usage & Features
何ができるかWhat it does
An editorial text experience where paragraphs illuminate progressively word-by-word as visitors scroll down.
スクロールに合わせて薄暗い単語が順次ホワイトやアクセントカラーで発光し、読み進めるリズムを作るタイポグラフィ演出です。
どこで使うかWhere to use
Commonly featured in Apple/Linear-style story pages, landing page manifestos, and key company statements.
AppleやLinearのような高品質なブランド紹介ページ、理念表明、プロダクトの核となるメッセージ部分に最適です。
特徴Key features
Tokenized word spans, relative scroll offset detection, luminous text-shadow glow, responsive typography.
単語ごとのスパン分割、相対スクロール位置判定、柔らかな文字グロー光彩、レスポンシブな文字サイズ設計。
調整可能パラメータ Adjustable Parameters
| Parameter | Default | Description |
|---|---|---|
highlight-color | #38bdf8 | Active word focal glow color |
実装コード Implementation Code
<div class="m022-viewport" id="scrollArea">
<p class="m022-text-flow">
<span class="m022-word is-lit">Great</span>
<span class="m022-word is-focus">software</span>
<span class="m022-word">experiences...</span>
</p>
</div>
.m022-text-flow {
font-size: 1.2rem;
line-height: 1.8;
font-weight: 600;
}
.m022-word {
display: inline-block;
opacity: 0.3;
color: rgba(148, 163, 184, 0.25);
transition: all 0.25s ease;
}
.m022-word.is-lit {
color: #f8fafc;
opacity: 1;
}
.m022-word.is-focus {
color: var(--m022-highlight-color, #38bdf8);
opacity: 1;
text-shadow: 0 0 16px var(--m022-highlight-color, #38bdf8);
}
import React, { useRef, useEffect } from 'react';
import './M-022.css';
export default function ScrollTextHighlighter({
text = 'Great software experiences should feel as fluid and effortless as natural thought.',
highlightColor = '#38bdf8'
}) {
const viewportRef = useRef(null);
const words = text.split(/\s+/);
useEffect(() => {
const vp = viewportRef.current;
if (!vp) return;
const onScroll = () => {
const trigger = vp.scrollTop + vp.clientHeight * 0.55;
const elements = vp.querySelectorAll('.m022-word');
elements.forEach(el => {
const top = el.offsetTop;
if (top < trigger - 35) {
el.className = 'm022-word is-lit';
} else if (top < trigger) {
el.className = 'm022-word is-focus';
} else {
el.className = 'm022-word';
}
});
};
vp.addEventListener('scroll', onScroll, { passive: true });
onScroll();
return () => vp.removeEventListener('scroll', onScroll);
}, [text]);
return (
<div className="m022-stage" style={{ '--m022-highlight-color': highlightColor }}>
<div className="m022-viewport" ref={viewportRef}>
<p className="m022-text-flow">
{words.map((w, i) => (
<span key={i} className="m022-word">{w} </span>
))}
</p>
</div>
</div>
);
}
.m022-stage {
position: relative;
width: 100%;
max-width: 620px;
border-radius: 16px;
background: #090d16;
border: 1px solid rgba(148, 163, 184, 0.2);
overflow: hidden;
}
.m022-viewport {
height: 300px;
overflow-y: auto;
padding: 36px 28px;
}
.m022-text-flow {
font-size: 1.2rem;
line-height: 1.8;
font-weight: 600;
}
.m022-word {
display: inline-block;
opacity: 0.3;
color: rgba(148, 163, 184, 0.25);
transition: all 0.25s ease;
}
.m022-word.is-lit {
color: #f8fafc;
opacity: 1;
}
.m022-word.is-focus {
color: var(--m022-highlight-color, #38bdf8);
opacity: 1;
text-shadow: 0 0 16px var(--m022-highlight-color, #38bdf8);
}
仕組みとカスタマイズHow It Works & Customization
仕組みHow it works
Splits body copy into inline words, calculating each word offset relative to a scroll trigger line (55% viewport height) to toggle lighting states.
文章を単語単位のインラインスパンに分解し、ビューポート中央(約55%位置)のトリガー線との交差判定で .is-lit や .is-focus クラスを動的に制御します。
カスタマイズ方法Customization
Customize highlight color using CSS custom property --m022-highlight-color and adjust trigger thresholds in script.
CSSカスタムプロパティ(--m022-highlight-color)で現在行のハイライト発光色を変更できます。
注意点Caveats
For large paragraphs, ensure words are batched or throttled to avoid excessive layout reads during rapid touch flings.
大量の長文に適用する場合は、スクロールハンドラーの間引き(throttle)や単語のoffsetTopキャッシュを行ってください。
よくある質問 Frequently Asked Questions
How can I support Japanese text without spaces? 日本語など空白で区切られていないテキストに対応できますか?
Tokenize by punctuation marks (、。) or use a client-side phrase segmentation library like Intl.Segmenter.
句読点での分割や、モダンブラウザ標準の Intl.Segmenter API を使用して文節単位にスパン分割することで綺麗に対応できます。
Can I style past words differently from unread words? 読了済みの単語と未読の単語でスタイルを変えられますか?
Yes, .is-lit targets fully illuminated past words, while unread words retain the default muted opacity.
はい、通過済みの単語には .is-lit が付与され、未読単語は薄暗い透過色のまま維持されます。
AIへの指示テンプレート AI Prompt Template
以下をAIに貼り付けると実装を依頼できます。 Paste the following into your AI assistant to request implementation.