TL;DR — A cell's
.Coloris not a color name; it is a single number.RGB(r, g, b)is the function that packs three channels (each 0 to 255) into that number. The catch is the order:RGBbuilds it as red-low, blue-high (r + g*256 + b*65536), which is the reverse of a web hex. So pasting#4472C4straight in as.Color = &H4472C4swaps red and blue and gives you the wrong color. Always build colors withRGB(...), and if you must use hex, remember the bytes are backwards.
' RGB packs three channels into one Long:
Range("A1").Interior.Color = RGB(68, 114, 196) ' a specific blue, correct on every machine
' The web hex #4472C4 is the SAME blue - but do NOT paste it raw:
Range("A2").Interior.Color = &H4472C4 ' WRONG: this is #C47244 (red and blue swapped)
Range("A3").Interior.Color = RGB(&H44, &H72, &HC4) ' RIGHT: split the hex into channels
Every color property in Excel VBA — cell fill (Interior),
Font, Borders, tab color, chart series — takes the same kind of
value: a 24-bit number. RGB is how you build it, and understanding what that number is explains a
whole family of "the color is close but wrong" bugs, especially when a hex code from a website or brand
guide is involved.
What you'll learn
- The mental model —
.Coloris one number, andRGBis the packer - The trap that catches everyone — the number is stored
BGR, reversed from web hex - The
vb*color constants, and what they reveal about byte order - Reading a color back and splitting it into red, green, blue
- Why the color model is identical across fills, fonts, borders and charts
- The judgment — define your palette once as named constants
The mental model: one number, three channels
A color on screen is three dials: how much red, how much green, how much blue, each from 0 to 255.
RGB(r, g, b) takes those three dials and folds them into one integer (a Long) that Excel stores on
the object. RGB(0,0,0) is black (all dials off), RGB(255,255,255) is white (all on),
RGB(255,0,0) is pure red. There is nothing mysterious about the color — the surprise is entirely in
how the three dials get packed into one number, and that is where the bug lives.
The rule that matters most: the number is BGR, not RGB
Here is the formula RGB actually uses:
RGB(r, g, b) = r + g * 256 + b * 65536
Read that carefully: red is the lowest byte, blue is the highest. In hexadecimal the stored value
is &HBBGGRR, not &HRRGGBB. A web color like #4472C4 means red 44, green 72, blue C4 in
RGB order — but Excel stores it in BGR order. So the moment you paste a web hex straight into
.Color, you have swapped the red and blue channels:
Range("A1").Interior.Color = &H4472C4 ' Excel reads this BGR: R=C4, G=72, B=44 -> an orange-red
That is not a rounding error; it is a completely different color, and it is the number-one reason a
brand color "looks wrong in the macro" when it looked fine in the CSS. The reliable fix is to never
hand Excel a packed hex at all — hand it the three channels and let RGB pack them:
Range("A1").Interior.Color = RGB(&H44, &H72, &HC4) ' correct: channels stay in the right dials
If you genuinely must store a literal, reverse it to &HC47244. But splitting the hex into RGB(...)
is clearer and impossible to get backwards, so that is the habit worth forming.
The vb constants, and what they prove
VBA ships a handful of named color constants. They are convenient for the primaries, and they quietly confirm the byte order:
Debug.Print vbRed ' 255 = RGB(255, 0, 0) -> red is the low byte
Debug.Print vbGreen ' 65280 = RGB(0, 255, 0)
Debug.Print vbBlue ' 16711680 = RGB(0, 0, 255) -> blue is the high byte
vbRed = 255 is the tell: if red were the high byte, pure red would be 16711680. Only eight of these
constants exist (vbBlack, vbWhite, vbRed, vbGreen, vbBlue, vbYellow, vbMagenta, vbCyan),
so they are fine for a quick primary but no substitute for a real palette. For anything branded, spell
it with RGB(...).
Reading a color back and splitting it
Reading .Color gives you the packed Long. To get the three channels out, reverse the packing —
red is the remainder, blue is the top:
Dim c As Long: c = Range("A1").Interior.Color
Dim r As Long, g As Long, b As Long
r = c Mod 256
g = (c \ 256) Mod 256
b = c \ 65536
Debug.Print r, g, b ' the original three channels
The practical takeaway for comparisons: never compare a stored .Color against a raw hex literal you
typed — compare it against RGB(...), which packs the same way Excel did. Testing
If .Interior.Color = RGB(68,114,196) is correct; If .Interior.Color = &H4472C4 is the BGR bug in
reverse.
One color model, everywhere
The payoff for learning this once is that it is the same number everywhere a color appears. The
identical RGB(...) value works on:
ws.Range("A1").Interior.Color = RGB(68, 114, 196) ' fill
ws.Range("A1").Font.Color = RGB(255, 255, 255) ' text
ws.Range("A1").Borders.Color = RGB(0, 0, 0) ' border lines
ws.Tab.Color = RGB(68, 114, 196) ' sheet tab
There is no per-object color format to relearn. Fill, font, border, tab, chart series — all take the
one 24-bit Long. That is why it pays to get the packing right once: the fix and the habit transfer to
every colored thing in the object model. (The older ColorIndex property is the exception — a palette
slot, not this number; see VBA ColorIndex.)
The judgment: name your palette once
Scattering RGB(255, 242, 204) through a hundred lines is how a report ends up with three slightly
different "golds." Define the palette once, at the top of the module, as named constants — then the
color has a name, lives in one place, and is trivially changed:
Private Const CLR_HEADER As Long = 4759559 ' RGB(68,114,196) packed once
Private Const CLR_WARN As Long = 13551615 ' RGB(255,199,206)
Or keep them as RGB(...) inside a small helper. Either way, the rule is the same one that governs
constants generally: a value that means something should have a name, not be
retyped. Build with RGB, store in one place, and the BGR trap can never bite because you never write
a packed hex by hand.
How ExcelMaster helps
The BGR reversal is a genuinely nasty bug because the code is valid and the color is merely wrong — a
brand blue that ships as orange, a comparison that never matches because it is testing a raw hex against
a BGR value. It costs an afternoon precisely because nothing errors.
ExcelMaster lets you give a color the way
you actually have it — "use #4472C4," "make it our brand green," "255, 242, 204" — and it writes
RGB(...) with the channels in the right dials, never a byte-reversed hex. Ask it to "highlight cells
that match the header color" and it compares against RGB(...), not a raw literal, so the match
actually works. When you reuse a color, it lifts it into a named constant. You keep the workbook and the
code, minus the swapped-channel afternoon.
Frequently asked questions
How does the RGB function work in VBA?
RGB(red, green, blue) takes three channels, each 0 to 255, and returns a single Long number that
Excel uses as a color: RGB(255, 242, 204) is a soft gold. Internally it computes
red + green*256 + blue*65536, so the number is a 24-bit color you can assign to any color property —
Interior.Color, Font.Color, Borders.Color and so on.
Why is my color wrong when I use a hex code in VBA?
Because Excel stores colors in BGR order (blue high byte, red low byte), which is the reverse of a web
hex like #RRGGBB. Assigning .Color = &H4472C4 reads it as BGR and swaps red and blue. Split the
hex into channels instead — .Color = RGB(&H44, &H72, &HC4) — or reverse the literal to &HC47244.
How do I convert a hex color to RGB in VBA?
Split the hex into its three byte pairs and pass them to RGB: for #4472C4, write
RGB(&H44, &H72, &HC4). This keeps each channel in the correct dial and avoids the BGR byte-order
trap you hit if you assign the packed hex directly to .Color.
How do I get the red, green and blue values back from a color?
Read the packed Long from .Color, then decompose it: r = c Mod 256, g = (c \ 256) Mod 256,
b = c \ 65536. Because Excel stores the value as BGR, red is the low byte and blue is the high byte —
this reverses exactly what RGB packed.
What are the vb color constants in VBA?
VBA provides eight named constants — vbBlack, vbWhite, vbRed, vbGreen, vbBlue, vbYellow,
vbMagenta, vbCyan — each equal to an RGB(...) value (vbRed = 255 = RGB(255,0,0)). They are handy
for primaries, but for any specific or branded color use RGB(r, g, b) so you control all three
channels.
Tested in
Tested in: Excel 365 (Windows 11), VBA 7.1 — last verified 2026-09-08.
Related guides: VBA ColorIndex · VBA Cell Color · VBA Font · VBA Conditional Formatting · VBA Constant
