TL;DR —
With object … End Withは、オブジェクトに一度だけ名前を付け、 そのメンバーに先頭のドットだけで届かせてくれます:.Value、.Font.Bold、.Interior.Color。打つ量が減り、読みやすく、そして本当に速くなります。 VBA がオブジェクト参照を毎行ではなく一度だけ解決するからです。仕掛けのすべては、 その先頭のドットに宿っています:.FontはあなたのWithオブジェクトに バインドし、ドットなしのFontはそうならない — それは暗黙のオブジェクト (たいていアクティブシート)にフォールバックし、無言で間違ったものを変えて しまいます。
With Sheets("Report").Range("A1")
.Value = "Total" ' 各ドットの意味:Sheets("Report").Range("A1") . ...
.Font.Bold = True
.Font.Size = 14
.Interior.Color = vbYellow
End With
深いオブジェクトのパスは、Excel VBA のあちこちにあります:
ThisWorkbook.Worksheets("Data").Range("A1").Font.…。この接頭辞を 10 行連続で
打つのは、退屈で、実行も遅く、読みにくいものです — そして別のセルに向け直したく
なったら、10 か所を編集することになります。With はこの 3 つを一度に解決します:
最初の行でオブジェクトを述べ、あとはブロック内の各行をドットでそこにぶら下げるの
です。この言語で最も単純な構文の 1 つでありながら、微妙に間違えやすいものの 1 つ
でもあります。
この記事で学べること
- 考え方の軸 —
Withは、代数の2(a+b)のように、くり返す接頭辞をくくり出すこと - ただ見た目が整うだけではない理由:
Withはオブジェクト参照を一度だけ解決すること - ドット抜けの罠 —
Font対.Font— そしてなぜそれが無言で失敗するのか - 入れ子の
Withブロックがドットをどう解決するのか、そしてなぜ 2 つで止めるべきか - このまとまりを束ねる
With+For Eachの定石
考え方の軸:くり返す接頭辞をくくり出す
With を、2*a + 2*b + 2*c を 2*(a + b + c) と書き直すときの「くくり出し」の
ように考えてください。くり返される部分 — ここではオブジェクトのパス
Sheets("Report").Range("A1") — を一度だけ述べ、括弧の中のすべてはそれが掛けられて
いると理解されます。VBA では「括弧」が With … End With で、「それを掛ける」が
先頭のドットです。
' With なし — 接頭辞が毎行くり返される
Sheets("Report").Range("A1").Value = "Total"
Sheets("Report").Range("A1").Font.Bold = True
Sheets("Report").Range("A1").Font.Size = 14
' With あり — 一度だけ書いて、ドットで入り込む
With Sheets("Report").Range("A1")
.Value = "Total"
.Font.Bold = True
.Font.Size = 14
End With
どちらもまったく同じことをします。2 つ目は短く、1 回の編集で向け直せ、そして —
次のセクションで示すように — 実際に速く走ります。ブロック内のすべては、With
行のオブジェクトを暗黙の接頭辞として持ちます。
見た目だけの話ではないと分かるルール:オブジェクトは一度だけ解決される
With は、打つ量を減らすだけの話ではありません。VBA が
Sheets("Report").Range("A1").Font を 10 の別々の行で目にすると、その連鎖全体を
10 回たどり直します — シートを引き、範囲を解決し、フォントを取ってくる — その
一行ごとに。With ブロックの中では、VBA はオブジェクトを、入るときに一度だけ
解決し、その解決済みの参照をドット付きの各メンバーで使い回します。
数行なら違いは目に見えません。何千ものセルにわたるループの中では、それは現実に なります。
Dim cell As Range
For Each cell In Range("A1:A10000")
With cell
.Value = .Value * 1.1 ' 'cell' の解決は反復ごとに一度…
.NumberFormat = "0.00" ' …三度ではない
.Font.Color = vbBlue
End With
Next cell
With がなければ、各 cell. は毎行その範囲オブジェクトを参照解決し直します。
With があれば、その参照解決は反復ごとに一度だけ起きます。ルールはこうです:
同じオブジェクトのメンバーに 3 つ以上触れるとき — とくにループの中では — それらを
With で包む。 読みやすさの改善が同時に速度も買ってくれる、数少ない例です。
別のオブジェクトを変えてしまう罠:先頭ドットの抜け
これは、With を単に便利なものではなく危険なものに変えるバグです。先頭のドット
こそが、メンバーを With オブジェクトに結びつけます。それを外すと、メンバーは
エラーになりません — 別の何かにバインドされるのです。
With Sheets("Report").Range("A1")
.Value = "Total"
Font.Bold = True ' バグ:先頭ドットなし — これは With オブジェクトのフォントではない
End With
.Font.Bold は Sheets("Report").Range("A1").Font.Bold を意味します。しかし
Font.Bold — ドットなし — は修飾されていない参照です。VBA はそれをアクティブ
シートの暗黙のコンテキストに対して解決するので、コンパイルエラーになるか、もっと
悪いことに、たまたまアクティブなシート上のセルを無言で書式設定してしまいます。
何も警告してくれません。With オブジェクトは手つかずのまま、別のオブジェクトが
変わるのです。
ルールは機械的で、頭に焼き付ける価値があります:With ブロックの中では、その
オブジェクトに属するメンバーはすべてドットで始まらなければならない。 With
ブロックをレビューするときは、左端を目で追ってください — . で始まっていない
ものは、別のオブジェクトへの意図的な参照か、さもなくばバグです。(これは
VBA ActiveSheet で扱う「暗黙の ActiveSheet」ミスと
同じ系統です — 修飾されていない Range や Cells は、たまたまアクティブなシート
に静かにくっつきます。)
入れ子のルール:ドットは最も近い With にバインドする
With ブロックは入れ子にでき、サブオブジェクトへ掘り下げるのに実際に役立ちます。
しかし解決のルールが人を引っかけます:先頭のドットは、つねに最も内側の With
にバインドします。
With Sheets("Report")
.Range("A1").Value = "Report" ' ドット 1 つ -> シート
With .Range("A2").Font ' フォントに対する内側の With を開く
.Bold = True ' .Bold -> フォント(最も内側)、シートではない
.Size = 12
End With
.Range("A3").Value = "Done" ' End With のあとはシートに戻る
End With
内側のブロックの中では、.Bold はフォントのものであって、シートのものでは
ありません。2 段までなら正しく読みやすい — しかし 3 段や 4 段になると、各ドットが
どのオブジェクトを指すのかの当てっこになってしまいます。ルールはこうです:
With ブロックの入れ子は最大 2 つまで。 それより深くなるなら、中間のオブジェクト
変数に代入し(Set fnt = .Range("A2").Font)、ドットの積み重ねの代わりに、
読み手に名前を与えましょう。
このまとまりを束ねる定石:With + For Each
With と For Each は自然な相棒です。For Each は
オブジェクトを 1 つずつ手渡し、With はループ変数をくり返すことなくそのオブジェクト
をすっきり扱わせてくれます。
Dim cell As Range
For Each cell In Sheets("Data").Range("B2:B100")
With cell
If .Value < 0 Then
.Interior.Color = vbRed
.Font.Bold = True
End If
End With
Next cell
声に出して読むと、ほとんど日本語のままです:「各セルについて、そのセルで — もし
負なら、赤く塗って太字にする」。この組み合わせ — コレクションを歩くための
For Each、各メンバーに作用するための With — は、Range
全体にわたる、すっきりした書式設定やデータ標示のマクロの背骨です。
ExcelMaster の活用
With は、千回くり返される小さなことです:接頭辞をくくり出し、ドットを忘れず、
深く入れ子にしすぎない。これはまさに、読みやすいマクロと脆いマクロを分ける機械的な
心配りであり — そして、ただシートを書式設定したいだけのときに、できれば考えたく
ない類のことです。
ExcelMaster なら、
代わりに結果を説明できます。「Data シートで、B 列の負の値をすべて赤くして太字に
して」と言えば、そのロジックを書いて実行します — すべてのオブジェクト参照を正しく
修飾するので、ドット抜けが引き起こす無言の「間違ったシート」バグは、そもそも起き
ようがありません。定期実行するマクロを手書きするときは、これからも自分で With に
手を伸ばすことになるでしょう。しかし日々の書式設定と標示の作業なら、望むものを
説明する方が、先頭のドットを一つひとつ手で正しく打つより勝るのです。
よくある質問
VBA の With ステートメントは何をしますか?
With object … End With はオブジェクトに一度だけ名前を付け、そのメンバーに、
フルのオブジェクトパスを毎行くり返す代わりに、先頭のドットだけ(.Value、
.Font.Bold)でアクセスできるようにします。コードは短く、向け直しやすく、そして
速くなります — VBA がオブジェクト参照を、各行でではなく入るときに一度だけ解決する
からです。
With ブロックが正しいオブジェクトを変えてくれないのはなぜですか?
ほぼいつも、先頭のドットの抜けです。With obj の中で .Font は obj を指し
ますが、ドットなしの Font は修飾されていない参照で、アクティブシートの暗黙の
コンテキストにバインドします — だから無言で間違ったオブジェクトを変えてしまうの
です。With オブジェクトに属するメンバーはすべて、ドットで始まらなければなりません。
With ステートメントは本当に VBA を速くしますか?
はい、控えめにですが、ループの中では効いてきます。VBA は With 行でオブジェクトを
一度だけ解決し、その参照をドット付きの各メンバーで使い回します。フルのオブジェクト
連鎖を各行でたどり直す代わりにです。2、3 行では気づきませんが、何千回もの反復に
わたれば、省かれた参照解決が積み上がります。
VBA で With ステートメントを入れ子にできますか?
はい。先頭のドットはつねに最も内側の有効な With にバインドするので、
With Sheets("Report") の中の With .Range("A2").Font は .Bold をフォントの
ものにします。2 段までは読みやすいですが、それより深い入れ子は、各ドットがどの
オブジェクトを指すのか分かりにくくします — 3 段以上入れ子にする代わりに、中間の
オブジェクト変数に代入しましょう。
ブロックの中で With オブジェクトそのものを変えられますか?
いいえ — With の参照は、ブロックに入った時点で固定されます。With が指す先を
途中で付け替えることはできません。別のオブジェクトを扱うには、End With で
ブロックを閉じ、新しいものを開きます。オブジェクトのメンバーを読み・書きするのは
自由ですが、ブロックの指す先を変えることだけはできません。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-08-01。
関連ガイド: VBA For Each · VBA Collection · VBA Range · VBA ActiveSheet · VBA For Loop
