WordPressでブログ記事が表示されない!fade-up CSSの落とし穴を実案件で踏み抜いた話
ある案件で「記事ページを開いても本文が真っ白で何も表示されない」という連絡がきた。ヘッダーもフッターも出てるのに、肝心の記事コンテンツだけ見えない。しかも自分の環境では普通に表示される。
調査してみたら、原因は意外なところにあった。スクロールアニメーション用の.fade-upクラスが悪さをしていたという話。この記事では、発生条件・原因・2パターンの対策を実案件ベースで整理する。
「表示されない」の正体
まず状況を整理する。クライアントから「一部のユーザーでブログ記事のコンテンツが表示されない」という報告。ページ自体は読み込まれていて、ヘッダーやサイドバーは正常。でも本文エリアだけが真っ白。
しかも全員に起きるわけじゃなくて、「一部の環境でだけ」発生する。再現条件がはっきりしないやつ。Web制作やってると、こういう「こっちでは再現しない系」の不具合が一番厄介なのを知ってるから、嫌な予感はしていた。
犯人は .fade-up の opacity: 0
DevToolsで記事ページのソースを見ていくと、本文を囲む要素に.fade-upというクラスがついていた。こいつのCSSがこれ。
※「DevTools」とは、ChromeやSafariなどのブラウザに標準搭載された開発者向けツールのこと。HTML構造の確認、CSSの検証、JavaScriptのデバッグなどがブラウザ上でできる。F12キーまたは右クリック→「検証」で開ける。
.fade-up {
opacity: 0;
transition: opacity 0.6s ease;
}
※「opacity」とは、CSSで要素の透明度を指定するプロパティのこと。0で完全に透明、1で完全に不透明になる。
透明インクで書いた文章をイメージするとわかりやすい。紙(DOM)の上にはちゃんと文字が書かれているのに、インクが透明なので目には見えない状態だ。特定の条件が揃ったとき(スクロールして画面内に入ったとき)にインクが発色して見えるようになる仕組みだが、その発色トリガーが動かないと永遠に透明なままになる。
初期状態でopacity: 0(完全に透明)。本来はユーザーがスクロールして要素が画面内に入ったタイミングで、JavaScriptのIntersectionObserverが発火してopacity: 1に切り替わり、フワッと表示される──という仕組みだ。
※「IntersectionObserver」とは、要素が画面内に入ったかどうかを監視するJavaScript APIのこと。スクロールアニメーションの発火タイミング制御などに使われる。
で、問題はここ。このIntersectionObserverが一部の環境で正常に発火しないケースがある。
- 古いブラウザやWebView環境でIntersectionObserver自体が未対応
- JSの読み込み順序の問題で、Observerの登録が間に合わない
- ページ読み込み時に要素がすでにビューポート内にある場合、初回の発火が起きない実装がある
- 広告ブロッカーや拡張機能がスクリプトをブロックしている
※「WebView」とは、アプリ内でWebページを表示するための仕組みのこと。LINEやTwitterのアプリ内ブラウザなどがこれにあたる。通常のブラウザと挙動が異なることがあり、JavaScriptが一部動かないケースもある。
※「ビューポート」とは、ブラウザの画面に実際に表示されている領域のこと。スクロールしていない初期状態で見えている範囲がビューポートにあたる。
※「DOM」とは、HTMLの構造をブラウザが解釈したデータのこと。JavaScriptからHTML要素を操作するときに使う概念で、「ページの骨格」とも言える。
結果としてopacity: 0のまま放置され、コンテンツが「存在してるのに見えない」状態になっていた。要素自体はDOMに存在してるから、選択すればテキストはコピーできる。けど見えない。これは気づきにくい。
対策は2パターン
パターン1:記事本文から fade-up を外す
シンプルに、記事本文エリア(.post-content)からfade-upクラスを取り除く方法。そもそもブログ記事のコンテンツにスクロールアニメーションって必要だろうか。「読んでもらうこと」が最優先なのに、アニメーション演出のせいで表示されないリスクを抱えるのは本末転倒だと思う。
テーマのテンプレートファイルやカスタマイズ画面で、本文を囲む要素からfade-upクラスを削除するだけ。一番確実。
パターン2:CSSフォールバックを入れる
「デザイン的にどうしてもアニメーションは残したい」という場合はこっち。CSSにフォールバックを追加して、JSが動かなくてもコンテンツが見える状態を担保する。
※「CSSフォールバック」とは、メインの処理(ここではJavaScriptによるアニメーション)が動かない場合でも最低限の表示を保証するCSS記述のこと。保険のような役割を果たす。
/* JSが動かなくても表示される */
.post-content .fade-up {
opacity: 1 !important;
}
/* JS有効時のみアニメーション適用 */
.js-enabled .post-content .fade-up {
opacity: 0;
transition: opacity 0.6s ease;
}
.js-enabled .post-content .fade-up.is-visible {
opacity: 1;
}
※「!important」とは、CSSの優先度を強制的に最高にする宣言のこと。他のスタイル指定を上書きしたいときに使うが、多用すると管理が大変になるので注意。
JSが正常に動く環境ではフワッとアニメーション。動かない環境でもコンテンツは確実に表示される。両方カバーできる。
教訓:アニメーションでコンテンツを殺すな
今回あらためて感じたのは、「見た目の演出」と「コンテンツの確実な表示」は別の問題だということ。fade-up系のアニメーションを使うときは、必ず「JSが動かなかったらどうなるか?」を確認しておくべきだった。
CSSの初期値がopacity: 0やdisplay: noneになっている場合、JS依存の表示復帰には必ずフォールバックを用意する。これ、自分の中のチェックリストに追加した。
まとめ
- WordPressで記事コンテンツが表示されない原因として、
.fade-upのopacity: 0+IntersectionObserverの不発が起きうる - 一部環境のみで再現する点が厄介で、気づきにくい
- 対策1:記事本文エリアから
fade-upクラスを外す(最も確実) - 対策2:CSSフォールバックで
opacity: 1を担保し、アニメーションはJS有効時のみ適用 - CSSの初期値を
opacity: 0やdisplay: noneにする場合は、必ずフォールバックを用意する
スクロールアニメーションは演出としては好きだけど、「コンテンツが確実に表示されること」が最優先。ここを見落とすと、せっかく書いた記事が読まれないという笑えない事態になる。同じようなアニメーション実装をしている人は、一度チェックしてみてほしい。
※この記事はNPCの中の人の実務経験をもとに書いています。