STUDIOでタブ切替UIを実装する方法|:targetが使えない理由とJSでの解決策

ノーコードWeb制作ツール「STUDIO」には、タブで表示内容を切り替えるUIの標準機能がありません。
そのため、タブ切替はカスタムコードで実装することになります。

本記事では、最初に試したCSSのみの方法(:target 方式)がSTUDIOの公開環境では動作しなかった原因と、最終的に採用したJavaScript方式の実装手順をまとめます。
同じ壁に当たった方の参考になれば幸いです。

目次

前提条件

  • STUDIOの有料プランであること(カスタムコード機能が必要)
  • カスタムコードはライブプレビューでは動作せず、公開後にのみ確認可能
  • カスタムコードの上限:1コード30,000文字、head/bodyそれぞれ最大10個まで

完成イメージ

セクション内にタブボタンを2つ配置し、クリックでその下のコンテンツが切り替わる構成です。

  • 初期表示:コンテンツAのみ表示。タブAが選択状態(塗り)、タブBは非選択状態(白抜き)
  • タブBをクリック:コンテンツBに切り替わり、タブの選択状態も反転
  • ページスクロールは発生しない

STUDIO側の構造とID設定

STUDIOでは要素に任意のclassを付けられませんが、IDは設定できます。CSSやJSはこのIDを起点に書きます。レイヤー構造は次の形にします。

Box(ID: tab-wrap)
├ タブ切替Box(横並び・gap 24px)
│ ├ タブA(ID: tab-btn-01)
│ └ タブB(ID: tab-btn-02)
├ コンテンツA(ID: tab-panel-01)
└ コンテンツB(ID: tab-panel-02)

作成手順の要点は以下のとおりです。

  1. 切り替えたいコンテンツ一式(Group)にIDを付け、Groupごと複製して2つ目のコンテンツを作成し、内容を書き換えて別のIDを付ける
  2. タブとコンテンツ全体を包む親BoxにもIDを付ける(tab-wrap
  3. タブは通常のBox+テキストで「選択中」のデザイン(塗り・角丸など)を作り込み、複製して並べる
  4. タブにリンク設定は不要(後述の理由により、リンクにするとかえって邪魔になります)

デザイン上のポイントとして、タブは2つとも「選択中」の見た目で作ります
非選択側のデザインはCSSが自動で上書きするため、STUDIO上で2種類のデザインを作る必要はありません。

最初に試した方法::target 方式(失敗)

当初は「CSSだけで完結できる」:target 擬似クラス方式を採用しました。
タブをページ内リンク(#tab-panel-02 など)にし、次のようなCSSで切り替える設計です。

#tab-panel-02 {
  display: none;
}
#tab-panel-02:target {
  display: block;
}
#tab-wrap:has(#tab-panel-02:target) #tab-panel-01 {
  display: none;
}

静的なHTMLサイトであれば定番のテクニックですが、STUDIOの公開サイトでは動作しませんでした
症状と切り分けの過程は次のとおりです。

症状1:クリックするとページ上部へスクロールするだけ

タブをクリックするとURLに #tab-panel-02 は付くものの、表示は切り替わらず、画面が上方向へスクロールするだけでした。これは display: none の要素(=画面上に存在しない要素)へスクロールしようとした結果です。

症状2:ハッシュ付きURLでリロードしても切り替わらない

:target はページ読み込み時のナビゲーションでは評価されるはずなので、ハッシュ付きのURLで再読み込みするテストをしました。それでも表示は切り替わりませんでした。

原因の考察

STUDIOの公開サイトは静的HTMLをそのまま表示するのではなく、読み込み後にJavaScriptがページを再構築する仕組みです。
ブラウザの :target は「ナビゲーション時に決定されたターゲット要素」に紐づくため、読み込み後にDOMが作り直されると、同じIDの要素が再生成されてもターゲットの紐付けが失われます。

一方で #tab-panel-02 { display: none } のような単純なIDセレクタは再構築後の要素にも効くため、「非表示だけは機能し、切り替えだけが永遠に発動しない」という中途半端な状態になります。

結論:STUDIOの公開環境で :target 方式は使えません。

採用した方法:JavaScript方式

クリックで親Boxにクラスを付け外しし、CSSがそのクラスを見て表示を切り替えるシンプルな方式に変更しました。DOM再構築への耐性を持たせるため、個々のボタンにイベントを付けるのではなく、document全体でクリックを監視(イベントデリゲーション)しています。
これならSTUDIOが内部でDOMを作り直しても動き続けます。

headの末尾に追加するCSS

<style>
#tab-panel-02 {
  display: none;
}
#tab-btn-01,
#tab-btn-02 {
  cursor: pointer;
  transition: background-color 0.2s, color 0.2s;
}
#tab-wrap.show-02 #tab-panel-01 {
  display: none;
}
#tab-wrap.show-02 #tab-panel-02 {
  display: block;
}
#tab-wrap.show-02 #tab-btn-01,
#tab-wrap:not(.show-02) #tab-btn-02 {
  background-color: #fff;
  box-shadow: inset 0 0 0 2px #333;
}
#tab-wrap.show-02 #tab-btn-01 p,
#tab-wrap:not(.show-02) #tab-btn-02 p {
  color: #333;
}
</style>

補足:

  • #333 の箇所はサイトのキーカラーに置き換えてください
  • 非選択タブの枠線に border ではなく box-shadow: inset を使っているのは、STUDIO側のスタイルと競合してレイアウトがずれるのを防ぐためです
  • タブ内テキストのセレクタ(p)は、STUDIOの出力によって span 等になる場合があります。効かないときは公開ページで実際のタグを確認してください

bodyの末尾に追加するJavaScript

<script>
document.addEventListener('click', function (e) {
  var btn1 = e.target.closest('#tab-btn-01');
  var btn2 = e.target.closest('#tab-btn-02');
  if (!btn1 && !btn2) return;
  e.preventDefault();
  var wrap = document.getElementById('tab-wrap');
  if (!wrap) return;
  if (btn2) {
    wrap.classList.add('show-02');
  } else {
    wrap.classList.remove('show-02');
  }
});
</script>

動作の仕組みは単純で、タブBのクリックで tab-wrapshow-02 クラスを付け、タブAのクリックで外すだけです。
表示の入れ替えとタブの見た目の反転は、すべてCSS側が担当します。

公開前に確認を挟む方法

カスタムコードはプレビューで動かないため、動作確認には公開が必須です。
とはいえ運用中のサイトで「作りかけの状態」を公開するわけにはいきません。
その場合は次の方法で確認を挟めます。

  1. 対象ページを複製し、URLを推測されにくい文字列にしたテストページを作る(どこからもリンクしない)
  2. テストページのページ単位カスタムコードにCSS/JSを追加し、あわせて <meta name="robots" content="noindex, nofollow"> を入れて検索エンジンから除外
  3. 本番ページ側は、追加した要素をレイヤーの非表示機能で隠しておく
  4. 公開し、テストページのURLだけを関係者に共有して確認してもらう
  5. 承認後、本番ページの要素を表示に戻し、カスタムコードを本番側へ移してテストページを削除

ハマりどころまとめ

  • カスタムコードはライブプレビュー非対応。 「反映されない」と焦る前に、公開後の本番URLで確認する
  • STUDIOで :target は動かない。 URLハッシュに依存する実装は避け、クリックイベント+クラス切替のJS方式にする
  • イベントはdocumentに委譲する。 DOM再構築で要素が差し替わっても動作を維持できる
  • STUDIOの非表示機能とCSSの display: none は別物。 エディタ上で邪魔だからと目アイコンで隠したまま公開すると、CSSに関係なく本番でも消える
  • IDはページ内で一意に。 要素を複製したあとのID・リンク先の変更漏れに注意
  • 確認はスーパーリロードで。 公開直後はブラウザキャッシュで古い状態が表示されることがある

おわりに

STUDIOはノーコードで完結する範囲が広い一方、標準機能にないUIはカスタムコードで補うことになります。
その際、公開サイトがJSで再構築される特性を踏まえないと、静的サイトでは定番のCSSテクニックが通用しないことがあります。
タブ切替に限らず、カスタムコードで表示制御を行う場合は「IDセレクタ+クラス切替+イベントデリゲーション」の組み合わせを基本形にするのが安全です。

同種の実装を検討している方の参考になれば幸いです。

シェアする
  • URLをコピーしました!
  • URLをコピーしました!
目次