個人サイト制作:サイトマップへ戻る

タブを使ってコンテンツを詰め込む

タブを使ったレイアウトは特に利点が多いです。
情報を整理し、ユーザーが簡単に必要な情報にアクセスできるようになります。
一目で全体の構造が分かりやすい。
ページがすっきりと見えて見た目も良いため、ユーザーが快適に閲覧できます。
何より直感的な操作がキーポイントかと。
タブは一貫したナビゲーションを提供して直感的に使えます。
初めての訪問者でもすぐに操作できます。

このページでは、そういったタブ式レイアウトを初めとして、ちょっとしたUIの工夫について書いていきます。
ゆくゆくはjQueryを使ったいろんなパターンとか、掲載していきますよ。

このページに関する注意事項

当Webサイト作成者は、例示を目的としてマークアップ及びプログラミング例を提供しており、明示または黙示にかかわらず、いかなる責任も負わないものとします。
このページは、説明されているマークアップ及びプログラミング言語、手順を作成およびデバッグするために使用される各種ツールに読者が精通していることを前提にしています。
このページは、特定の機能を説明するのに役立つ可能性がありますが、当Webサイト作成者がこれらの例を変更した上で、特定の要件を満たすために追加の機能を提供したり、システムを構築したりすることはできません。
加えて、この例の手順に従う場合は、読者の各種ファイルを事前にバックアップすることを推奨いたします。

タブを作るCSSとJavaScript

ライブラリを使うかどうかは、要件や好みによるでしょう。 無理にどっかのライブラリを使わなくても良いし、ここではまず簡単なコードを紹介していきます。

タブを作るstyle.css


/* タブのコンテナを作成し、タブを横並びに配置 */
.fein {
 display: flex; /* フレックスボックスで配置 */
 border-bottom: 1px solid #ccc; /* 下線を追加 */
}

/* タブのスタイルを定義 */
.tab-fein {
 border: 1px solid #ccc; /* 枠線を追加 */
 padding: 10px 20px; /* 内側の余白を設定 */
 border-radius: 10px 10px 0 0; /* 角を丸める */
 background-color: rgba(173, 216, 230, 0.3); /* 背景色を薄い青に設定 */
 cursor: pointer; /* マウスカーソルをポインターに変更 */
}

/* 最後のタブ以外に右の余白を設定 */
.tab-fein:not(:last-child) {
 margin-right: 5px; /* 右側の余白を5pxに設定 */
}

/* タブにホバーした際のスタイル */
.tab-fein:hover {
 background-color: rgba(173, 216, 230, 0.5); /* 背景色を濃くする */
}

/* アクティブなタブのスタイル */
.tab-fein.active {
 background-color: rgba(173, 216, 230, 0.7); /* より濃い背景色に設定 */
 font-weight: bold; /* 文字を太字に変更 */
 border-bottom: 3px solid #007BFF; /* 下線を青色に変更 */
}

/* タブの内容のスタイルを定義 */
.tab-pane-fein {
 position: absolute; /* 絶対位置に配置 */
 width: 95%; /* 幅を95%に設定 */
 opacity: 0; /* 初期状態は非表示 */
 border: 1px solid #ccc; /* 枠線を追加 */
 padding: 10px; /* 内側の余白を設定 */
 border-radius: 5px; /* 角を丸める */
 box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 影を追加 */
 transform: translateX(-100%); /* 初期位置を左外に設定 */
 transition: transform 0.5s ease, opacity 0.5s ease; /* トランジションを設定 */
}

/* アクティブなタブの内容を表示 */
.tab-pane-fein.active {
 position: static; /* 通常の配置に変更 */
 opacity: 1; /* 表示 */
 transform: translateX(0); /* 位置をリセット */
}

トランジション(transition)はCSSで要素の状態が変化する際に、その変化を滑らかにアニメーションで表現するためのプロパティです。
トランジションを使用することで、要素のスタイルが急激に変わるのではなく、段階的に変わるようになります。

このコードでは、タブの内容が切り替わる際に次のようなトランジションが設定されています。


transform: translateX(0); /* 位置をリセット */
transition: transform 0.5s ease, opacity 0.5s ease; /* トランジションを設定 */

CSSトランジション

transform: translateX(0);
タブの内容の初期位置を設定しています。
translateX(-100%)はタブの内容を左に100%ずらし、translateX(0) は元の位置に戻します。

opacity: 0;opacity: 1;
タブの内容の表示/非表示を設定しています。
非アクティブ時は透明(opacity: 0;)、アクティブ時は表示(opacity: 1;)となります。

transition: transform 0.5s ease, opacity 0.5s ease;
これがトランジションの設定です。
transformopacity の変化を0.5秒かけてスムーズに実行します。
ease は変化が始めはゆっくりで中間は速く、終わりにまたゆっくりになるように設定するイージング関数です。

このトランジションを使うことで、タブの内容が切り替わる際にアニメーション効果が適用され、ユーザーにとって視覚的に不自然な感覚を与えません。

タブを作るtab.js


document.addEventListener('DOMContentLoaded', () => {
 const tabsFein = document.querySelectorAll('.tab-fein');
 const tabPanesFein = document.querySelectorAll('.tab-pane-fein');

 tabsFein.forEach(tab => {
  tab.addEventListener('click', () => {
   const target = document.getElementById(tab.getAttribute('data-tab'));

   tabsFein.forEach(tab => {
    tab.classList.remove('active');
   });

   tabPanesFein.forEach(pane => {
    pane.classList.remove('active');
   });

   tab.classList.add('active');
   target.classList.add('active');
  });
 });

 document.querySelector('.tab-fein').classList.add('active');
 document.getElementById('pane1-fein').classList.add('active');
});

このJavaScriptコードについては、きちんと書いた方が良さそう。
初めてこのタイプのコードにチャレンジしたときには、私は紙にぜんぶ書きださないと分からなかったです。
では、次の順番に説明していきます。

  1. DOMContentLoadedイベント
  2. 要素の選択
  3. イベントリスナーの追加
  4. クラスの切り替え
  5. 初期状態の設定

1. DOMContentLoadedイベント


document.addEventListener('DOMContentLoaded', () => {
// コードの内容
});

DOMContentLoadedイベントは、HTML文書が完全に読み込まれ、解析された時点で発生します。

このイベントはページ全体の読み込みが完了するのを待たずに、DOMの構造が読み込まれた時点で発生します。
これでスクリプトの実行を早めることができます。

2. 要素の選択


const tabsFein = document.querySelectorAll('.tab-fein');
const tabPanesFein = document.querySelectorAll('.tab-pane-fein');

querySelectorAllメソッドは、指定されたCSSセレクターに一致する全ての要素を選択し、NodeListオブジェクトとして返します。

ここでは、.tab-feinクラスと.tab-pane-feinクラスを持つ要素をそれぞれ取得しています。

3. イベントリスナーの追加


tabsFein.forEach(tab => {
tab.addEventListener('click', () => {
// コードの内容
});
});

forEachメソッドを使って、全てのタブ要素に対してクリックイベントリスナーを追加しています。

addEventListenerメソッドは、指定されたイベント(ここではclick)が発生したときに実行される関数を登録します。

4. クラスの切り替え


const target = document.getElementById(tab.getAttribute('data-tab'));

tabsFein.forEach(tab => {
tab.classList.remove('active');
});

tabPanesFein.forEach(pane => {
pane.classList.remove('active');
});

tab.classList.add('active');
target.classList.add('active');

getElementByIdメソッドを使って、クリックされたタブのdata-tab属性値と一致する要素を取得しています。

classListオブジェクトを使って、全てのタブとタブの内容からactiveクラスを削除し、クリックされたタブとその内容にactiveクラスを追加しています。

5. 初期状態の設定


document.querySelector('.tab-fein').classList.add('active');
document.getElementById('pane1-fein').classList.add('active');

最初のタブとその内容を初期状態でアクティブにするために、activeクラスを追加しています。

これが全体の流れです。
このコードはタブをクリックすると対応する内容が表示され、他のタブとその内容が非アクティブになるように動作します。
ちょっと感覚的に分かりにくいかもしれませんが、1行ずつ読んでいけば、自然と全体が見えてきます。

PythonでタブUIを実装する

フェードアウト効果の草花写真

次はBrython(ブリトン)でタブUIの実装を試みます。
Pythonのシンプルな文法を使ってフロントエンドの機能を実装でき、JavaScriptを深いレベルで学ぶ必要がなくなります。
Pythonの知識だけでフロントエンド開発ができるツールなんですよね。
JavaScriptに比べると若干パフォーマンスが劣るようですが、軽微なUIなら支障はありません。
Pythonライブラリや機能にしても、全てを扱う必要はないのですから。

Brython(Browser Pythonの略)について
フェードアウト効果の草花写真

Pythonのコードを直接ブラウザ上で実行するためのライブラリです。
JavaScriptの代わりにPythonを使用してフロントエンド開発を行うことができます。
BrythonはPython 3の多くの機能をサポートしており、Pythonの標準ライブラリの一部も使用できます。
方法は単純で、アナデンで使われているLuaを動かした時と同じように、HTMLファイルにスクリプトタグを追加するだけです。

さっそくコードを見てみましょう。

BrythonのJSファイルを取得して関連付ける

アナデンで使われているLuaを実装した時と似ています。
ひとまず実行環境を用意してあげないと、Pythonがブラウザ上で動作しません。

Brythonをhtmlファイルと関連付けるコード


<head>
 <script src="/script/brython.js"></script>
 <script src="/script/brython_stdlib.js"></script>
</head>

もうHTML・CSS・JavaScriptによるサイト構築の基礎についてはご存じのものとして話を進めます。

上記のように設定することで、Brythonの主要な機能と標準ライブラリを含めることができます。
両方のファイルを使うとBrythonをフルに活用することができますよ。
JavaScriptファイルの設置場所は御自身のサイトに合うようにパスを修正してください。

フェードアウト効果の草花写真

まず、Brython公式サイトから、githubのBrythonリリースページへ移動します。
そのサイトから「Brython-3.13.0.zip」をダウンロードします。
zipを解凍すると、次のファイルが出てきます。

brython.js
Brythonの主要なスクリプトで、PythonコードをJavaScriptに変換して実行します。
これがなければ、Brythonは動作しません。
brython_stdlib.js
Brythonの標準ライブラリを含むスクリプトです。
Pythonの標準ライブラリの機能をブラウザ上で利用するために必要です。

インターネット越しにBrythonを使うこともできますが、自分のサイトのディレクトリに入れちゃった方が後がラクかと思います。

HTMLの中にPythonを含める

フェードアウト効果の草花写真

長くなるから、まだここではPythonまでは書かれていません。
いったんhtml部分のみ記載しています。
ポイントとなるのは、Brythonを使用してブラウザ内でPythonコードを実行しているところです。
DOMの操作やイベントハンドリングを行う構成としてみました。
JavaScriptはBrythonの初期化を行っているだけなので、主なロジックはPythonスクリプトに依存しています。

タブUIの骨組みとなるhtmlコード


<div class="atelier-container">
 <div class="atelier-tabs">
  <div class="atelier-tab" data-tab="1">Tab 1</div>
  <div class="atelier-tab" data-tab="2">Tab 2</div>
  <div class="atelier-tab" data-tab="3">Tab 3</div>
 </div>
 <div class="atelier-tab-content" data-content="1">Content for Tab 1</div>
 <div class="atelier-tab-content" data-content="2">Content for Tab 2</div>
 <div class="atelier-tab-content" data-content="3">Content for Tab 3</div>
</div>

<div class="atelier-container">
 <div class="atelier-tabs">
  <div class="atelier-tab" data-tab="4">Tab 4</div>
  <div class="atelier-tab" data-tab="5">Tab 5</div>
  <div class="atelier-tab" data-tab="6">Tab 6</div>
 </div>
 <div class="atelier-tab-content" data-content="4">Content for Tab 4</div>
 <div class="atelier-tab-content" data-content="5">Content for Tab 5</div>
 <div class="atelier-tab-content" data-content="6">Content for Tab 6</div>
</div>

<script type="text/python">
python部分はここではいったん省略
</script>

<script>
 window.addEventListener('load', () => {
  brython({ debug: 1, selector: ".atelier-container" });
 });
</script>

このコードの概要をざっと説明します。

HTMLの構造

タブコンテナ(.atelier-container)
2つのタブコンテナがあり、それぞれに複数のタブ(.atelier-tab)とタブコンテンツ(.atelier-tab-content)が含まれています。
タブ(.atelier-tab)
各タブは data-tab 属性で識別され、クリックすると対応するコンテンツが表示されます。
タブコンテンツ(.atelier-tab-content)
各タブに対応するコンテンツで、data-content 属性によってどのタブに対応するかが示されています。

Pythonスクリプト(省略されている部分)

フェードアウト効果の草花写真

タブのクリックイベントを処理し、対応するタブコンテンツの表示・非表示を制御するロジックなどが含まれています。(後述します)

JavaScriptの部分

ページの読み込み時にBrythonが初期化され、.atelier-container 内でPythonコードが実行されます。
動作の流れとしては、次のような感じです。

  1. ページが読み込まれると、Brythonライブラリが初期化されます。
  2. 各タブをクリックすると、Pythonスクリプトによって対応するタブコンテンツが表示されます。
  3. 非アクティブなタブコンテンツは非表示になります。

Pythonコードの紹介

いよいよここからPythonコードです。
個人的にはJavaScriptでタブUIを作るよりラクだと感じるけど、まぁ好みかな?
まずは簡単にさらーっと説明しますね。

フェードアウト効果の草花写真

タブ切り替えの説明

このコードは、タブをクリックすると、それに対応するコンテンツ(中身)を表示するものです。

タブを準備
タブ(ボタンみたいなもの)とその中身(コンテンツ)をまとめておきます。
タブをクリックすると
クリックされたタブを「アクティブ(選ばれた)」状態にして、そのタブの中身を表示するために準備します。
アニメーションをつける
タブの中身がスライドして出てくる動きをつけます。

全体の流れ

これで、タブを切り替えるたびに対応する中身がアニメーションと一緒に表示されるようになります。

タブUIを作るPythonコード


from browser import document, timer

def show_tab(event):
 container = event.target.closest('.atelier-container')
 tabs = container.select('.atelier-tab')
 contents = container.select('.atelier-tab-content')

 for tab in tabs:
  tab.classList.remove('atelier-active-tab')
 for content in contents:
  content.classList.remove('atelier-active-content')
  content.style.transition = 'transform 1s ease-in-out, opacity 1s ease-in-out'
  content.style.transform = 'translateX(-100%)'
  content.style.opacity = '0'
  content.style.visibility = 'hidden'

 event.target.classList.add('atelier-active-tab')
 tab_id = event.target.getAttribute('data-tab')
 active_content = container.select(f'[data-content="{tab_id}"]')[0]
 active_content.classList.add('atelier-active-content')

 def show_content():
  active_content.style.visibility = 'visible'
  active_content.style.opacity = '1'
  active_content.style.transform = 'translateX(0)'

 timer.set_timeout(show_content, 50)

for container in document.select('.atelier-container'):
 tabs = container.select('.atelier-tab')
 if tabs:
  tabs[0].classList.add('atelier-active-tab')
  container.select('.atelier-tab-content')[0].classList.add('atelier-active-content')
  for tab in tabs:
      tab.bind('click', show_tab)

アニメーションについてはCSSでやっても良いと思うのですが、Luaと違ってPythonなら多少は慣れているので。
せっかくだからやってみましたよ。
ちなみにこのタブUIで用いられるJavaScriptとPythonコードは、1つのWebページにつき1カ所に書かれていれば良いです。
複数のタブを1つのWebページに実装しても、正常動作するようにしてあります。
では、ここからは少し詳しくいきます。

必要なモジュールをインポート


from browser import document, timer

document
ウェブページのDOM(Document Object Model)にアクセスするためのモジュールです。
timer
時間を指定して関数を実行するためのモジュールです。

タブを表示する関数を定義


def show_tab(event):
    container = event.target.closest('.atelier-container')
    tabs = container.select('.atelier-tab')
    contents = container.select('.atelier-tab-content')

show_tab関数
タブがクリックされたときに呼び出されます。
event.target
クリックされたタブ要素を指します。
closest('.atelier-container')
クリックされたタブの親要素であるコンテナを取得します。
tabs
コンテナ内のすべてのタブを取得します。
contents
コンテナ内のすべてのタブコンテンツを取得します。

現在のアクティブなタブとコンテンツを非アクティブにする


for tab in tabs:
    tab.classList.remove('atelier-active-tab')
for content in contents:
    content.classList.remove('atelier-active-content')
    content.style.transition = 'transform 1s ease-in-out, opacity 1s ease-in-out'
    content.style.transform = 'translateX(-100%)'
    content.style.opacity = '0'
    content.style.visibility = 'hidden'

for tab in tabs
すべてのタブからatelier-active-tabクラスを削除します。
for content in contents
すべてのタブコンテンツからatelier-active-contentクラスを削除します。

ここで、タブコンテンツに対してアニメーション(スライドアウトとフェードアウト)を設定します。

クリックされたタブをアクティブにし、対応するコンテンツを表示


event.target.classList.add('atelier-active-tab')
tab_id = event.target.getAttribute('data-tab')
active_content = container.select(f'[data-content="{tab_id}"]')[0]
active_content.classList.add('atelier-active-content')

event.target.classList.add('atelier-active-tab')
クリックされたタブをアクティブにします。
tab_id
クリックされたタブのdata-tab属性の値を取得します。
active_content
対応するタブコンテンツを取得します。
active_content.classList.add('atelier-active-content')
対応するコンテンツをアクティブにします。

遅延してコンテンツを表示


def show_content():
    active_content.style.visibility = 'visible'
    active_content.style.opacity = '1'
    active_content.style.transform = 'translateX(0)'

timer.set_timeout(show_content, 50)

show_content関数
アクティブなタブコンテンツを表示するためのものです。
timer.set_timeout(show_content, 50)
50ミリ秒後にshow_content関数を実行します。

最後のforから始まっている部分


for container in document.select('.atelier-container'):
 tabs = container.select('.atelier-tab')
 if tabs:
  tabs[0].classList.add('atelier-active-tab')
  container.select('.atelier-tab-content')[0].classList.add('atelier-active-content')
  for tab in tabs:
   tab.bind('click', show_tab)

ここなんだよねー
これはですねー…ウェブページ内のすべての「atelier-container」をループしているのです。
アナザーエデンで言うところの、ループ攻略ですよ!

ちょっと詳しめにいきましょう。

ウェブページ内のすべてのatelier-containerをループ


for container in document.select('.atelier-container'):

このコードはウェブページ内にあるすべての .atelier-container クラスを持つ要素を見つけて、それぞれに対して同じ処理を行うためのループです。
簡単に言うと、ページにあるすべての「タブコンテナ」を順番に処理します。

初期設定として、最初のタブとタブコンテンツをアクティブに


if tabs:
    tabs[0].classList.add('atelier-active-tab')
    container.select('.atelier-tab-content')[0].classList.add('atelier-active-content')

このコードはタブコンテナ内にタブ (.atelier-tab) が存在するかを確認しています (if tabs:)。
もしタブが存在する場合、最初のタブ (tabs[0]) に atelier-active-tab クラスを追加して、それをアクティブ(選択された状態)にします。
同様に、最初のタブコンテンツにも atelier-active-content クラスを追加して表示されるようにします。
このコードがないと、ページがロードされたときに最初のタブとその内容が表示されなくなってしまうのです。

各タブにクリックイベントをバインドし、タブがクリックされたときに show_tab 関数を実行します


for tab in tabs:
    tab.bind('click', show_tab)

このコードはコンテナ内のすべてのタブ(.atelier-tab)に対して、クリックイベント(クリックされたときに起こる処理)を設定しています。
tab.bind('click', show_tab) は、各タブをクリックしたときに show_tab 関数を実行するように設定しています。
つまり、タブがクリックされると、そのタブに対応するコンテンツを表示する処理が実行されるってこと。

装飾要素のCSSコード

CSSはプログラミング風に考えると余計にこんがらがるので、単純にコメントアウトを付けてコードを紹介します。

タブUIを装飾するstyle.css


/* タブのスタイル */
.atelier-tab {
 display: inline-block; /* タブをインラインブロックに設定 */
 margin: 0 5px; /* タブ間の左右マージンを5pxに設定 */
 padding: 10px 20px; /* タブ内のパディングを上下10px、左右20pxに設定 */
 border: 1px solid #ccc; /* タブの境界線を1pxの実線で#cccの色に設定 */
 cursor: pointer; /* マウスカーソルをポインターに変更 */
 border-top-left-radius: 10px; /* 左上の角を10pxの円弧に設定 */
 border-top-right-radius: 10px; /* 右上の角を10pxの円弧に設定 */
 background-color: rgba(144, 238, 144, 0.5); /* 背景色を半透明のライトグリーンに設定 */
}

/* タブコンテンツのスタイル */
.atelier-tab-content {
 display: none; /* デフォルトでは表示しない */
 padding: 20px; /* コンテンツ内のパディングを20pxに設定 */
 border-top: none; /* 上部の境界線をなしに設定 */
 border: 1px solid #ccc; /* コンテンツの境界線を1pxの実線で#cccの色に設定 */
 border-radius: 10px; /* 角を10pxの円弧に設定 */
 box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* コンテンツに影を付ける */
 background-color: #fff; /* 背景色を白に設定 */
}

/* アクティブなタブのスタイル */
.atelier-active-tab {
 background-color: rgba(144, 238, 144, 1); /* 背景色を不透明のライトグリーンに設定 */
}

/* アクティブなタブコンテンツのスタイル */
.atelier-active-content {
 display: block; /* アクティブなコンテンツを表示 */
}

要するに、このCSSは「タブ」と「タブの中身」について、それぞれデザインしているのです。
AI学習や無断転載を防ぐプログラムの小ネタ集ではJavaScriptを用いて青色のタブUIを実装しました。
ここではPythonだから、緑色のタブUIにしてみたんだよね。

JavaScript以外の言語でも実装可能

こういうのはフレームワークを使うのが普通ですが、ちょっとした変化球ですよね。

フェードアウト効果の草花写真

html・css・JavaScriptでタブUIを作るのは一般的過ぎて退屈だから、このサイトのランタイムであるPythonを使ってやってみました。
本来ならサーバー側で使う言語でも、こうやってフロントで動かせるのはおもしろいですよね。
でもできるものとそうでないものがある。

タグUIは便利ですよ?
冗長になりがちな記述を無理に縮めることなく収められますし、見た目もスッキリするからね。


サイトマップ

全ページをリスト化したサイトマップも用意していますが、けっこうなページ数があります。
下記の「カテゴリー分けサイトマップ」のほうが使いやすいでしょう。

アナザーエデン関連ページ・サイトマップ

アナザーエデンの強敵戦やストーリーコンテンツのリスト、お勧めバッジなどを掲載したコーナーです。
期間限定のない普通のRPGですので、初心者でも安心して続けていけるゲームとなっています。
もっとも重要なグラスタについては、場所別に網羅した表があります。

個人サイトのホスティングとコンテンツ作成

個人でウェブサイトを作るにはどうすればいいか。
HTML・CSS・JavaScriptの書き方はもちろん、無料かつ広告なしでホームページを作る方法を掲載したコーナーです。
Webデザインやレイアウトについても書いてあります。

魚釣りなどアウトドアのエリア

ゲームとパソコンだけじゃなく、アウトドアも趣味なんです。
このコーナーでは魚釣りの記録とか、魚料理のレシピ、はたまたサイクリングなどなど。
アウトドアに関連するコンテンツが詰め込まれています。