HTML font color

Text colour comes from the CSS color property. The old <font color> attribute was removed from the specification, and while browsers still honour it, nothing else does.

HTML font color is set with the CSS color property, applied either in a stylesheet or in a style attribute on the element.

<p style="color: #e5e7eb;">Text in a light grey.</p>

The old <font color="red"> element was removed from the HTML specification. Browsers still render it, so pages using it do not break, but it is not markup you should write now.

A page with paragraphs in several colour values, rendered as written.
A page with paragraphs in several colour values, rendered as written.

Value formats

Format Example Alpha Notes
Hex #2563eb No The most portable, six digits
Hex with alpha #2563eb80 Yes Eight digits, last two are opacity
Named rebeccapurple No 147 names, useful for quick tests
rgb() rgb(37 99 235 / 60%) Yes Space syntax is current
hsl() hsl(221 83% 53%) Yes Adjust lightness without changing hue
currentColor currentColor Inherits Matches the element's own text colour

currentColor is the useful one people miss. Set it on a border or an SVG fill and it tracks the text colour automatically.

Where to put the declaration

Three places, in increasing order of maintainability.

  1. Inline on the element. style="color: #ef4444". Highest specificity, hardest to override. Fine for one-off emphasis, bad as a system. See inline CSS.
  2. In a <style> block in the head. Keeps the page self-contained while still centralising the rule. This is the right default for a file you intend to send.
  3. In an external stylesheet. Correct for a site, wrong for a single file that has to travel, because the CSS file will not go with it.
<style>
  :root { --text: #e5e7eb; --muted: #9ca3af; --accent: #60a5fa; }
  body  { color: var(--text); background: #0b1220; }
  .muted { color: var(--muted); }
  a     { color: var(--accent); }
</style>

Custom properties put the palette in one block. Changing the body colour later is one edit, not a search across the file.

Inheritance

color inherits. Set it on body and every descendant picks it up unless something overrides it.

Three things override it without you asking:

  • Links. The browser default styles a with its own colour. Set a { color: ... } explicitly.
  • Form controls. Inputs and buttons often use the system colour rather than inheriting. Add color: inherit to them.
  • Elements with their own defaults, such as mark, which carries both a colour and a background.
button, input, select, textarea { color: inherit; font: inherit; }
A form where inputs inherit the page text colour instead of the system default.
A form where inputs inherit the page text colour instead of the system default.

Contrast that holds up

The common failure is mid grey on a light background. It reads fine to the person who wrote the sentence and poorly to everyone else.

Pair Ratio Verdict
#111827 on #ffffff About 17 to 1 Body text, comfortable
#6b7280 on #ffffff About 4.8 to 1 Body text, at the limit
#9ca3af on #ffffff About 2.5 to 1 Fails, even for large text
#e5e7eb on #0b1220 About 14 to 1 Body text on dark, comfortable

Aim for 4.5 to 1 on normal text. For secondary labels, reduce size or weight rather than fading the colour further.

currentColor and colour-mix

currentColor resolves to whatever color is on that element. It removes a whole class of duplicated values.

.badge {
  color: #f59e0b;
  border: 1px solid currentColor;
}
.icon { fill: currentColor; }

Change the text colour and the border and the icon follow. This is the standard way to make an inline SVG icon match the text beside it.

color-mix() goes further, deriving a related colour arithmetically.

.subtle {
  color: color-mix(in oklab, currentColor 60%, transparent);
}

That produces a muted version of whatever colour is in force, without naming a second hex value. It degrades cleanly, since an unsupported function invalidates only that declaration and the inherited colour stands.

Colour on specific element types

Element Behaviour
a Uses the browser default until you set it
button, input Uses the system colour, needs color: inherit
::placeholder Separate pseudo-element, set it explicitly
::selection Sets the highlight text and background
mark Carries its own colour and background
hr Takes border-color, not color, in most browsers

Placeholder text is the one most often missed. A default placeholder on a dark background is frequently unreadable.

::placeholder { color: #6b7280; opacity: 1; }
::selection { background: #2563eb; color: #ffffff; }

The opacity: 1 line matters because some browsers apply a default opacity to placeholders on top of the colour.

Semantic colour names

Hard-coding hex values throughout a document makes a later theme change a search and replace across the file. Name the roles instead.

:root {
  --text: #111827;
  --text-muted: #4b5563;
  --text-inverse: #ffffff;
  --link: #1d4ed8;
  --danger: #b91c1c;
  --success: #15803d;
}

Naming by role rather than by hue means --danger can change from red to orange without every reference reading wrong.

Colour and dark mode

A fixed dark text colour becomes unreadable when the surface changes. Pair every color with an explicit background-color on the same element, or handle it at the theme level.

@media (prefers-color-scheme: dark) {
  :root { --text: #e5e7eb; --muted: #9ca3af; }
  body  { background: #0b1220; }
}

Dark mode CSS covers the full set of adjustments, including images and borders.

Checking the result outside your editor

The colour test page opened from a share link on a second screen.
The colour test page opened from a share link on a second screen.

Screens vary more than people expect. A grey that reads well on a calibrated monitor can vanish on a laptop at low brightness.

Open the file in the HTML file opener to confirm the rules survive outside your project, then paste it into a document and turn it into a link so someone else can check it on their own screen.

Because color needs no external file, the page stays self-contained and looks the same from a link as it does locally.

Next: HTML font family list for typeface stacks, and how to change the font in HTML for the rest of the type settings.

Questions people ask

Does the font color attribute still work?

Browsers still render it for compatibility, but it was removed from HTML and is not valid markup. It cannot be overridden cleanly, it does not respond to dark mode, and it puts presentation in the content. Use the CSS color property instead.

What is the difference between color and background-color?

color sets the text and, by default, the border and text decoration colour. background-color fills the element box behind the text. Both are needed for a readable result, since a colour that works on white can be unreadable on a dark surface.

Which colour format should I use?

Hex is the most common and the most portable. Use rgb() or hsl() when you need transparency or want to adjust lightness arithmetically. Modern browsers also accept hex with an alpha channel, written as eight digits.

What contrast ratio counts as readable?

The widely used threshold is 4.5 to 1 for normal body text and 3 to 1 for large text, roughly 24px and above or 19px bold. Grey on grey is the usual failure, and it is invisible to the author because they already know what the text says.

Keep reading