TL;DR —
rng.Offset(rowDelta, colDelta)renvoie une nouvelle plage décalée d'autant de lignes et de colonnes par rapport àrng. C'est un pas, pas un lieu : elle conserve la même taille, ne modifie pasrnget ne sélectionne rien. Les deux nombres sont relatifs —Offset(1, 0)avance d'une ligne vers le bas,Offset(0, 0)est la cellule elle-même, et les valeurs négatives montent ou vont à gauche. Offset déplace ;Resizechange la taille. Combinez-les et vous obtenez l'idiome de plage le plus utile de tout VBA :data.Offset(1).Resize(data.Rows.Count - 1)— « tout sauf l'en-tête ».
Offset est la façon dont une macro dit « la cellule à côté de celle que je viens
de trouver ». Vous avez localisé une correspondance, un total, un en-tête — et vous
voulez maintenant lire ou écrire la cellule une colonne plus loin ou une ligne
plus bas. Ce déplacement relatif est toute la raison d'être d'Offset, et cela
devient un réflexe dès que vous cessez de lire les arguments comme des coordonnées
pour les lire comme des pas.
Ce que vous allez apprendre
- Le modèle mental : Offset est un pas relatif, pas une adresse absolue
- Le piège du décalage d'une unité — pourquoi
Offset(1, 1)atterrit sur B2, pas sur A1 - Offset conserve la taille ;
Resizela change — et pourquoi les deux vous sont généralement nécessaires - L'idiome de saut d'en-tête
Offset(1).Resize(n - 1), expliqué - En quoi
Range.Offset(VBA) diffère de la fonctionOFFSET()de la feuille de calcul
Le modèle mental : Offset est un pas, pas un lieu
Tenez-vous sur une cellule. Offset(rowsDown, colsRight) fait autant de pas et
vous remet la cellule (ou le bloc) où vous atterrissez — une plage toute neuve.
L'originale reste intacte. Parce que le déplacement est relatif, le même
Offset(1, 0) signifie « une ligne vers le bas », que vous partiez de A1 ou de
Z500.
Sub OffsetSteps()
Debug.Print Range("B2").Offset(1, 0).Address ' -> $B$3 (une ligne vers le bas)
Debug.Print Range("B2").Offset(0, 1).Address ' -> $C$2 (une colonne vers la droite)
Debug.Print Range("B2").Offset(-1, 0).Address ' -> $B$1 (une ligne vers le haut)
Debug.Print Range("B2").Offset(0, 0).Address ' -> $B$2 (aucun déplacement)
End Sub
Remarquez que Offset(0, 0) est la cellule elle-même. C'est le signe que ce sont
des deltas, pas des positions. Si vous voulez une cellule absolue, ne calculez
pas un décalage depuis A1 — utilisez Cells(row, col). Offset sert au « relatif à
quelque chose que je possède déjà ».
La règle qui piège les débutants : le décalage d'une unité
Le bug d'Offset numéro un, c'est de lire les arguments comme une coordonnée.
Offset(1, 1) ne signifie pas la cellule A1 ni « ligne 1, colonne 1 ». Cela
signifie une ligne vers le bas et une colonne vers la droite depuis l'ancre.
Depuis A1, on atterrit sur B2.
Range("A1").Offset(1, 1).Address ' -> $B$2, PAS $A$1
Range("A1").Offset(0, 0).Address ' -> $A$1
Prononcez les deux arguments à voix haute, « bas, droite », à chaque fois, et le
bug disparaît. Cela explique aussi le motif de boucle classique : pour écrire un
résultat à côté de chaque ligne trouvée, vous décalez du compteur de boucle, et la
première ligne utilise Offset(0, …), pas Offset(1, …).
La distinction qui perturbe tout le monde : Offset déplace, Resize change la taille
Offset ne change jamais la taille d'une plage — il fait glisser la forme
entière. Déplacez une colonne de dix cellules et vous obtenez une colonne de dix
cellules ailleurs :
Range("A1:A10").Offset(0, 1).Address ' -> $B$1:$B$10 (10 cellules, déplacées à droite)
Pour changer la taille d'une plage, il faut une autre méthode,
Resize(rows, cols), qui redessine le bloc à partir de sa cellule en haut à
gauche :
Range("A1").Resize(5, 2).Address ' -> $A$1:$B$5 (5 lignes, 2 colonnes)
Ce sont les deux moitiés de l'arithmétique des plages : Offset choisit où, Resize choisit quelle taille. Vous les combinez sans cesse — le plus souvent pour retirer une ligne d'en-tête.
L'idiome à mémoriser : sauter l'en-tête avec Offset + Resize
Vous avez un tableau, en-tête compris, et vous ne voulez que le corps des données. Décalez d'une ligne vers le bas pour quitter l'en-tête — mais Offset seul conserve la même hauteur, si bien que la plage dépasse désormais d'une ligne sous les données. Resize la rétrécit de cette ligne :
Sub DataBodyOnly()
Dim tbl As Range, body As Range
Set tbl = Range("A1").CurrentRegion ' en-tête + données
Set body = tbl.Offset(1).Resize(tbl.Rows.Count - 1)
body.Select ' lignes de données seules, sans en-tête
End Sub
Offset(1) (le delta de colonne vaut 0 par défaut) fait glisser tout le bloc d'une
ligne vers le bas ; Resize(tbl.Rows.Count - 1) rogne la ligne du bas qui dépasse
désormais. Le résultat, c'est le corps des données sans l'en-tête — exactement la
plage que vous voulez trier, copier ou effacer. Cette unique ligne remplace bien
des constructions manuelles de chaînes A2:A. Pour trouver tbl sans coder en
dur, voyez comment trouver la dernière ligne et
CurrentRegion.
Le piège du bord de la feuille
Parce qu'Offset est relatif, franchir le bord de la feuille est une erreur, pas un plafonnement silencieux :
Range("A1").Offset(-1, 0) ' erreur d'exécution 1004 — impossible de remonter au-dessus de la ligne 1
Si une macro remonte ou va à gauche près du coin supérieur gauche (fréquent lors
de la recherche d'en-têtes), protégez le déplacement ou vérifiez rng.Row > 1
avant de décaler vers le haut.
La méthode Offset contre la fonction OFFSET de la feuille
Elles partagent un nom et la même idée, mais ce ne sont pas le même outil. La
fonction de feuille de calcul OFFSET() vit dans
une cellule, est volatile (elle se recalcule à chaque changement, ce qui peut
ralentir un classeur) et renvoie une valeur ou une référence pour une formule.
Range.Offset est une méthode VBA : elle renvoie un objet Range, n'est pas
volatile, et ne s'exécute que lorsque votre code s'exécute. Si vous écrivez une
macro, utilisez la méthode ; ne recourez à la fonction de feuille que lorsqu'il
vous faut une référence vivante, qui se met à jour toute seule, à l'intérieur d'une
formule.
Comment ExcelMaster aide
Le code chargé d'Offset construit d'ordinaire une seule chose : un résultat placé relativement à quelque chose que vous avez trouvé — un indicateur à côté de chaque correspondance, un cumul une colonne plus loin, une valeur copiée depuis la ligne sous une étiquette. ExcelMaster prend cette intention en langage courant — « à côté de chaque facture en retard, écris le nombre de jours de retard » — et génère la logique de référence relative, pour que vous n'ayez ni à compter les deltas à la main ni à déboguer un décalage d'une unité.
Vous écrirez encore Offset au cœur d'une boucle de macro serrée. Mais pour la
tâche quotidienne « place un résultat à côté de chaque ligne », décrire
l'emplacement est plus rapide et moins risqué que de raisonner sur (1, 0) contre
(0, 1).
Questions fréquentes
Que fait Offset en VBA ?
rng.Offset(rowDelta, colDelta) renvoie une nouvelle plage décalée d'autant de
lignes et de colonnes par rapport à rng, en conservant la même taille. C'est un
déplacement relatif : Offset(1, 0) avance d'une ligne vers le bas, Offset(0, 1)
d'une colonne vers la droite, et les nombres négatifs montent ou vont à gauche. Il
ne modifie ni ne sélectionne la plage d'origine.
Pourquoi Offset(1, 1) ne renvoie-t-il pas la cellule A1 ?
Parce que les arguments sont des deltas, pas des coordonnées. Offset(1, 1)
signifie une ligne vers le bas et une colonne vers la droite depuis la cellule
d'ancrage, donc Range("A1").Offset(1, 1) vaut B2. Utilisez Cells(row, col)
quand vous voulez une cellule absolue plutôt qu'un pas relatif.
Quelle est la différence entre Offset et Resize ?
Offset déplace une plage sans changer sa taille ; Resize(rows, cols) change la
taille depuis la cellule en haut à gauche, sans la déplacer. On les combine
souvent — rng.Offset(1).Resize(rng.Rows.Count - 1) saute une ligne d'en-tête en
descendant d'une ligne et en rétrécissant d'une.
Comment sauter la ligne d'en-tête avec Offset ?
Utilisez table.Offset(1).Resize(table.Rows.Count - 1). Offset(1) déplace le
bloc sous l'en-tête ; Resize rogne la ligne qui dépasse désormais du bas, ne
laissant que le corps des données.
VBA Range.Offset est-il identique à la fonction OFFSET de la feuille de calcul ?
Non. Range.Offset est une méthode VBA qui renvoie un objet Range et n'est pas
volatile. La fonction de feuille OFFSET() vit dans une cellule, est volatile
(elle se recalcule sans cesse) et renvoie une valeur ou une référence pour les
formules. Utilisez la méthode dans les macros ; réservez la fonction aux références
vivantes dans les formules.
Testé dans
Testé dans : Excel 365 (Windows 11), VBA 7.1 — dernière vérification le 30/07/2026.
Guides associés : VBA Last Row · VBA UsedRange contre CurrentRegion · VBA Range · Fonction OFFSET (feuille de calcul)
