GASのWebアプリで、トップ画面と2つのページをリンクで切り替える例です。
Code.gsのdoGetがURLのpを読み、対応するHTMLを返します。
4ファイルを同じプロジェクトに作る
| 条件 | 結果 |
|---|---|
| Code.gs(コード.gs) | doGetと、許可するページ名の一覧 |
| Index.html | トップ画面 |
| Menu1.html | 1つ目の画面 |
| Menu2.html | 2つ目の画面 |
新しいApps Scriptプロジェクトを作り、Code.gsに次のJavaScriptを貼り付けます。
「ファイルを追加」からHTMLを選び、Index、Menu1、Menu2の名前で作成します。
ファイル名の大文字・小文字をコードと揃えてください。
HTMLをCode.gsへ貼り付けると動きません。
Code.gsにはdoGet、各HTMLファイルには対応するHTMLだけを入れます。
Code.gs:pから表示するファイルを選ぶ
const PAGE_FILES = Object.freeze({index: 'Index', menu1: 'Menu1', menu2: 'Menu2'});
function doGet(e) {
const values = e && e.parameters && e.parameters.p;
const page = e && e.parameter && e.parameter.p || 'index';
if ((values && values.length !== 1) ||
!Object.prototype.hasOwnProperty.call(PAGE_FILES, page)) {
return HtmlService.createHtmlOutput(
'<h1>該当するページがありません</h1><p>URLのpをindex、menu1、menu2のいずれかにしてください。</p>'
).addMetaTag('viewport', 'width=device-width, initial-scale=1')
.setTitle('ページ指定を確認してください');
}
const appUrl = ScriptApp.getService().getUrl();
if (!appUrl) throw new Error('テストデプロイまたはWebアプリのURLから開いてください。');
const template = HtmlService.createTemplateFromFile(PAGE_FILES[page]);
template.appUrl = appUrl;
return template.evaluate()
.addMetaTag('viewport', 'width=device-width, initial-scale=1')
.setTitle('ページ遷移の練習:' + page);
}
pの値はindex、menu1、menu2だけを受け付け、指定がない場合はindexを使います。
未知の値やpの重複指定はエラー画面にするため、URLから任意のファイル名を渡して開く構成ではありません。
Webアプリの入口に必要なdoGetとイベントの仕様はGoogle公式のWebアプリガイドを参照してください。
Index.html:トップ画面
<!DOCTYPE html>
<html lang="ja">
<head>
<base target="_top">
<style>body{font:18px/1.7 sans-serif;margin:2rem;max-width:42rem}nav{display:flex;gap:1rem;flex-wrap:wrap}a{padding:.5rem;border:1px solid #2768af;border-radius:4px;color:#14569b}a:focus-visible{outline:3px solid #e09319;outline-offset:3px}</style>
</head>
<body>
<h1>Indexページ</h1>
<p>練習用のトップ画面です。Menu1、Menu2へ移動して戻れます。</p>
<nav aria-label="練習ページ">
<a href="<?= appUrl ?>?p=index">トップ</a>
<a href="<?= appUrl ?>?p=menu1">Menu1</a>
<a href="<?= appUrl ?>?p=menu2">Menu2</a>
</nav>
</body>
</html>
Menu1.html:1つ目の画面
<!DOCTYPE html>
<html lang="ja">
<head>
<base target="_top">
<style>body{font:18px/1.7 sans-serif;margin:2rem;max-width:42rem}nav{display:flex;gap:1rem;flex-wrap:wrap}a{padding:.5rem;border:1px solid #2768af;border-radius:4px;color:#14569b}a:focus-visible{outline:3px solid #e09319;outline-offset:3px}</style>
</head>
<body>
<h1>Menu1ページ</h1>
<p>最初の練習画面です。トップまたはMenu2へ移動できます。</p>
<nav aria-label="練習ページ">
<a href="<?= appUrl ?>?p=index">トップ</a>
<a href="<?= appUrl ?>?p=menu1">Menu1</a>
<a href="<?= appUrl ?>?p=menu2">Menu2</a>
</nav>
</body>
</html>
Menu2.html:2つ目の画面
<!DOCTYPE html>
<html lang="ja">
<head>
<base target="_top">
<style>body{font:18px/1.7 sans-serif;margin:2rem;max-width:42rem}nav{display:flex;gap:1rem;flex-wrap:wrap}a{padding:.5rem;border:1px solid #2768af;border-radius:4px;color:#14569b}a:focus-visible{outline:3px solid #e09319;outline-offset:3px}</style>
</head>
<body>
<h1>Menu2ページ</h1>
<p>2番目の練習画面です。トップまたはMenu1へ移動できます。</p>
<nav aria-label="練習ページ">
<a href="<?= appUrl ?>?p=index">トップ</a>
<a href="<?= appUrl ?>?p=menu1">Menu1</a>
<a href="<?= appUrl ?>?p=menu2">Menu2</a>
</nav>
</body>
</html>
4ファイルと模擬テストをダウンロードできます。
記事中のHTMLは表示用のコードなので、WordPressの記事内で実行せず、Apps ScriptのHTMLファイルへ貼り付けます。
ZIP内ではarticle-315.jsがCode.gs用で、Index.html・Menu1.html・Menu2.htmlが各画面です。
配布版には今回のviewport修正が含まれていないため、実行時は本文の4ファイルを使ってください。
template.appUrlにWebアプリのURLを渡し、evaluateでHTMLを生成します。
画面幅の設定は、Code.gsでHtmlOutputのaddMetaTagを呼び出して指定します。
Apps Scriptでは、HTMLファイルへ直接書いたmetaタグは無視されます。
addMetaTagの公式仕様に合わせ、通常ページとエラー画面の両方へ設定しています。
通常のHTMLファイル出力とテンプレートの評価を混同しないでください。
公式のHTMLテンプレート仕様を参照してください。
リンクはWebアプリのURLと?p=を組み合わせ、base target=”_top”を設定します。
Apps ScriptのHTMLはIFRAME内で表示されるため、単に相対URLだけを指定する構成とは区別します。
HTMLサービスの制限も確認してください。
自分専用のデプロイで動かす
4ファイルを保存し、「デプロイ→新しいデプロイ」で種類を「ウェブアプリ」にします。
練習では実行者を自分、アクセスできるユーザーを「自分のみ」にしてデプロイします。
表示されたWebアプリの/execで終わるURLを開き、Indexページが表示されることを確認します。
エディタの実行ボタンでdoGetを動かす方法と、ブラウザーでWebアプリのURLを開く方法を区別してください。
初回デプロイ後は「デプロイ→デプロイをテスト」で/devのテストURLを取得できます。
テストURLは編集権限を持つ人向けで、保存した最新コードを使います。
/execはデプロイしたバージョンを使うため、コードの保存だけではそのバージョンに更新されません。
ScriptApp.getService().getUrlは、テスト環境から呼び出した場合はテスト用URLを返します。
デプロイ前はURLが取得できない場合があるため、エディタでの手動実行を表示確認の代わりにしないでください。
Service.getUrlの公式仕様を参照してください。

遷移とエラーを確認する
| 条件 | 結果 |
|---|---|
| URLにpなし、または?p=index | Indexページ |
| ?p=menu1 | Menu1ページ |
| ?p=menu2 | Menu2ページ |
| ?p=unknown、またはpを重複指定 | 該当するページがありません |
トップからMenu1、Menu2へ移動し、トップへ戻れるか確認します。
Tabキーでリンクを選び、Enterキーでも同じページへ進めることを確認してください。
旧版ではMenu1のリンク先やMenu2の見出しに取り違えがありました。
本例ではリンクの表示名、pの値、HTMLの見出しを対応させています。
| 条件 | 結果 |
|---|---|
| doGetが見つからない | Code.gsにJavaScriptを貼り、関数名を確認する |
| HTMLファイルが見つからない | Index・Menu1・Menu2の名前と大文字小文字を確認する |
| 画面が変わらない | devとexec、保存中のコードとデプロイ済みバージョンを確認する |
| リンクが別のフレームに開く | base targetとテンプレートのappUrlを確認する |
| 変更を戻したい | 変更前の4ファイルへ戻し、execを使う場合はデプロイ設定のバージョンも確認する |
ページ遷移のためにXFrameOptionsMode.ALLOWALLを設定する必要はありません。
外部ページへの埋め込みを許可する話と、このWebアプリ内のページ切り替えは別に判断します。
実サービスで確認した範囲
2026年10月3日に、自分専用のWebアプリで3つの画面、トップへの戻り、未知のpのエラー、Enterでの遷移を確認しました。
devのリンクが同じテスト用URLを使うことも確認しています。
この4ファイルはDriveやGmailのデータを読みません。
不特定多数への公開、別アカウントでの利用、外部iframeの埋め込みは試していません。
2026年10月28日は公式仕様と配布コードを照合し、viewport追加とページ分岐を模擬試験しました。
今回の修正後のWebアプリ表示やスマートフォンでの操作は未検証です。
他の自動化はGoogleの目的別ガイドから確認できます。
さらに学びたい・環境を整えたい方へ
この記事の手順を試したあと、スプレッドシートやGASを体系的に学びたい方に向けた参考書です。
必要なテーマが目次に含まれるか確認して選んでください。
関連記事と旧資料
関連記事は目的が合うものから確認してください。
旧資料や外部ツールの説明は、本稿の練習コード・検証範囲と異なる場合があります。




よくある質問:GASのWebアプリでページ遷移を実装するときのチェックリスト
このWebアプリは、何をしますか?
トップ画面と2つのページを、リンクで切り替えます。Code.gsのdoGetがURLのpを読み、対応するHTMLファイルを返します。
pに任意のファイル名を入れて、開けますか?
開けません。pの値はindex、menu1、menu2だけを受け付け、指定がなければindexを使います。未知の値やpの重複指定は、エラー画面になります。
HTMLファイルの名前は、何でもよいですか?
Index、Menu1、Menu2の名前で作成し、コードと大文字・小文字を揃えてください。HTMLをCode.gsへ貼り付けると動きません。Code.gsにはdoGet、各HTMLファイルには対応するHTMLだけを入れます。
コードを保存したのに、画面が変わらないのはなぜですか?
devとexecの違いが原因のことがあります。devのテストURLは保存した最新コードを使いますが、execはデプロイしたバージョンを使います。コードの保存だけでは、execのバージョンは更新されません。
リンクが別のフレームで開くときは?
base targetとテンプレートのappUrlを確認します。Apps ScriptのHTMLはIFRAME内で表示されるため、相対URLだけを指定する構成とは区別します。
ページ遷移のために、ALLOWALLの設定は必要ですか?
必要ありません。外部ページへの埋め込みを許可する話と、このWebアプリ内のページ切り替えは別に判断します。
公開範囲は、どう設定しますか?
練習では実行者を自分、アクセスできるユーザーを「自分のみ」にしてデプロイします。不特定多数への公開や別アカウントでの利用は、この記事では試していません。
この記事の手順は、どこまで確認済みですか?
2026年10月3日に、自分専用のWebアプリで3つの画面、トップへの戻り、未知のpのエラー、Enterでの遷移を確認しました。外部iframeの埋め込みは試していません。画面は変わることがあるため、最新は公式で確認してください。
