TL;DR —
SpecialCellsは、アドレスではなく種類でセルを選ばせます。すべての空白、 すべての可視セル、すべての数式、すべての定数 — これらを Excel が拾います。ホーム → 検索と選択 → 条件を選択してジャンプのコード版です。最も大事なルール:1 つも 見つからないとき、空の範囲は返らず、**error 1004「セルが見つかりません」**が発生します。 だから無防備な呼び出しは時限爆弾です。必ずこう包みます:
Dim blanks As Range
On Error Resume Next
Set blanks = ThisWorkbook.Worksheets("Data").Range("A2:A1000").SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If Not blanks Is Nothing Then blanks.Value = 0 ' 空白が実際に見つかったときだけ走る
ここまでで組み立ててきた参照は、どれも1 つの長方形を表していました — Range("A1:D100")、
Cells(r, c)、Resize や CurrentRegion で切り出したブロック。しかし実務が欲しがるのは、
長方形とは限りません。埋めるべきすべての空セル、フィルター後の可視行だけ、ロックしたい
数式だけ。SpecialCells は、それを頼むための道具です — アドレスを述べるのをやめ、どんな
種類のセルが欲しいかを述べ始めます。本記事は 1 つの考えを軸にしています。SpecialCells
は参照を返すフィルターであり、「該当なし」は空集合ではなくエラーだ。 これを押さえれば、
ほかの罠はすべて消えます。
この記事で学べること
- 考え方の軸 —
SpecialCellsは種類でセルを選ぶ、条件を選択してジャンプのコード版 - 最も大事なルール — 該当がないと
error 1004を投げるので、あらゆる呼び出しをガードする - 実際に使うセルの種類 — 空白、可視、定数、数式、最後のセル
- 空白埋めパターン —
xlCellTypeBlanksと 1 行の数式 - 可視行コピーパターン — AutoFilter のあとの
xlCellTypeVisible(行数を守る切り札) - 結果がしばしば非連続(複数の
Areas)になる理由と、それが変えること
考え方の軸:SpecialCells は種類でセルを選ぶ、アドレスではなく
Range と Cells は、どのセルかに位置 — 文字列か 2 つの数値 — で答えます。SpecialCells
は別の問いに答えます。ある種類のセルはどれか? 検索する領域と種類の定数を渡すと、Excel は
その領域を走査し、条件に合うすべてのセルへの参照を返します。
Dim used As Range: Set used = ActiveSheet.UsedRange
used.SpecialCells(xlCellTypeFormulas).Interior.Color = vbYellow ' すべての数式を強調する
条件を選択してジャンプ(F5 を押してセル選択)を使ったことがあれば、これはまさに
あのダイアログのコード版です — 「定数」「数式」「空白セル」「可視セル」は同じ選択肢です。
強みは、走査を Excel がやってくれること。「これは空白か?」とシートをループで尋ねることは
一切なく、すべての空白を一度に頼み、Excel が 1 つの(しばしば奇妙な形の)範囲として返します。
最も大事なルール:該当がないとエラーになる
動くマクロをクラッシュに変えるのが、この一点です。検索領域の中で種類に合うセルが1 つも
ないとき、SpecialCells は空の範囲を返しません — error 1004「セルが見つかりません」
を発生させます。空白がゼロの範囲を SpecialCells(xlCellTypeBlanks) に通すと、マクロはそこで
止まります。
' 脆い書き方 - 空白が 1 つもない日に error 1004 でクラッシュする:
Range("A2:A1000").SpecialCells(xlCellTypeBlanks).Value = 0
これはバグではなく仕様です。SpecialCells は「該当なし」を空集合ではなく例外的な状態として
扱います。つまり安全な書き方は任意ではなく、唯一の正しい書き方です。3 段構えのガードは、
エラー処理を有効にし、呼び出しを実行し、すぐ無効に戻し、それから Nothing を判定します。
Dim hits As Range
On Error Resume Next
Set hits = Range("A2:A1000").SpecialCells(xlCellTypeBlanks)
On Error GoTo 0 ' 直ちに通常のエラー報告へ戻す
If hits Is Nothing Then
MsgBox "No blank cells to fill."
Else
hits.Value = 0
End If
On Error Resume Next は危険な 1 行だけを覆い、On Error GoTo 0 がその直後に通常のエラー
報告を戻すので、ほかのバグを黙って握りつぶすことはありません(VBA On Error
を参照)。ガードを省けば、マクロは時限爆弾になります — 空白のあるテスト用ファイルでは
すべて動き、最初のきれいなファイルで爆発します。
実際に使うセルの種類
SpecialCells(Type, [Value]) は種類の定数を取り、ほんの一握りでほぼすべてを賄えます。
rng.SpecialCells(xlCellTypeBlanks) ' 領域内の空セル
rng.SpecialCells(xlCellTypeVisible) ' フィルターや非表示行で隠れていないセル
rng.SpecialCells(xlCellTypeConstants) ' 直接入力した値(数値、文字列) - 数式ではない
rng.SpecialCells(xlCellTypeFormulas) ' 数式を持つセル
rng.Cells.SpecialCells(xlCellTypeLastCell) ' 使用範囲の右下の角
xlCellTypeConstants と xlCellTypeFormulas は、結果の型で絞る任意の第 2 引数を取ります —
SpecialCells(xlCellTypeFormulas, xlErrors) は、いまエラーを返している数式だけをつかむので、
シート上のすべての #REF! や #DIV/0! を見つける最速の方法です。
Dim bad As Range
On Error Resume Next
Set bad = ActiveSheet.Cells.SpecialCells(xlCellTypeFormulas, xlErrors)
On Error GoTo 0
If Not bad Is Nothing Then bad.Interior.Color = vbRed ' エラー数式を一度にすべて印づける
空白埋めパターン
SpecialCells に手を伸ばす定番の理由は、レポートの隙間を埋めること — 下に続く空白へラベルを
繰り返す、空の数値をゼロにする、です。空白を選び、選択全体へ一気に書き込みます。各空白の
上のセルの値をコピーするには、相対 R1C1 数式を使ってから値に変換します。
Dim gaps As Range
On Error Resume Next
Set gaps = Range("A2:A5000").SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If Not gaps Is Nothing Then
gaps.FormulaR1C1 = "=R[-1]C" ' 各空白 = 真上のセル
gaps.Value = gaps.Value ' 数式を静的な値に固定する
End If
これは数千の隙間をループなしの 2 行で埋めます。FormulaR1C1 = "=R[-1]C" は「1 行上、同じ列」
を意味し、すべての空白へ一度に書き込まれます。2 行目は数式を結果に置き換えるので、並べ替えても
埋めた値が残ります。
可視行コピーパターン(行数を守る切り札)
xlCellTypeVisible は最も役立つ種類です。なぜなら、それなしで VBA がすることのせいです。
AutoFilter を適用したあと、フィルターで外れた行は消えたのではなく
隠れているだけ — そして素の .Copy はそれらもコピーします。ユーザーに見えているものだけを
操作するには、SpecialCells(xlCellTypeVisible) を経由しなければなりません。
' フィルターが残した可視行だけをコピー - 隠れた行は飛ばす:
ws.Range("A1").CurrentRegion.SpecialCells(xlCellTypeVisible).Copy _
Destination:=Sheets("Summary").Range("A1")
xlCellTypeVisible がないと、これはブロック全体を隠れた行ごとコピーし、ユーザーがフィルターで
除いたデータを黙って貼り付けます。これはアドレス指定のクラスターと本物のフィルター作業とを
つなぐ橋です。CurrentRegion がブロックを見つけ、SpecialCells(xlCellTypeVisible) がそれを
可視行に絞ります。同じ発想でフィルター済みの行を削除できます。フィルターしてから
.Offset(1).SpecialCells(xlCellTypeVisible).EntireRow.Delete です。
複数エリアの落とし穴:結果はしばしば長方形ではない
SpecialCells を、それ以前のどの参照とも違うものにしているのがこれです。返る範囲はたいてい
非連続です。散らばった 10 個の空白は、10 個の別々のエリアから成る 1 つの参照として
返ります。それは調べ方を変えます。
Dim vis As Range: Set vis = rng.SpecialCells(xlCellTypeVisible)
Debug.Print vis.Count ' すべてのエリアを合わせた可視セルの総数
Debug.Print vis.Areas.Count ' それがいくつの別ブロックか
Dim a As Range
For Each a In vis.Areas
Debug.Print a.Address ' 連続する各ブロックを 1 つずつ
Next a
.Count はセルの総計、.Areas.Count はそれらが成す分離ブロックの数です。ほとんどの操作 —
値の設定、色づけ、別シートへの .Copy — はすべてのエリアを一度に扱うので、ループはめったに
要りません。例外は順序に依存するものです。SpecialCells で見つけた行を削除するなら、上へ
向かってループするのではなく .EntireRow を 1 回の呼び出しで削除しましょう。エリアが下から上
の順である保証はないからです。この複数エリアの形は Union と共通で、
Union は同じ非連続の参照を意図して組み立てます。
ExcelMaster の活用
SpecialCells が強力なのは、まさに鋭いからです。On Error のガードを忘れればきれいな
ファイルがマクロをクラッシュさせ、xlCellTypeVisible を忘れればフィルターが隠していた行を
コピーし、結果を長方形と思い込めばセルごとのループが誤った順序で着地します。どれも静かで
状況依存の失敗です — あなたのデータでは動き、他人のデータで壊れます。
ExcelMaster なら、代わりに
結果を述べるだけで済みます。「A 列のすべての空白を、その上の値で埋めて」や「可視行だけを
Summary シートにコピーして」と言えば、ガード付きの SpecialCells 呼び出し、Is Nothing の
確認、可視のみの経路を書いてくれます — 空白のないファイルでも、半分の行を隠すフィルターでも
生き延びる版です。ブックもコードもあなたの手元に残り、最初のエッジケースでのクラッシュを
飛ばせます。
よくある質問
なぜ SpecialCells は「セルが見つかりません」エラーを出すのですか?
検索領域の中に、指定した種類に合うセルが1 つもないとき、SpecialCells が error 1004 を
発生させるからです — 「該当なし」を空の範囲ではなくエラーとして扱います。空白セルのない領域を
SpecialCells(xlCellTypeBlanks) に通すと、マクロは止まります。呼び出しを On Error Resume Next
で包み、On Error GoTo 0 で戻し、使う前に If Not result Is Nothing を判定しましょう。
VBA でフィルター後の可視セルだけを選択するには?
xlCellTypeVisible を使います。rng.SpecialCells(xlCellTypeVisible) です。AutoFilter のあと、
フィルターで外れた行は隠れていても範囲の一部なので、素の .Copy はそれらを含めます。
SpecialCells(xlCellTypeVisible) を経由すると、コピー・色づけ・削除を、ユーザーが実際に
見えている行だけに限定できます。
xlCellTypeConstants と xlCellTypeFormulas の違いは何ですか?
xlCellTypeConstants は、直接入力した値 — あなたが打ち込んだ数値や文字列 — を持つセルを
返します。xlCellTypeFormulas は、数式を持つセルを返します。どちらも結果の型で絞る任意の
第 2 引数を取るので、SpecialCells(xlCellTypeFormulas, xlErrors) は、いま #REF! や #DIV/0!
のようなエラーを表示している数式セルだけを返します。
VBA ですべての空白セルを一度に埋めるには?
SpecialCells(xlCellTypeBlanks)(空白なしエラーへのガード付き)で空白を選び、選択全体へ 1 つの
文で書き込みます。各空白の上の値をコピーするには、gaps.FormulaR1C1 = "=R[-1]C" を使い、
続いて gaps.Value = gaps.Value で数式を静的な値に固定します。ループは要りません。
SpecialCells は連続した範囲を返しますか?
たいていは返しません。頼んだ空白や可視セルはしばしば散らばっているので、SpecialCells は
複数エリアの参照を返します。.Count はすべてのエリアを合わせたセルの総数で、.Areas.Count
はそれらが成す別ブロックの数です。ほとんどの操作はすべてのエリアを一度に扱います。連続する
各ブロックを個別に扱う必要があるときだけ For Each a In result.Areas でループしましょう。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-08-16。
関連ガイド: VBA Union · VBA Intersect · VBA AutoFilter · VBA CurrentRegion · VBA On Error
