GASのHTMLにBootstrapを読み込ませる方法

バックエンドエンジニアでも簡単な画面を作らないといけない場合があり、その時に覚えておくと良いのが、フロントエンドフレームワークのBootstrapです。簡単に画面が作れますので、エンジニアにとって重宝する存在です。
今回は、BootstrapをGASのHTMLに読み込ませてみました。

HTMLファイル

実際にBootstrapで作成した画面がこちらになります。

勤怠システム用の画面になります。

GASの場合、HTMLページを表示させると、まずdoGetという関数が実行されます。
ですので、doGet関数の中にindex.htmlを表示する処理を書く必要があります。

function doGet(e) {
 let template = HtmlService.createTemplateFromFile('index');
 return template.evaluate();
}

上記のように拡張子「.html」は指定する必要がありません。indexと指定しましょう。
コード.gsに上記の関数を書いたら、今度はindex.htmlを設置します。
GASでは、ファイル一覧の右上にある「+」ボタンからファイルを追加するのですが、「スクリプト」か「HTML」しか設置することができません。つもり、CSSやJS(JavaScript)ファイルを設置することができません。

実際にBootstrapのサイトからファイルをダウンロードして頂くとわかりますが、Bootstrap用のJSや、CSSファイルは大量のソースが書かれていますので、すべてをindex.htmlファイルの中に記載するのは現実的ではありません。
ではどうするかというと、HTMLファイル内で別のHTMLファイルを読み込ませるのです。
CSSファイルやJSファイルもHTMLファイルとして読み込ませる必要があります。

今回は上記のようなファイルを設置しており、index.htmlから読み込まれるようにしています。
実際のindex.htmlが下記になります。

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <?!= HtmlService.createHtmlOutputFromFile('css_reset').getContent(); ?>
    <?!= HtmlService.createHtmlOutputFromFile('css_bootstrap').getContent(); ?>
    <?!= HtmlService.createHtmlOutputFromFile('css_style').getContent(); ?>
  </head>
  <body>
  <?!= HtmlService.createHtmlOutputFromFile('menue').getContent(); ?>
  <div class="container">
  <form method="POST" action='<?=posturl?>'>
    <div class="table-responsive">
    <table class="table">
        <tr>
          <th width="20%">名前</th>
          <td><?=username?></td>
        </tr>
        <tr>
          <th>状態</th>
          <td><?=status?></td>
        </tr>
    </table>
    </div>

    <div id='realtime'></div>
    
    <div class="text-center">
      <input type="submit" value="<?=button_label?>" class="btn btn-primary">
      <input type="hidden" name='type' value="<?=stamp_type?>">
    </div>
  </form>  
  </div>
  <script>
    function showClock() {
      let nowTime = new Date();
      let nowYear = nowTime.getFullYear();
      let nowMonth = nowTime.getMonth();
      let nowDate = nowTime.getDate();
      let nowHour = nowTime.getHours();
      let nowMin  = nowTime.getMinutes().toString().padStart(2, '0');
      let nowSec  = nowTime.getSeconds().toString().padStart(2, '0');
      let msg = nowYear + "年" + nowMonth + "月" + nowDate + '日<br>' + nowHour + ":" + nowMin + ":" + nowSec;
      document.getElementById("realtime").innerHTML = msg;
    }
    setInterval('showClock()',1000);
  </script>
    <?!= HtmlService.createHtmlOutputFromFile('bootstrap').getContent(); ?>
  </body>
</html>

外部ファイルの読み込み

HtmlService.createHtmlOutputFromFile(‘ファイル名’).getContent();と記載することで、記述部分に別のファイルのHTMLソースを出力することができます。
実際にheadやヘッダー部分、フッター部分は外部のファイルを読み込むようにしています。

Bootstrapの場合、ダウンロードしたファイルは複数ありますが、今回利用しているのは、bootstrap.min.cssと、bootstrap.min.jsの2つになります。
bootstrap.min.css は、css_bootstrap.htmlに名前を変更し、 bootstrap.min.js は、bootstrap.htmlに変更しました。
上記のindex.htmlのソースコードをわかりやすく表したのが、下の図になります。

css_reset.htmlとcss_style.htmlは、こちらで独自に書いたCSSになります。
注意事項としては、今回HTMLファイルとして外部ファイルを読み込ませているため、ファイルをそのままCSSやJavaScriptとして読み込ませることができません。

ですので、CSSの場合は、< style >~</style>というタグで囲む必要があり、JSの場合は、<script>~</script>タグで囲む必要があります。

css_bootstrap.htmlのソース
bootstrap.htmlのソース

ちなみに、index.htmlに直接書き込んでいるJavaScriptがありますが、あれはリアルタイムで動く時計を表示するためのコードで、bootstrapと同じようにファイルを外部に置くこともできます。

また、index.htmlのbodyタグ内で読み込んでいるmenue.html(スペルミスです。本当はmenu.htmlとしたかった。)ですが、CSSやJSの部分ではなく、純粋なHTMLの部分を外部読み込みしています。
ヘッダーや、メニューなど、パーツごとに外部読み込みすることで、複数ページにまたがって共通して使用する時に、何度も同じHTMLコードを書かなくて済みます。

問題発生!レスポンシブにならない!

ここで問題が発生しました。本来Bootstrapで作った画面は、レスポンシブになるはずだったのですが、スマホで見てもレスポンシブ画面にならないのです。

スマホで見た時の画面

Webブラウザをギュッと狭めた場合は、レスポンシブに反応していましたが、スマホで表示した場合は、PCと同じ比率の画面になってしまいました。
もしかすると、GASのHTML画面は、iframe内に表示されていることが関係しているのかもしれません。

viewportを追加したり、

<meta name="viewport" content="width=device-width,initial-scale=1">

<meta name="viewport" content=" width=320, initial-scale=0.5 ">
などやってみましたが、駄目でした。

結局、うまくいく方法は見つからず、CSSのbodyの箇所に「zoom:2;」を追加して、コンテンツ自体を大きく表示するようにしました。(結果的にPCでも大きく表示されてしまいます。)

そこまで変わりませんが、少し見やすくなりました。

今回は、BootstrapをGASのHTMLで使う方法について解説しました。
このテンプレートを使った勤怠システムについての説明はまた別の記事でご紹介したいと思います。