TL;DR —
rng.Offset(rowDelta, colDelta)devuelve un rango nuevo desplazado esas filas y columnas respecto derng. Es un paso, no un lugar: conserva el mismo tamaño, no cambiarngy no selecciona nada. Los dos números son relativos:Offset(1, 0)es una fila hacia abajo,Offset(0, 0)es la propia celda y los negativos van hacia arriba o hacia la izquierda. Offset mueve;Resizecambia el tamaño. Júntalos y obtienes la fórmula de rangos más útil de todo VBA:data.Offset(1).Resize(data.Rows.Count - 1), «todo menos el encabezado».
Offset es la forma en que una macro dice «la celda de al lado de la que acabo de
encontrar». Has localizado una coincidencia, un total, un encabezado; ahora quieres
leer o escribir la celda una columna a la derecha o una fila más abajo. Ese
movimiento relativo es todo el trabajo de Offset, y se vuelve algo natural en cuanto
dejas de leer los argumentos como coordenadas y empiezas a leerlos como pasos.
Lo que aprenderás
- El modelo mental: Offset es un paso relativo, no una dirección absoluta
- La trampa del desfase por uno: por qué
Offset(1, 1)cae en B2, no en A1 - Offset conserva el tamaño;
Resizelo cambia, y por qué casi siempre necesitas los dos - La fórmula para saltar el encabezado
Offset(1).Resize(n - 1), explicada - En qué se diferencia
Range.Offset(VBA) de la función de hoja de cálculoOFFSET()
El modelo mental: Offset es un paso, no un lugar
Plántate en una celda. Offset(rowsDown, colsRight) da esos pasos y te entrega la
celda (o el bloque) en la que aterrizas: un rango totalmente nuevo. El original
queda intacto. Como el movimiento es relativo, el mismo Offset(1, 0) significa
«una fila hacia abajo» tanto si partes de A1 como de Z500.
Sub OffsetSteps()
Debug.Print Range("B2").Offset(1, 0).Address ' -> $B$3 (una fila hacia abajo)
Debug.Print Range("B2").Offset(0, 1).Address ' -> $C$2 (una columna a la derecha)
Debug.Print Range("B2").Offset(-1, 0).Address ' -> $B$1 (una fila hacia arriba)
Debug.Print Range("B2").Offset(0, 0).Address ' -> $B$2 (sin movimiento)
End Sub
Fíjate en que Offset(0, 0) es la propia celda. Esa es la señal de que son deltas,
no posiciones. Si quieres una celda absoluta, no calcules un desplazamiento a
partir de A1: usa Cells(row, col). Offset es para «en relación con algo que ya
tengo».
La regla que pilla a los principiantes: la trampa del desfase por uno
El error número uno con Offset es leer los argumentos como una coordenada.
Offset(1, 1) no significa la celda A1 ni «fila 1, columna 1». Significa una
fila hacia abajo y una columna a la derecha desde la celda ancla. Desde A1, eso cae
en B2.
Range("A1").Offset(1, 1).Address ' -> $B$2, NO $A$1
Range("A1").Offset(0, 0).Address ' -> $A$1
Di los dos argumentos en voz alta como «abajo, derecha» cada vez y el error
desaparece. También explica el patrón de bucle clásico: para escribir un resultado
junto a cada fila que encuentras, desplazas por el contador del bucle, y la primera
fila usa Offset(0, …), no Offset(1, …).
La distinción que hace tropezar a todos: Offset mueve, Resize cambia el tamaño
Offset nunca cambia el tamaño de un rango: desliza la forma entera. Mueve una
columna de diez celdas y obtienes una columna de diez celdas en otro sitio:
Range("A1:A10").Offset(0, 1).Address ' -> $B$1:$B$10 (10 celdas, movidas a la derecha)
Para cambiar el tamaño de un rango necesitas otro método, Resize(rows, cols),
que vuelve a dibujar el bloque desde su celda superior izquierda:
Range("A1").Resize(5, 2).Address ' -> $A$1:$B$5 (5 filas, 2 columnas)
Son las dos mitades de la aritmética de rangos: Offset elige dónde, Resize elige cómo de grande. Echas mano de los dos juntos constantemente, casi siempre para descartar una fila de encabezado.
La fórmula que vale la pena memorizar: saltar el encabezado con Offset + Resize
Tienes una tabla que incluye su encabezado y quieres solo el cuerpo de datos. Desplázate una fila hacia abajo para salir del encabezado, pero Offset por sí solo conserva la misma altura, así que el rango ahora se extiende una fila más allá de los datos. Resize lo encoge de vuelta esa fila:
Sub DataBodyOnly()
Dim tbl As Range, body As Range
Set tbl = Range("A1").CurrentRegion ' encabezado + datos
Set body = tbl.Offset(1).Resize(tbl.Rows.Count - 1)
body.Select ' solo filas de datos, sin encabezado
End Sub
Offset(1) (el delta de columna vale 0 por defecto) desliza el bloque entero una
fila hacia abajo; Resize(tbl.Rows.Count - 1) recorta la fila inferior que ahora
sobresale. El resultado es el cuerpo de datos con el encabezado eliminado: el rango
exacto que quieres ordenar, copiar o limpiar. Esta única línea sustituye un montón
de A2:A armado a mano. Para encontrar tbl sin codificarlo a mano, mira
cómo encontrar la última fila y
CurrentRegion.
La trampa del borde de la hoja
Como Offset es relativo, dar un paso más allá del borde de la hoja es un error, no un recorte silencioso:
Range("A1").Offset(-1, 0) ' error en tiempo de ejecución 1004 — no se puede subir de la fila 1
Si una macro sube o va hacia la izquierda cerca de la esquina superior izquierda
(algo habitual al buscar encabezados), protege el movimiento o comprueba
rng.Row > 1 antes de desplazarte hacia arriba.
Offset, el método, frente a OFFSET, la función de hoja de cálculo
Comparten nombre y la misma idea, pero no son la misma herramienta. La función de
hoja de cálculo OFFSET() vive en una celda, es
volátil (se recalcula con cada cambio, lo que puede ralentizar un libro) y
devuelve un valor o una referencia para una fórmula. Range.Offset es un método de
VBA: devuelve un objeto Range, no es volátil y solo se ejecuta cuando se
ejecuta tu código. Si estás escribiendo una macro, usa el método; recurre a la
función de hoja de cálculo solo cuando necesites una referencia viva y
autoactualizable dentro de una fórmula.
Cómo ayuda ExcelMaster
El código cargado de Offset suele construir una sola cosa: un resultado colocado en relación con algo que encontraste —una marca junto a cada coincidencia, un acumulado una columna más allá, un valor copiado de la fila que hay debajo de una etiqueta—. ExcelMaster toma esa intención en lenguaje natural —«junto a cada factura vencida, escribe los días de retraso»— y genera la lógica de referencias relativas, para que no tengas que contar deltas a mano ni depurar un desfase por uno.
Seguirás escribiendo Offset dentro de un bucle de macro ajustado. Pero para la
tarea cotidiana de «pon un resultado al lado de cada fila», describir la ubicación
es más rápido y más difícil de equivocar que razonar sobre (1, 0) frente a
(0, 1).
Preguntas frecuentes
¿Qué hace Offset en VBA?
rng.Offset(rowDelta, colDelta) devuelve un rango nuevo desplazado esas filas y
columnas respecto de rng, conservando el mismo tamaño. Es un movimiento relativo:
Offset(1, 0) es una fila hacia abajo, Offset(0, 1) es una columna a la derecha y
los números negativos mueven hacia arriba o hacia la izquierda. No cambia ni
selecciona el rango original.
¿Por qué Offset(1, 1) no devuelve la celda A1?
Porque los argumentos son deltas, no coordenadas. Offset(1, 1) significa una
fila hacia abajo y una columna a la derecha desde la celda ancla, así que
Range("A1").Offset(1, 1) es B2. Usa Cells(row, col) cuando quieras una celda
absoluta en lugar de un paso relativo.
¿Cuál es la diferencia entre Offset y Resize?
Offset mueve un rango sin cambiar su tamaño; Resize(rows, cols) cambia el tamaño
desde la celda superior izquierda sin moverlo. A menudo los combinas:
rng.Offset(1).Resize(rng.Rows.Count - 1) salta una fila de encabezado bajando una
fila y encogiendo una.
¿Cómo salto la fila de encabezado con Offset?
Usa table.Offset(1).Resize(table.Rows.Count - 1). Offset(1) mueve el bloque
hacia abajo más allá del encabezado; Resize recorta la fila que ahora sobresale
por abajo, dejando solo el cuerpo de datos.
¿Es lo mismo Range.Offset de VBA que la función OFFSET de hoja de cálculo?
No. Range.Offset es un método de VBA que devuelve un objeto Range y no es
volátil. La función de hoja de cálculo OFFSET() vive en una celda, es volátil (se
recalcula constantemente) y devuelve un valor o una referencia para fórmulas. Usa el
método en macros; usa la función solo para referencias vivas en fórmulas.
Probado en
Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación el 30/07/2026.
Guías relacionadas: VBA Última fila · VBA UsedRange frente a CurrentRegion · VBA Range · Función OFFSET de hoja de cálculo
