VBAでセルを操作するとき「Range("A1")」は書けるけれど、動的な範囲指定になると急に手が止まる。そんな経験はありませんか?
固定のセル番地しか使えないままだと、行数が変わるたびにコードを書き直すことになります。データが増えるほど手間も増える悪循環です。
この記事では、Rangeの基本から Offset・Resize・CurrentRegion といった動的操作まで体系的に解説します。コピペで使えるサンプルコード付きなので、すぐに実務に活かせますよ。
NOTE
VBEの起動方法や画面の見方は「VBE画面の見方」で解説しています。初めてマクロを書く方は先にチェックしてみてください。
VBA Rangeプロパティとは?
Rangeは、ワークシート上のセルやセル範囲を指定するためのプロパティです。
指定したセルに対して値の読み書き・書式変更・コピー・削除ができます。VBAでExcelを動かすなら、ほぼ必ず使う基本中の基本です。
NOTE
Cellsプロパティでもセルを指定できます。どちらも取得するのは「Rangeオブジェクト」です。Rangeは文字列指定、Cellsは数値指定という違いがあります。
Rangeの基本構文
'--- 単一セルを指定 ---
Range("A1")
'--- セル範囲を指定 ---
Range("A1:C10")
'--- シートを明示して指定 ---
ActiveSheet.Range("A1")
Worksheets("Sheet1").Range("A1")
ActiveSheet.Range("A1") の ActiveSheet は省略できます。ただし省略すると、別シートを操作するマクロで意図しないシートを参照することがあります。慣れないうちはシートを明示しましょう。
VBA Rangeの基本的な使い方
ここからは、Rangeのセル指定パターンを1つずつ見ていきましょう。
単一セルを指定する
1つのセルを指定するには、ダブルクォーテーションの中にセル番地を書きます。
Sub SingleCell()
'--- A1セルに値を入力 ---
Range("A1").Value = "こんにちは"
End Sub
.Value は省略しても動きます。ただし明示した方がコードの意図が伝わりやすいです。
セル範囲を指定する
複数のセルをまとめて指定するには、コロン : で範囲を表します。
Sub CellRange()
'--- A1からD8までの範囲を選択 ---
Range("A1:D8").Select
End Sub
シート上でドラッグして選ぶ感覚と同じです。
飛び飛びのセルを指定する
離れた複数のセルを指定するには、カンマ , で区切ります。
Sub NonContiguous()
'--- 飛び飛びのセルを太字にする ---
Range("A1,C3,E5").Font.Bold = True
End Sub
Excelで Ctrl を押しながらクリックして複数選択するのと同じイメージです。
列全体・行全体を指定する
列や行をまるごと指定するには、列文字または行番号をコロンでつなぎます。
Sub EntireColumnAndRow()
'--- A列全体を選択 ---
Range("A:A").Select
'--- A列からF列までを選択 ---
Range("A:F").Select
'--- 1行目全体を選択 ---
Range("1:1").Select
'--- 1行目から8行目までを選択 ---
Range("1:8").Select
End Sub
名前定義されたセルを指定する
Excelの「名前の定義」で名前を付けたセル範囲は、Rangeから直接参照できます。
Sub NamedRange()
'--- 名前定義「売上合計」を参照 ---
Dim total As Double '合計金額
total = Range("売上合計").Value
MsgBox "合計: " & total
End Sub
名前定義を使うとセル位置が変わってもコード修正が不要です。実務では積極的に活用したいテクニックですね。
Offsetで隣接セルを参照する
基準セルから相対的にずらした位置を参照するのが Offset プロパティです。「A1から2行下・1列右」のような指定ができます。
Offsetの構文と動作イメージ
Range("基準セル").Offset(行方向, 列方向)
| 引数 | 説明 | 既定値 |
|---|---|---|
| RowOffset | 行方向のずらし幅(正=下、負=上) | 0 |
| ColumnOffset | 列方向のずらし幅(正=右、負=左) | 0 |
具体例を見てみましょう。
Sub OffsetDemo()
'--- A1から2行下・1列右 → B3 ---
Range("A1").Offset(2, 1).Value = "ここはB3"
'--- C5から1行上 → C4 ---
Range("C5").Offset(-1, 0).Value = "ここはC4"
'--- A1から3列右(行方向は省略) → D1 ---
Range("A1").Offset(, 3).Value = "ここはD1"
End Sub
片方の引数だけ指定すれば、もう一方は0として扱われます。行方向だけ、列方向だけのずらしも簡単です。
Offsetの実務活用例
入力データの隣のセルに処理結果を書き込むパターンです。
Sub WriteResult()
Dim lastRow As Long '最終行
Dim i As Long 'ループカウンター
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastRow
'--- A列の値を2倍にしてB列に書き込む ---
Cells(i, 1).Offset(0, 1).Value = Cells(i, 1).Value * 2
Next i
End Sub
Offsetを使えば「今見ているセルの隣」を直感的に参照できます。For文と組み合わせると、行ごとの処理がスッキリ書けますよ。
Resize・CurrentRegionで範囲を動的に操作する
Offsetが「位置をずらす」操作なら、Resizeは「範囲の大きさを変える」操作です。CurrentRegionは表全体を自動取得してくれます。
Resizeの構文と動作イメージ
Range("基準セル").Resize(行数, 列数)
| 引数 | 説明 | 省略時 |
|---|---|---|
| RowSize | 変更後の行数 | 元の行数を維持 |
| ColumnSize | 変更後の列数 | 元の列数を維持 |
Sub ResizeDemo()
'--- A1を起点に5行3列の範囲を選択 ---
Range("A1").Resize(5, 3).Select
'--- A1:C1(1行3列)を5行に広げる ---
Range("A1:C1").Resize(5).Select
End Sub
Resizeは起点(左上セル)を変えずにサイズだけ変更します。Offsetとは役割が違うので、セットで覚えておきましょう。
CurrentRegionで表全体を取得する
CurrentRegionは、指定したセルを含む「空白行・空白列で囲まれた範囲」を自動取得するプロパティです。
Sub CurrentRegionDemo()
Dim tbl As Range 'テーブル全体
Set tbl = Range("A1").CurrentRegion
MsgBox "表の範囲: " & tbl.Address & vbCrLf & _
"行数: " & tbl.Rows.Count & vbCrLf & _
"列数: " & tbl.Columns.Count
End Sub
表の行数や列数が変わっても、つねに表全体を返してくれます。「データ件数が毎回違う」という場面で重宝するプロパティです。
NOTE
CurrentRegionは保護されたシートでは使用できません。シート保護を設定している場合は注意してください。
ヘッダー行を除いてデータ部分だけを操作する
実務では「見出し行を除いたデータ部分だけ」を処理したい場面が多いです。Offset と Resize を組み合わせると実現できます。
Sub DataWithoutHeader()
Dim tbl As Range 'テーブル全体
Set tbl = Range("A1").CurrentRegion
'--- 1行下にずらして、行数を1つ減らす ---
tbl.Offset(1, 0).Resize(tbl.Rows.Count - 1, _
tbl.Columns.Count).ClearContents
MsgBox "データ部分をクリアしました"
End Sub
処理の流れを整理すると、次のようになります。
CurrentRegionで見出し行を含む表全体を取得Offset(1, 0)で1行下にずらす(見出し行をスキップ)Resize(行数 - 1)で行数を1つ減らす(はみ出し防止)
このパターンはよく使うので、ぜひ覚えておいてください。
VBA Rangeのプロパティとメソッド
Rangeで指定したセルに対して使える、主なプロパティとメソッドを紹介します。
よく使うプロパティ
| プロパティ | 説明 | 使用例 |
|---|---|---|
.Value | セルの値を取得・設定 | Range("A1").Value = 100 |
.Text | 表示文字列を取得(読み取り専用) | MsgBox Range("A1").Text |
.Formula | 数式を取得・設定 | Range("A1").Formula = "=SUM(B1:B10)" |
.Font | フォント設定(色・太字・サイズ等) | Range("A1").Font.Bold = True |
.Interior | セルの塗りつぶし | Range("A1").Interior.Color = vbYellow |
.NumberFormat | 表示形式 | Range("A1").NumberFormat = "#,##0" |
.Row / .Column | 行番号・列番号を取得 | MsgBox Range("C5").Row → 5 |
.Address | セルのアドレスを取得 | MsgBox Range("A1").Address → $A$1 |
よく使うメソッド
| メソッド | 説明 | 使用例 |
|---|---|---|
.Select | セルを選択 | Range("A1").Select |
.Copy | セルをコピー | Range("A1").Copy Range("B1") |
.Clear | 値・書式をすべて消去 | Range("A1:C10").Clear |
.ClearContents | 値だけ消去(書式は残す) | Range("A1:C10").ClearContents |
.Delete | セルを削除 | Range("A1").Delete Shift:=xlUp |
.AutoFill | オートフィル | Range("A1").AutoFill Range("A1:A10") |
TIP
.Value2は日付型や通貨型を経由せず、Doubleとしてそのまま返します。型変換が不要なぶん処理速度が速いので、大量データを扱うときは.Value2がおすすめです。
プロパティの使用例
Sub PropertyDemo()
'--- A1セルに値を入力 ---
Range("A1").Value = "売上データ"
'--- A1セルを太字+赤文字にする ---
Range("A1").Font.Bold = True
Range("A1").Font.Color = vbRed
'--- B1セルに数式を入力 ---
Range("B1").Formula = "=SUM(B2:B10)"
'--- B1セルの表示形式を桁区切りにする ---
Range("B1").NumberFormat = "#,##0"
End Sub
メソッドの使用例
Sub MethodDemo()
'--- A1:C10をコピーしてE1に貼り付け ---
Range("A1:C10").Copy Range("E1")
'--- A列の値だけクリア(書式は残す) ---
Range("A:A").ClearContents
End Sub
VBA Rangeを使った実務活用パターン
基本を押さえたところで、実務で使える具体的なコードを見ていきましょう。
パターン1: 表の見出し行を書式設定する
Sub FormatHeader()
Dim rngHeader As Range '見出し範囲
Set rngHeader = Range("A1:E1")
With rngHeader
.Value = Array("日付", "部署", "品目", "数量", "金額")
.Font.Bold = True
.Interior.Color = RGB(68, 114, 196)
.Font.Color = vbWhite
.HorizontalAlignment = xlCenter
End With
End Sub
With ステートメントを使うと、同じ範囲への操作をまとめて書けます。Range指定の繰り返しが不要になるので、コードが読みやすくなりますよ。
パターン2: 特定の範囲のデータをクリアする
入力フォームのリセットボタンなどで使えるパターンです。
Sub ClearInputArea()
'--- 入力エリア(B2:D20)の値だけクリア ---
Range("B2:D20").ClearContents
'--- カーソルを先頭に戻す ---
Range("B2").Select
MsgBox "入力エリアをクリアしました"
End Sub
.ClearContents なら罫線や色を残したまま値だけ消せます。.Clear だと書式ごと消えるので注意してください。
パターン3: セル範囲を別シートにコピーする
データを別シートに転記する場面で使えるコードです。
Sub CopyToSheet()
Dim wsFrom As Worksheet '転記元
Dim wsTo As Worksheet '転記先
Set wsFrom = Worksheets("データ")
Set wsTo = Worksheets("レポート")
'--- A1:E20をレポートシートのA1に貼り付け ---
wsFrom.Range("A1:E20").Copy wsTo.Range("A1")
MsgBox "コピーが完了しました"
End Sub
別シートを操作するときはシートの明示が必須です。
パターン4: Range(Cells, Cells)で動的に範囲を指定する
データの件数が変わっても対応できるよう、最終行を取得して範囲を動的に決めるパターンです。
Sub DynamicRange()
Dim lastRow As Long '最終行
'--- A列の最終行を取得 ---
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
'--- A1から最終行のC列までに罫線を引く ---
Range(Cells(1, 1), Cells(lastRow, 3)).Borders.LineStyle = xlContinuous
MsgBox "罫線を引きました(" & lastRow & "行目まで)"
End Sub
Cells(Rows.Count, 1).End(xlUp).Row は最終行取得の定番です。シートの最下行から上方向に検索して、最初にデータがあるセルの行番号を返します。End プロパティは Excelの Ctrl + 矢印キー と同じ動きです。xlUp(上方向)のほか xlDown・xlToLeft・xlToRight も指定できます。
最終行の取得方法について詳しくは「最終行を取得する3つの方法」をチェックしてみてください。
Range(Cells(開始), Cells(終了)) の形なら、開始位置も終了位置も変数で制御できます。
NOTE
Cellsは行番号・列番号を数値で指定するプロパティです。RangeとCellsの詳しい使い分けは「RangeとCellsの使い分け」で解説しています。
パターン5: For EachでRangeをループ処理する
Range内のセルを1つずつ処理するには、For Each が便利です。
Sub HighlightNegative()
Dim rng As Range '対象範囲
Dim cell As Range '個別セル
Set rng = Range("B2:B20")
For Each cell In rng
'--- マイナスの値を赤文字にする ---
If IsNumeric(cell.Value) Then
If cell.Value < 0 Then
cell.Font.Color = vbRed
End If
End If
Next cell
End Sub
For Each は「範囲内のセルを順番に取り出す」構文です。行番号を気にせず書けるのがメリットですね。
For Each の詳しい使い方は「For Eachでセル・シートを一括処理」で解説しています。
TIP
For Each の処理順序は「左から右、上から下(行優先)」が一般的です。ただし公式ドキュメントでは順序が保証されていません。順序が重要な処理ではFor文を使いましょう。
よくあるエラーと対処法
Rangeで遭遇しやすいエラーをまとめました。
| エラー | 原因 | 対処法 |
|---|---|---|
| 実行時エラー1004 | 別シートのRangeとCellsでシート指定が食い違っている | With の中で .Range(.Cells(...)) とドットを付ける |
| 実行時エラー1004(Rangeメソッド失敗) | Range内の文字列が不正(全角文字混入など) | セル番地に全角文字がないか確認する |
| 実行時エラー9 | 存在しないシート名を指定している | シート名のスペルを確認する |
| 実行時エラー91 | Range型変数に Set を付けずに代入 | Set rng = Range("A1") と書く |
| マクロが保存できない | .xlsx 形式で保存しようとしている | .xlsm 形式で保存する |
別シート操作時のエラーを防ぐコード
別シートのセルを操作するときに起きやすいエラー1004の正しい書き方です。
Sub CrossSheetExample()
'--- エラーが起きるコード ---
' Sheets("Sheet2").Range(Cells(1, 1), Cells(10, 3)).Select
'--- CellsがActiveSheetを参照してしまう ---
'--- 正しいコード ---
With Sheets("Sheet2")
.Range(.Cells(1, 1), .Cells(10, 3)).Select
End With
End Sub
With の中で .Cells とドットを付ければ、CellsもSheet2を参照するようになります。
Set忘れを防ぐコード
Range型の変数に代入するときは Set が必須です。
Sub SetExample()
Dim rng As Range '対象範囲
'--- 正しい ---
Set rng = Range("A1:C10")
'--- エラーになる ---
' rng = Range("A1:C10") ← Setがないとエラー
End Sub
Cellsプロパティとの違い・使い分け
Rangeと並んでよく使われるのがCellsプロパティです。
| 項目 | Range | Cells |
|---|---|---|
| 指定方法 | 文字列("A1" 形式) | 数値(行番号, 列番号) |
| 範囲指定 | Range("A1:C10") で直接指定 | 単体では1セルのみ |
| 名前定義 | Range("売上合計") で対応 | 非対応 |
| 変数との相性 | 文字列結合が必要 | 数値を直接渡せる |
| ループ処理 | やや書きにくい | 行・列を変数で制御しやすい |
使い分けのポイントは次のとおりです。
- 固定のセル範囲 → Range
- 名前定義の参照 → Range
- 変数でセル位置を動かす → Cells
- ループ処理 → Cells
- 動的な範囲指定 → Range(Cells, Cells) の組み合わせ
TIP
迷ったら「固定範囲はRange、ループはCells」と覚えておけばOKです。詳しくは「RangeとCellsの使い分け」をチェックしてみてください。
まとめ
VBA Rangeプロパティの使い方を振り返りましょう。
- Range(“A1”) で単一セル、Range(“A1:C10”) で範囲を指定
- 行全体は Range(“1:1”)、列全体は Range(“A:A”)
- Offset で基準セルからの相対位置を参照
- Resize で範囲サイズを動的に変更
- CurrentRegion で表全体を自動取得
- Range(Cells, Cells) で動的な範囲指定
- 別シートの操作は シートオブジェクトを明示
- Range型変数への代入は Set を忘れずに
Rangeはセル操作の出発点です。Offset・Resize・CurrentRegionまで使いこなせると、データ件数に左右されない柔軟なマクロが書けるようになります。ぜひVBEを開いて試してみてください。
