言語学サイトのWordPressテーマを開発中、ブロックエディタの「カラム」ブロックが突然機能しなくなった。2カラムレイアウトを設定しても、コンテンツが縦に積み重なってしまう。 調査の結果、functions.phpの誤った設定が原因だと判明した。不要なスタイルを削除しようとして、wp-block-libraryをdequeueしていたのだ。 wp-block-libraryは、WordPressのブロックエディタが生成するすべてのブロックの基本スタイルを含んでいる。これを削除すると、カラムブロックだけでなく、ギャラリー、引用、ボタンなど、すべてのブロックが正しく表示されなくなる。 正しいアプローチは、wp-block-libraryを保持しつつ、テーマでブロックスタイルのサポートを明示的に宣言することだった。 この一行を追加することで、WordPressはテーマがブロックエディタと互換性があることを認識し、適切なスタイルを適用する。 同時に、年表(Chronology)セクションのリファクタリングも行った。複雑なHTMLテーブルを廃止し、新しいショートコードシステム([chronology_section])に置き換えた。このショートコードは、functions.phpで定義され、モバイルレスポンシブな年表テーブルを生成する。 モバイルCSS版でも苦労した。年表テーブルが小さな画面で崩れていた。最終的に、完全に書き直したchronology.css(v4)を作成し、flexboxベースのレスポンシブレイアウトを実装した。 現在、言語学サイトのWordPressテーマは、ブロックエディタと完全に互換性がある。カラムブロックは正しく動作し、年表セクションはすべてのデバイスで読みやすく表示される。
言語学ポータルサイトの「モンゴル語学の歴史」年表ページで、21世紀セクションの構造を整理した。当初、テーブルの上部に2行の「概要行」があり、その後に2000年代、2010年代、2020年代の詳細が続いていた。 しかし、この概要行は冗長だった。21世紀が「進行中の過程」であることは、2020年代のセクションを見れば明らかだ。わざわざ冒頭で述べる必要はない。 そこで、2つの概要行を削除し、年代見出し(2000年代、2010年代、2020年代)だけに依存する構造に変更した。これにより、テーブルの構造が明確になり、各年代のセクションが等しく扱われるようになった。 同時に、概念的なスタンスは維持した。21世紀は「完結した歴史的時代」ではなく「進行中のプロセス」だという認識だ。これはコンテンツの書き方(現在形の使用、暫定的な評価など)に反映されている。 視覚的な改善として、年代見出しに軽い背景色を付けることも検討している。ただし、これはデザインの方向性を先に決める必要がある。選択肢は3つだ: この選択は、サイト全体のデザイン言語に影響するため、慎重に決定する必要がある。現時点では、シンプルな構造の整理だけを実施し、視覚的な装飾は保留としている。
辞書サイト(itako-dict)と言語学ポータル(linguistics)で、スマートフォンでの表示が崩れているという報告を受けた。3カラムレイアウト(左サイドバー、メインコンテンツ、右サイドバー)が横並びのままで、メインコンテンツが押し潰されて読めない状態だった。 原因を調査したところ、共有CSSファイル(/shared-assets/css/dict-style.css)にモバイル用のメディアクエリが完全に欠けていることが判明した。デスクトップ版のCSSしか定義されていなかったため、小さな画面でも3カラムレイアウトが維持されていた。 解決策は、適切なメディアクエリを追加することだった。画面幅780px以下の場合、レイアウトをdisplay: flexとflex-direction: columnで縦積みに変更する。さらに、表示順序も調整する必要があった。モバイルでは、メインコンテンツ→左サイドバー→右サイドバーの順が最も読みやすい。 この修正を共有CSSファイルに適用したことで、itako-dictとlinguisticsの両サイトが同時に修正された。これが共有アセットアーキテクチャの利点だ。 さらに、両サイトのfunctions.phpでCSSのバージョン番号を’2.4’から’2.5’に更新した。これにより、ユーザーのブラウザキャッシュが強制的にクリアされ、新しいCSSが確実に読み込まれる。 現在、両サイトはすべてのデバイスサイズで正しく表示される。デスクトップでは3カラムレイアウト、タブレットでは2カラム、スマートフォンでは1カラムと、画面サイズに応じて適切にレイアウトが変化する。モバイルUXが大幅に改善された。
小説翻訳サイト(Khokh Sudar)で、ヘッダーが上部に固定されない問題が発生した。position: stickyを指定していたにもかかわらず、スクロールしてもヘッダーが画面上部に留まらなかった。 デバッグの結果、CSSセレクターの衝突が原因だと判明した。テーマのCSSには.pageというクラスのスタイルが定義されていたが、WordPressの静的ページでは<body>タグに自動的に.pageクラスが付与される。このため、ページ全体のレイアウトが意図しない形で変更されていた。 問題のあったCSS: このスタイルが<body class=”page”>に適用されると、position: stickyの親要素がflexboxコンテナになってしまう。position: stickyは特定の条件下でしか機能せず、親要素のレイアウトモデルによっては動作しない。 解決策は、セレクターをより具体的にすることだった。.pageの代わりに#main-contentというユニークなIDを使用し、そのIDを持つ要素にのみレイアウトスタイルを適用する。 これにより、<body>タグのスタイルが変更されることなく、意図した要素にのみレイアウトが適用される。 副次的な問題も修正した。functions.phpでJavaScriptファイルを読み込む際、静的サイト用のanagura-nav.jsを指定していたが、WordPressサイトではanagura-wp-nav.jsを使う必要があった。この間違いにより、モバイルメニューが機能していなかった。 タイポグラフィも調整した。メインのフォントサイズは読みやすさのため16pxに戻し、フッターのみ14pxの小さいフォントを使用する。これにより、視覚的な階層が明確になった。 現在、Khokh Sudarサイトはすべてのデバイスで正しく動作している。ヘッダーは画面上部に固定され、モバイルメニューも機能し、フォントサイズも適切だ。
Anagura Hubサイト(itako999.com/anagura/)で、メインコンテンツのグリッドカードがクリックできないという問題が発生した。各カードには見出し内に<a>タグがあるが、カード全体をクリック可能にしたかった。 最初、CSS-onlyソリューション(::before疑似要素で透明なオーバーレイを作成)を試みたが、これが既存のyurt-style.cssのグリッドレイアウトを破壊してしまった。CSSの特異性(specificity)とカスケードの問題で、意図しないスタイルが適用されていた。 最終的に、JavaScriptによる解決策を採用した。anagura-nav.jsにクリックリスナーを追加し、.hub-card要素をクリックしたら、その内部の<h2> <a>のリンク先にナビゲートする。 この実装には重要なチェックが含まれている。!e.target.closest(‘a’)により、ユーザーが直接<a>タグをクリックした場合は、イベントが重複して発火しないようにしている。 もう一つの問題は、動的に生成されるナビゲーションバーのリンクが正しく機能していなかったことだ。これはブラウザキャッシュが原因だった。JavaScriptファイルを更新してもブラウザが古いバージョンをキャッシュしていたため、変更が反映されなかった。HTMLの<script>タグにバージョンパラメータ(?v=2)を追加することで、キャッシュバスティングを実現した。 現在、Anagura Hubのすべてのリンクは正しく機能している。動的ナビゲーションバーもグリッドカードも、ルート相対パス(/linguistics/など)を使用し、どのページからアクセスしても正しいURLに遷移する。
辞書データベースサイト(Dict-DB)で、クライアントサイドJavaScriptによる動的フィルタリングを実装した。サーバーサイドのページリロードなしで、即座にフィルタリング結果が表示される。 データ構造: フィルタリングロジック: 3つのドロップダウン(Language、Category、Decade)の組み合わせでフィルタリング: 結果の表示: フィルタリング結果をカードレイアウトで表示: 初期ソート: デフォルトでは、最新の辞書が最初に表示される(逆時系列): パフォーマンス最適化: 420件以上のエントリでも、フィルタリングは瞬時に完了する。配列のフィルタ操作はJavaScriptエンジンで最適化されており、このサイズのデータセットでは十分高速だ。 さらに大規模なデータセットでは、以下の最適化を検討できる: 現在、Dict-DBのフィルタリングは快適に動作している。ユーザーはドロップダウンを変更すると、即座に結果が更新されるのを見ることができる。
Anaguraプロジェクトの複数サイト(Hub、Blog、Dict-DB、Khokh Sudar、Linguistics)で、ナビゲーションとフッターを統一するため、JavaScriptによる動的生成システムを実装した。 課題: 各サイトで手動でナビゲーションリンクを管理していたため、リンク追加や変更のたびに、すべてのHTMLファイルを編集する必要があった。これは非効率で、エラーも発生しやすい。 解決策: anagura-nav.jsに、すべてのナビゲーションデータを一元管理する配列を作成: このデータから、各ページのナビゲーションバーとフッターのリンクを動的に生成する。言語も自動検出される(<html lang=”ja”>属性から)。 関連サイトリストの自動生成: サイドバーの「関連サイト」リストも、同じデータから生成される。現在のページを除外し、残りのサイトをリスト表示: フッターの著作権表示の統一: すべてのサイトで、同じフッターテキストをJavaScriptで生成: これにより、年号が自動的に更新され、機械可読性も向上する。 Sticky/Scrolling Footer問題の解決: フッターが短いページでは画面下部に固定され、長いページではコンテンツの最後に表示されるようにする必要があった。Flexboxで解決: FOUT(Flash of Unstyled Content)の解決: Webフォントの読み込み中、システムフォントが表示されてしまう問題を、フォントプリロードで解決: 現在、すべてのAnaguraサイトは統一されたナビゲーションシステムを使用している。新しいサイトを追加する際は、NAVIGATION_DATA配列に1つのエントリを追加するだけで、すべてのサイトに自動的に反映される。
辞書プロジェクトでは、複数のAIペルソナ(Claude、Taavi、Gemini、Prof. Erdenebileg、Naranchimeg)がそれぞれ作業ログを記録している。これらのログを一元管理するため、Logbook自動化システムを構築した。 当初は、各ペルソナごとに個別のステージングフォルダを持つ設計だったが、これが管理の複雑化を招いた。そこで、単一のSTAGING_LOGBOOK_IDに統合し、すべてのペルソナがここに一時的にログを書き込む方式に変更した。 次の課題は、Google Docsの複数のLogbookファイルを自動的にフォーマットすることだった。見出しレベルの統一、アルファベット順の挿入位置の決定、完璧なMarkdown変換などが必要だった。特に、Google DocsのH2見出しをMarkdownの##に、本文の段落を適切に改行付きで変換する処理には注意が必要だった。 最終的には、別々に動作していたLogbook-SyncManagerとLogbook-Formatterを単一のGASプロジェクトに統合した。これにより、単一のメニューインターフェースから両方の機能にアクセスできるようになった。 さらに、FormatterをDocument IDのハードコードから解放し、LOGBOOKS_FOLDER_ID内のすべてのファイルを動的に処理するように改良した。これにより、新しいLogbookファイルを追加しても、コードの変更が不要になった。 現在、このシステムは時間トリガーで自動実行されており、各ペルソナのログは適切なLogbookファイルのアルファベット順の位置に自動的に挿入される。Google DriveのLogbookが「単一の真実の源(single source of truth)」となり、GitHubへの同期も自動化されている。
モンゴル系文字(伝統モンゴル文字、パスパ文字、ソヨンボ文字)およびモンゴル語の借用語の語源としてチベット文字やディーバナーガリー文字(サンスクリット用)を入力するためのWebベースのキーボードツール、KhamagBichigを開発した。Google Apps Scriptで動作し、ブラウザから直接アクセスできる。 最大の技術的課題は、Shiftキーの状態管理だった。物理キーボードのShiftキー、画面上の仮想SHIFTボタン、そして「Unshifted/Shifted」表示ボタンの3つを完全に同期させる必要があったからだ。 当初の実装では、これらが独立して動作してしまい、Shiftキーを押しても仮想キーボードの表示が切り替わらない、または逆に仮想ボタンをクリックしても入力が変わらないという問題が発生した。 解決策は、すべてのShift状態を唯一の情報源(single source of truth)として管理することだった。shiftStateという変数を定義し、すべてのShift関連イベント(キーボード、ボタンクリック、表示切替)がこの変数を参照・更新するように実装した。 もう一つの課題は、各文字体系の文字マッピングデータの整備だった。scriptMappingsとscriptLegendsという2つのオブジェクトに、すべての文字体系の完全なキーマップと凡例を格納する必要があった。データの欠損があると、一部のキーが機能しないという問題が起きる。 現在、KhamagBichigは安定稼働している。伝統モンゴル文字だけでなく、パスパ文字、ソヨンボ文字、チベット文字やディーバナーガリー文字の入力にも対応しており、モンゴル系文字研究者にとって便利なツールになった。
辞書プロジェクトで複数のWebアプリケーション(ダッシュボード、SystemHub、TeamHub、Logbookビューアなど)を開発するうちに、デザインの一貫性を保つことが課題になってきた。そこで、StyleCoreという統一デザインライブラリを構築することにした。 StyleCoreの設計思想は、スタイリングを3つの明確なレイヤーに分離することだ。第一層のCore(getThemeCss())は色、タイポグラフィ、スペーシングなどの基本変数を定義する。第二層のLayout(getFullpageLayoutCss()、getSidebarLayoutCss())はページ全体のレイアウトパターンを提供する。第三層のLocalはアプリ固有のスタイルを記述する。 この分離により、大きなメリットが得られた。たとえばダッシュボードのカラースキームを変更したい場合、CoreのCSS変数を一箇所修正するだけで、すべてのコンポーネント(ボタン、カード、モーダル、フォームなど)に変更が反映される。 実装にあたっては、Google Apps Scriptの特殊な環境を考慮する必要があった。通常のWebアプリと違い、GASではCSSファイルを.css.htmlという拡張子で保存し、<?!= include(‘StyleCore’) ?>という特殊な構文でインクルードする。この仕組みを理解するまで、試行錯誤を重ねた。 現在、StyleCoreはダッシュボード、SystemHub、TeamHubで実装済みだ。次はLogbookビューアとTraditional Mongolian Script Viewerにも適用する予定だ。デザインの統一は、単なる見た目の問題ではなく、開発効率の向上とメンテナンスコストの削減に直結する。