目次
スプレッドシートの集計作業や運用業務を行っていると、特定範囲(たとえばA列)に適用されている背景色や文字色、フォントスタイル、罫線などのデザイン情報だけを、すでに別の計算式や手入力データが入っている隣の列(B列など)へ反映させたい状況がよくあります。日々の業務画面で「スプレッドシート 書式だけコピー」を行いたいケースです。
ここで安易に通常のコピー&ペースト操作をGASで再現しようとして、標準的な copyTo メソッドをパラメーターなしで呼び出すと、コピー先の列に入っていた重要な計算式や数値データまでコピー元の値でまるごと上書きされて消え去ってしまいます。PasteType を指定する方法もありますが、範囲の取得やメソッドの選択を誤ると、意図しないセルへ書式が食い込んだり、数式の参照先がズレて集計結果が壊れるトラブルを引き起こします。
すでに値が流し込まれている列に対して、既存のデータを一切破壊することなく、純粋にデザインの書式だけを隣の列へ移植するには、GASの Range オブジェクトに用意されている専用のメソッドを正確なパラメータで呼び出す必要があります。この記事では、スプレッドシートの値を保持したまま書式だけコピーしたい場合の実務的な回避策と、パラメータの指定で発生しやすい領域のズレや事故を防ぐためのメモをまとめておきます。
隣の列に計算結果が入っているとき通常のコピーで値が消える罠
まず、タイトルの状況で実際に発生する致命的なズレやトラブルについて触れておきます。最もよくある失敗は、コピー先(隣の列)にすでにユーザーが入力した値や、SUMやVLOOKUPなどの関数式が入っているにもかかわらず、コピー元(左側の列)の Range に対して copyTo() をそのまま実行してしまうケースです。GASの copyTo() はデフォルトで「値・数式・書式・入力規則」のすべてを上書きするため、処理が走った瞬間にコピー先の入力内容がすべて消滅します。
この問題を回避するために copyTo(destination, {formatOnly: true}) のようなオプションを探す人もいますが、GASの Range.copyTo にはこのような形式の直感的なオプション引数は用意されていません。一般的には SpreadsheetApp.CopyPasteType.PASTE_FORMAT を指定する手法が知られていますが、処理対象の Range 指定と貼り付け先の起点セルの関係性を正確に把握していないと、貼り付け位置が1行ずれたり、列全体に余計な書式が広がって既存のレイアウトを破壊することがあります。
特に、コピー元とコピー先で「行の範囲」が微妙に異なっている場合、範囲の解釈がずれやすくなります。たとえばコピー元が A1:A10 で、コピー先の先頭として B1 を指定したつもりでも、参照の取り方によっては B1:B10 ではなく意図しない矩形領域に適用されてしまう構造的な罠が存在します。値を取り直さずにデザインだけを隣に移すには、行と列の位置関係(インデックス)を明示的に数値で指定できる専用メソッドへ切り替えるのが確実です。
領域のズレを防いで書式のみを移すコードと引数の指定ルール
セルの中身(数値や計算式)には一切手を加えず、背景色や罫線、フォントの書式だけを隣の列へ正確に移植したい場面では、copyFormatToRange メソッドを使用します。このメソッドは値の上書きを構造的に発生させないため、安全にデザインのみを転写できます。
ただし、このメソッドには「呼び出し元の Range で取得する表現(A1表記など)」と「引数で渡す領域の指定方法(数値のインデックス)」の間に強いズレが存在します。GASの getRange では通常 (行, 列) の順番で指定しますが、copyFormatToRange の引数は (targetSheet, column, column, row, row) という順番で列番号が先に来ます。ここを勘違いすると、まったく関係のない行や列へ書式がコピーされてしまうため注意が必要です。
以下は、A1:A10 の書式だけを、隣のB列(2列目)の1行目から10行目へコピーするコード例です。
function copyColumnFormatOnly() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// A1:A10 の範囲の書式(色・罫線・フォント等)だけを2列目(B列)の1行目〜10行目へ複製する
// 引数の並び: (対象シート, 開始列, 終了列, 開始行, 終了行)
sheet.getRange("A1:A10").copyFormatToRange(sheet, 2, 2, 1, 10);
}
このコードを実行すると、B1:B10 に入っている既存の値や計算式は1文字も変更されず、A1:A10 に設定されていた背景色や罫線のデザインだけが適用されます。
いつ使うかというと、毎月の集計シートで「A列にだけ綺麗に色分けや罫線のデザインが設定されており、新たにデータが入力されたB列にも同じ見た目を適用したいが、B列の計算式は絶対に消したくない」というタイミングです。
ここでずれる点は、先ほども触れた引数の順番です。getRange(“A1:A10”) で指定している範囲(1行目〜10行目)と、copyFormatToRange の末尾2つの引数 (1, 10) が一致していない場合、コピー先の書式適用範囲が上下にズレてしまいます。また、引数の列指定 (2, 2) は「2列目から2列目まで」、つまりB列単一を指しますが、ここを (2, 3) とするとB列とC列の2列分へ一気に書式が拡張されます。
このズレを回避するための文章的なポイントとして、GAS内での列と行の数え方はすべて「1から始まるインデックス(1-indexed)」であることを強固に意識してください。A列=1, B列=2, C列=3 です。A1表記の範囲から動的に数値を取得する場合は、`range.getRow()`, `range.getLastRow()`, `range.getColumn()`, `range.getLastColumn()` などのプロパティを用いて引数を組み立てると、ハードコーディングによるズレを根絶できます。
動的に範囲が変わるシートで列番号の指定ミスを防ぐアプローチ
実務で運用するスプレッドシートは、常にデータが10行目ぴったりで終わるとは限りません。週や月によって50行になったり100行になったりします。固定の数値(1や10など)をコードに直書きしていると、データが伸びたときに途中から書式が適用されなくなったり、逆にデータが存在しない空行にまで無駄な背景色がついて印刷や表示が崩れる原因になります。
動的なシートで書式コピーを行う場合は、データが存在する最終行(getLastRow)を取得し、それを copyFormatToRange の引数に連動させるアプローチを取ります。また、A列やB列といった列の位置も、将来的に列の挿入などで変わる可能性があるなら、列名を直接書くのではなく、検索や見出し行の位置から列番号を動的に計算する作法を取り入れるべきです。
例えば、コピー元の起点となる列番号を `sourceCol = 1`(A列)、コピー先の列番号を `targetCol = 2`(B列)と変数化し、最終行を `lastRow = sheet.getLastRow()` で取得します。その上で、`sheet.getRange(1, sourceCol, lastRow, 1).copyFormatToRange(sheet, targetCol, targetCol, 1, lastRow);` のように記述することで、データ長の変化に追従する柔軟なコードになります。
この動的処理を組み込む際にも注意すべきズレが存在します。シート全体で `sheet.getLastRow()` を実行すると、C列やD列にたまたま入っている遥か下のメモ書きや注記の行まで「最終行」としてカウントされてしまう点です。その結果、A列やB列のデータは20行目までしかないのに、書式だけが100行目までコピーされてしまい、見た目が著しく損なわれます。特定の列の最終行だけを正確に取得したい場合は、その列の配列を取り出して後ろから空欄でないセルを探すか、Range オブジェクトの特定列に対して判定を行うロジックを噛ませることで事故を防ぐことができます。
条件付き書式やセル結合が混在する場合の崩れと対処
copyFormatToRange は大変便利なメソッドですが、対象のセル範囲に「条件付き書式」や「セルの結合」が含まれている場合、思わぬ見た目の崩れや設定の増殖が発生します。現場で事故になりやすいポイントなので、事前の理解と対策が欠かせません。
まず「条件付き書式」についてです。copyFormatToRange は静的な背景色やフォントだけでなく、セルに設定されている条件付き書式ルールも一緒にコピー先へ追加します。一見便利に思えますが、この処理をボタン押下やトリガーで何度も繰り返し実行すると、シート内部に「B1:B10に適用するルール」が実行した回数だけ何重にも重複して登録されてしまいます。これが積もると、スプレッドシートの動作が非常に重くなり、画面のスクロールや値の更新が遅延する原因になります。
条件付き書式が絡むシートでこの問題を回避するには、書式コピーを実行する前にコピー先の条件付き書式ルールを一度クリアするか、あるいは最初から条件付き書式の適用範囲を「A1:B10」のように列全体を包括するルールとして1つだけ設定しておき、GASで個別に書式コピーを行わない運用へ切り替えるのが賢明です。
次に「セルの結合」が絡む場合です。コピー元のA列でA1とA2が結合されている状態で copyFormatToRange をB列に適用すると、B列のB1とB2も強制的に結合されます。もしB1とB2にそれぞれ別の重要な数値が入っていた場合、セル結合に伴って片方の値が見えなくなったり、計算対象から外れてしまうといった不具合が発生します。コピー先に値が入っている状態での書式コピーでは、コピー元にセル結合が含まれていないかを事前に確認するか、結合を解除した標準的なセル構成に対して実行するのが安全です。
単なる色塗りだけでなく、罫線に関しても注意が必要です。コピー元に外枠太線が引かれている場合、隣の列へコピーすると「左側の罫線」がコピー先の既存の罫線と重なり、二重線になったり一部の罫線が上書きされて消える現象が起きます。デザインの崩れを完全に防ぐには、コピー処理を実行した後に、必要に応じて全体の境界線の書式を一度整える処理を補完しておくと、業務で安心して使えるスクリプトになります。

