🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA の Resize — アンカーから範囲を作り直す(そしてなぜデルタではなく総数なのか)

|

Excel VBA の Resize — アンカーから範囲を作り直す(そしてなぜデルタではなく総数なのか)

TL;DRResize(rows, columns) は、範囲の左上のアンカーを固定したまま、長方形を ちょうどその行数の高さ・列数の幅に描き直します。参照を移動させず(それは Offset です)、選択もしません — 同じ角に新しい範囲を返します。 落とし穴は、引数が加えるデルタではなく、最終サイズを表す 1 始まりの絶対的な総数だという 点です。Range("A1").Resize(5, 3) は A1:C5(合計 5 行・3 列)で、Resize(0, ...) は error 1004 を投げます。片方の引数を省くと、その次元は変わりません。

Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Data")
' アンカーは A1 のまま。長方形は 5 行 x 3 列に描き直される。
ws.Range("A1").Resize(5, 3).Select        ' A1:C5 を選択
' 列数を省くと幅はそのままで、高さだけを伸ばせる:
ws.Range("A1:D1").Resize(10).Select       ' A1:D10(幅は 4 のまま)

Resize は、マクロが "A1:D100" をベタ書きするのをやめ、参照を実際のデータに合わせ始めるため の方法です。小さなメソッドですが、大きな誤解が 1 つ付いて回ります。人は Resize(5) を 「5 行足す」と読みますが、意味は「5 行にする」です。本記事は、この先のすべてのルールが自然に 導かれる 1 つの考えを軸にしています。Resize はアンカーを固定し、最終サイズを述べる。 これを押さえれば、デルタではなく総数というルールも、省略した引数も、見出しを落とすイディオムも、 どれも驚きではなくなります。

この記事で学べること

  • 考え方の軸 — Resize は左上のアンカーを固定して長方形を描き直す
  • 最も大事なルール — 引数は加えるデルタではなく、合計の総数
  • 引数を省いて片方の次元をそのままにする
  • 複数セルの範囲でも、アンカーが常に左上である理由
  • 見返りの大きい 2 つのパターン — 見出しを落とす、そして配列を収まるブロックへ書き込む
  • OffsetCurrentRegion の隣で Resize がどこに収まるか

考え方の軸:Resize はアンカーを固定して長方形を描き直す

どの範囲にも左上のセル — そのアンカー — があります。Resize はそのアンカーを寸分違わぬ 位置に残したまま、長方形をあなたが与えたサイズに描き直します。

ws.Range("B2").Resize(3, 4)   ' アンカー B2 はそのまま。新しい範囲は B2:E4(3 行、4 列)

選択範囲の右下のハンドルをつかんでドラッグする様子を思い浮かべてください。左上の角は固定され、 サイズが手の中で変わります。それがこのメソッドのすべてです。2 つ、これはそうではないものが あります。1 つは Offset — こちらはサイズを変えずに参照全体を新しい 位置へスライドさせます。もう 1 つは、選択でも動作でもないという点です — Resize範囲を 返すので、その結果を使わなければなりません(.Value =.SelectSet r = ...)。1 行に ぽつんと置かれた Resize の呼び出しは、何もしません。

最も大事なルール:デルタではなく総数

これが、サイズの違う範囲を生む誤解です。Resize(rows, columns) は、最終的な長方形の 1 始まりの絶対的な総数であって、現在のサイズに足す量ではありません。

ws.Range("A1").Resize(5, 3)   ' A1:C5  -> 合計 5 行 3 列。「5 行追加」ではない
ws.Range("A1").Resize(1, 1)   ' A1     -> 単一のセル(1 行、1 列)

つまり Resize(1) は 1 行であって、「1 行縮める」ではありません。そして範囲はゼロや負のサイズ を持てないので、Resize(0, 3)Resize(-1, 3)実行時エラー 1004を投げます。行数を 計算しているなら、ガードしましょう。見出し行だけのデータブロックは Rows.Count - 1 = 0 に なり、それを Resize に渡すとクラッシュします。リサイズの前に、空のケースを確認しましょう。

引数を省いて次元をそのままにする

どちらの引数も省略でき、省いた引数は「その次元は変えない」を意味します。これは実務で最も よくある使い方です — 片側を固定し、もう片側を変える。

ws.Range("A1:D1").Resize(10)        ' 行 -> 10、列は 4 のまま  => A1:D10
ws.Range("A1:D1").Resize(, 6)       ' 列 -> 6、行は 1 のまま   => A1:F1

Resize(, 6) の先頭のカンマに注目してください — これが第 1 引数を飛ばして第 2 引数だけを設定 する方法です。Resize(10) を「10 行、幅はそのまま」と読むのはまさに正解で、だからこそ見出し 1 行を表全体に伸ばすのが 1 行で済むのです。

アンカーは常に左上

Resize はアンカーから計算し、その角を除いて既存のサイズを無視します。複数セルの範囲に 対して呼ぶと、古い寸法は消えます。

ws.Range("B2:D10").Resize(1, 1)   ' B2 に縮む - アンカーだけ

これは、Resize が既存のブロックを現在のサイズに対して相対的に調整すると期待する人を驚かせ ます。そうはなりません — 左上からサイズを言い直すのです。範囲の最初のセルから意図して形を 変えたいなら、まさにそのとおりの動きになります。うっかり大きな範囲に対して呼んでしまったなら、 サイズを捨ててしまったことになります。アンカーが明示的に必要なときは、rng.Cells(1, 1)VBA Cells を参照)がリサイズの起点となる左上のセルを返します。

見返りの大きい 2 つのパターン

役に立つ Resize は、ほぼこの 2 つのどちらかです。1 つ目は、見出し行を落とすこと — Offset と組み合わせます。Offset だけでは高さが同じままで、下端を 1 行はみ出してしまうからです。

Dim tbl As Range: Set tbl = ws.Range("A1").CurrentRegion   ' 見出しを含むブロック全体
Dim body As Range
' 見出しの先へ 1 行下げ、それから高さを 1 縮めてはみ出さないようにする:
Set body = tbl.Offset(1, 0).Resize(tbl.Rows.Count - 1, tbl.Columns.Count)

Offset は移動し、Resize は形を変える — 両者でブロックからデータ本体を切り出します。 2 つ目は、配列を、それに収まるブロックへ書き戻すことです。配列をリサイズしていない 1 つの セルに代入すると、そのセルだけが埋まります。先にアンカーを配列の寸法にリサイズしましょう。

Dim data(1 To 100, 1 To 3) As Variant
' ... data を埋める ...
ws.Range("A1").Resize(UBound(data, 1), UBound(data, 2)).Value = data   ' A1:C100 を一度で埋める

この 1 回の代入は、1 セルずつループするより桁違いに速く、Resize こそが対象をデータにぴったり 合わせる立役者です。

Offset は移動、Resize は形を変える

この 2 つを取り違えなければ、動的な範囲は面倒でなくなります。Offset は参照がどこにあるか を変え、Resizeどれくらいの大きさかを変える。 一方で位置を決め、もう一方で形を決め ます。実務のほとんどは両方を使います — アンカーを見つけ、飛ばしたい分だけオフセットし、残りに 合わせてリサイズする。そもそものブロック検出に CurrentRegion を 組み合わせれば、あらかじめサイズの分からないデータを参照するための道具一式がそろいます — データが 1 行増えた日に壊れるベタ書きアドレスを、一度も打ち込むことなく。形はデータの中に 宿ります。Resize はただ、参照をそれに合わせるだけです。

ExcelMaster の活用

Resize は、静かな罠をいくつか隠しています。サイズの違うブロックを生む、総数とデルタの 読み違え。計算した行数がゼロになったときの error 1004。既存のサイズを捨ててしまうアンカー。 そして、対象を一度もリサイズしなかったせいで 1 セルだけ埋まる配列代入。どれも、やらかした 瞬間には役立つメッセージを出してくれません。

ExcelMaster なら、代わりに結果を 説明するだけで済みます。「この表を A1 から始めてシートに書き込んで」あるいは「見出し行を除いて データを選択して」と言えば、アンカーを配列のぴったりの寸法にリサイズするか、見出しの先へ オフセットして高さを 1 縮めます — 何も投げないよう、空のブロックのケースをガードしながら。 ブックもコードもあなたの手元に残り、最初のセルだけが埋まった、あのデバッグの一幕を飛ばせます。

よくある質問

Excel VBA で Resize は何をしますか?

Resize(rows, columns) は、元の範囲の左上のセル(アンカー)を保ち、ちょうど rows の高さ・ columns の幅を持つ新しい範囲を返します。参照を移動させず、それ自体では何も選択しません — 返された範囲を使います。たとえば Range("A1").Resize(10, 3).Value = data のように。

Resize はデルタですか、それとも絶対サイズですか?

最終サイズの1 始まりの絶対的な総数であって、足す量ではありません。Range("A1").Resize(5, 3) は A1:C5(合計 5 行 3 列)で、Resize(1, 1) は単一のセルです。範囲は空にできないので、 Resize(0, ...) や負の総数は実行時エラー 1004 を投げます。

VBA で Resize と Offset の違いは何ですか?

Offset はサイズを変えずに範囲を新しい位置へ移動し、Resize は左上のアンカーを固定した ままサイズを変えます。両者は補い合い、よく一緒に使われます。たとえば rng.Offset(1, 0).Resize(rng.Rows.Count - 1, rng.Columns.Count) は、見出し行を飛ばしてから 高さを詰め、結果がはみ出さないようにします。

Resize で配列を範囲に書き込むには?

アンカーのセルを配列の寸法に合わせてリサイズし、1 つの文で代入します。 Range("A1").Resize(UBound(data, 1), UBound(data, 2)).Value = data です。配列をリサイズして いない 1 つのセルに代入するとそのセルだけが埋まるので、ブロック全体がデータを受け取れるように するのが Resize の役目で、1 セルずつのループよりはるかに高速です。

行数だけをリサイズして列はそのままにするには?

第 2 引数を省きます。Range("A1:D1").Resize(10) は高さを 10 行にし、幅は 4 のまま残して A1:D10 になります。列だけを変えるには、先頭のカンマで第 1 引数を飛ばします。 Range("A1:D1").Resize(, 6) は A1:F1 になります。

検証環境

検証環境: Excel 365(Windows 11)、VBA 7.1 — 最終確認 2026-08-15。

関連ガイド: VBA Offset · VBA CurrentRegion · VBA Cells · VBA Range · VBA For Loop