※本記事はプロモーションを含みます
目次
スプレッドシートを業務の基幹ツールや簡易データベースとして使っていると、スクリプト実行結果のステータス表示やバリデーションエラーの警告表示など、GASでセルの文字色を変更したい場面が頻繁に出てきます。ただし、単にセルを選択してメニューからパレットを選ぶ作業なら手作業で十分です。なので、API経由で取得した数千行のデータ判定結果に応じて文字色を赤や青に動的に変えたい場合、Google Apps Script側から正確かつ高速に制御しなければなりません。というのは、単一セルへの基本的な適用手順と、業務コードでそのままループを回した際に直面する実行時間上限への対策まで、実際に動くコードをベースに掘り下げていくからです。
setFontColorで単一セルの色を即座に書き換える最小構成
特定のエラー発生セルや、バッチ処理完了時の通知用セルなど、ピンポイントでセルの文字色を変更する処理は最も基本的な操作です。なので、まずは対象シートを取得しましょう。そして、セル範囲(Range)を特定してから文字色を設定する最小限のコードを確認しましょう。
function changeSingleCellFontColor() { ... }
この処理を実行すると、現在アクティブなシートのA1セルに入力されているテキストの文字色が青色に変わります。ただし、実務ではバッチ処理が正常に完了したステータスセルを青文字にします。なので、バリデーションチェックで必須項目が空欄だったセルを赤文字にして担当者に修正を促すトリガー連動処理でよく使います。というのは、このコードを使うタイミングは、更新対象が1箇所から数箇所程度と明確に限定されているからです。たとえば日次集計のサマリーシートにあるヘッダーや、処理ステータスを管理する特定のフラグセルを更新する用途であれば、この1行だけで目的を果たせます。ただし、これをそのまま100行ある売上データの各行をループで判定しながら塗る書き方に流用すると、処理速度が急激に低下し始めます。スプレッドシートに対する書き込み処理は、1回呼び出すごとにGoogleの内部サーバーとの通信が発生します。なので、呼び出し回数が増えるほどスクリプトの実行時間が肥大化します。1セルだけの更新であれば体感時間はコンマ数秒です。ただし、数十行を超えるデータに対して同じ感覚で適用しようとすると、処理が重くなる原因になる点にはあらかじめ注意しましょう。
また、文字色を変更する対象のセルに数式が入っている場合や、セル内の文字列の一部だけに色を付けたい場合、このメソッドではセル全体の文字列に対して一律で指定した色が適用されます。ただし、特定の一部の文字だけを赤くしたい場合には、RichTextValue関連の別メソッドを使う必要があります。なので、セル全体の視認性を上げる目的であれば、setFontColor()を直接呼ぶのが最も手軽でメンテナンスしやすい書き方です。
指定できるカラー形式とデフォルトに戻す際のリセット値
セルの文字色を変更するにあたって、引数として渡す色の指定方法には大きく分けて16進数のカラーコード(HEX値)と、定義済みの色名(カラーネーム)の2通りが存在します。ただし、基本的にはデザインの揺らぎを防ぎ、他システムやCSSとトーンを合わせるために16進数指定を使います。というのは、それが実務で一般的だからです。
色名を指定する場合、redやblue、green、blackといった一般的な英語の文字列をそのまま渡すことができます。ただし、パッと見でどのような色が設定されているのかがコード上で把握しやすいです。なので、開発中の検証コードや、エラー箇所を暫定的に目立たせたいだけの簡易スクリプトであれば色名指定でも問題ありません。ただし、実際の業務運用では視認性を落とさないために少し落ち着いた赤色(例:#d93025)にしたいです。なので、コーポレートカラーに合わせた特定の青色(例:#1a73e8)を使いたいといった要件が必ず出てきます。というのは、最初から#で始まる6桁の16進数文字列を定数として定義して渡す設計にしておく方が、後からのデザイン変更やリファクタリングに強くなるからです。
文字色を元に戻したい場合の挙動についても把握しましょう。一度文字色を赤や青に変更したあと、データを再取得して正常値に戻った際、色を解除してシートの初期設定に戻したいケースがあります。ただし、このとき安易に#000000(黒)を指定してしまうと、後からスプレッドシートの全体テーマをダークモードに変更したり、別のアカウントで異なるテーマが適用されたりした際に、意図しない見栄えの崩れを引き起こすことがあります。なので、シート本来のデフォルトの文字色に戻したい場合は、引数にnullを渡すのが正しい作法です。sheet.getRange(“A1”).setFontColor(null);と記述することで、セルに明示的に設定されていた文字色のオーバーライドが解除されます。というのは、これでスプレッドシート標準の文字色へとリセットされるからです。
ループ処理で1セルずつ塗るとAPI制限やタイムアウトに直面する
業務でありがちな失敗が、数十件から数千件の行データに対して、forループの中でsetFontColor()を1セルずつ連続実行してしまう実装です。ただし、GAS セル 文字色 変更の処理を自動化しようとした際、多くの人が最初にこの実装で速度低下の壁にぶつかります。
例えば、500行のデータに対して1行ずつステータスを読み取り、もしエラーという文字が含まれていたらそのセルの文字色を赤に変更する処理を素朴に書くと次のようになります。行ごとにgetRange(i, 1).setFontColor(“#ff0000”)を呼び出すことになります。ただし、この書き方をすると1セル処理するたびにGoogleのバックエンドAPIへHTTPリクエストが飛ぶのと同じようなオーバーヘッドが生じます。なので、1回の書き込みに0.1秒かかったとすると、500行のデータを処理するだけで50秒以上を消費してしまいます。Google Apps Scriptには無料アカウントで6分、Workspaceアカウントでも最大30分というスクリプト実行時間の厳格な上限が設けられています。というのは、対象データが1000行や2000行に膨らんだ瞬間に、スクリプトはタイムアウトで異常終了するからです。
さらに、実行時間の上限に達しなかったとしても、短時間に大量の読み書きAPIを叩き続けることで、Googleの内部クォータ制限(短時間あたりのAPIリクエスト頻度上限)に引っかかります。なので、「Service invoked too many times」というエラーが発生して処理が中断されるリスクが高まります。ただし、中途半端に行の途中でスクリプトが止まると、どこまで文字色が変更されていてどこからが未処理なのかが分からなくなります。というのは、再実行した際にデータの不整合を引き起こす要因にもなるからです。したがって、更新対象の行数が複数存在することが分かっている処理では、単一セル用のメソッドをループの中で安易に回す書き方は避けましょう。
複数セルの文字色を一括で書き換えるならsetFontColorsを使う
複数行・複数列にまたがるセルの文字色を高速に変更したい場合は、範囲全体のセル色を2次元配列として一括で流し込めるsetFontColors()を使用します。なので、どれだけデータ行数が多くても、シートへの書き込みAPI呼び出しをわずか1回で完結させることができます。
function updateBatchFontColors() { ... }
このコードでは、まずシートから対象範囲のデータをgetValues()で一度にメモリ上へ吸い出します。なので、JavaScriptの配列操作(map)を使って判定を行っています。そして、セルの配置と完全に一致する行×列の2次元配列を作成した上で、最後にsetFontColors(colors)を1回だけ実行しましょう。
このアプローチを採用する最大のメリットは、圧倒的な実行速度の向上です。ただし、500行×3列(計1500セル)の文字色を変更する場合でも、API呼び出しがデータの取得と反映の計2回だけで済みます。なので、処理時間は1秒未満で終わります。というのは、ループ内で1行ずつ色を塗っていた頃と比べて数十倍以上の高速化が見込めるため、データ件数が将来的に増えたとしても実行時間制限に怯える必要がなくなるからです。
注意点として、渡す2次元配列のサイズは、適用対象として指定したrangeの行数および列数と完全に一致していなければなりません。ただし、行数が1行でも足りなかったり、特定の行だけ列の要素数がズレていたりすると、「パラメータのサイズが範囲のサイズと一致しません」という実行時エラーが発生して処理全体が失敗します。なので、配列を組み立てる際は、元データの行・列の構造を崩さないように慎重にマッピング処理を構築しましょう。
条件付き書式との優先度競合や表示のズレを防ぐポイント
GASでセルの文字色を変更するコードを正しく記述したにもかかわらず、スクリプトがエラーなく終了したのに画面上の文字色が全く変わらない現象に遭遇することがあります。ただし、このトラブルの主たる原因は、スプレッドシート側に手動または過去の設定によって適用されている条件付き書式との優先度関係にあります。
スプレッドシートの表示仕様において、条件付き書式による色のオーバーレイは、GASのsetFontColor()やメニューから直接指定した通常の文字色設定よりも描画の優先度が高く設定されています。なので、もし対象セルに対して値が特定の条件を満たすときに文字色を黒にする条件付き書式ルールが既に適用されている場合、スクリプト側でどれだけ赤や青の文字色を流し込んでも、画面上のレンダリングは条件付き書式のルールによって上書きされ、見た目が一切変わりません。というのは、スクリプトによる文字色変更を意図通りに反映させたい場合は、シート上の競合する条件付き書式ルールを削除するか、GAS側から既存のルールを一時的に退避・クリアする処理を入れる必要があるからです。
また、文字色だけを変更しても背景色とのコントラストが不足して文字が読めなくなる視認性の問題も実務では頻発します。ただし、エラー行を強調しようとして赤文字(#ff0000)を設定したものの、そのセルに既に薄い赤やオレンジの背景色が設定されていた場合、文字が背景に溶け込んでかえって見落としの原因になります。なので、ステータスやバリデーション結果を視覚的に通知する仕組みを作る際は、文字色だけでなく必要に応じてsetBackground()やsetBackgrounds()を併用しましょう。というのは、背景色と文字色の双方が適切なコントラスト比を保てるように一括制御する設計を検討すべきだからです。
対象セルが1つだけなのか、それともデータ行全体なのかを見極めましょう。そして、状況に応じてsetFontColor()とsetFontColors()を適切に使い分けましょう。

