web3icons

When a dark logo needs a light tile

How to detect logos that disappear on a dark surface, style the light tile you place behind them, keep tiles consistent, and choose a tile over recoloring.

6 min read

A light tile is a small light shape placed behind a logo that would otherwise vanish on a dark interface: a black exchange symbol, a navy coin, a dark gray wallet mark. It's a simple fix, and it's easy to get wrong. Tile too many logos and your dark list fills with bright squares that look selected. Style them inconsistently and the tiles read as random patches.

This guide covers which logos get a tile, how the tile should look, keeping tiles consistent, and when recoloring is the better choice.

Decide by measurement, per surface

Whether a logo needs a tile is a property of the logo and the surface it sits on, not of the brand. Measure the logo's colors against your surface with the WCAG contrast ratio and apply a threshold; color contrast ratio explained has the formula.

There are two sensible rules:

  • Every color is too dark. Tile only when nothing in the logo would stay visible. A dark logo with one bright accent keeps its own look. This is conservative and produces few tiles.
  • The dominant color is too dark. Tile when the color covering the most area fails, even if a small detail passes. This catches a navy coin with a small white symbol, where the symbol shows but the coin's outline is lost. It produces more tiles.

For the threshold, something around 1.5:1 catches logos that truly disappear. Raising it toward 3:1 sounds stricter but tiles many mid-tone logos that are perfectly visible: a deep purple at 2:1 is weak at 16 px but clearly there at 32 px. Start low and look at the result.

Make the decision once, at build time, and store it with the icon. Your catalog entry then carries a flag, and rendering stays trivial:

{ "key": "exchange/example", "name": "Example Exchange", "dark": true }

The exception is any color the user controls. If people can recolor mono icons, the check has to run on the color they picked, at render time:

// contrastRatio is the WCAG formula; SURFACE is your panel color, such as '#15181E'
const tiled = variant === 'mono' ? contrastRatio(monoColor, SURFACE) < 1.5 : icon.dark === true

Web3 Icons works this way. Logos too dark for its dark interface are shown on a light tile, and a mono icon gets the same tile if you choose a dark color for it.

What the tile should look like

Color. Use a light gray rather than pure white. On a #0E1014 page, white is 19:1, the brightest thing on the screen by far. A gray such as #E4E8EE is still 15.5:1 against that page but glares less, and dark logos keep plenty of contrast on it: black is about 17:1 and a navy like #1A237E about 10.8:1. You can go darker still, to around #C9CED6, if the tiles feel too loud; black on that is still about 13:1.

Keep in mind what the tile does to the logo's light parts. An orange like #F7931A sits at about 1.9:1 on #E4E8EE. This is why the "every color is too dark" rule pairs well with tiles: a logo whose colors are all dark has nothing light left to lose.

Shape. Follow your container system. If token icons are circles, tiled tokens get a circular tile; wallets and exchanges with rounded-square icons get a rounded-square tile with the same radius. A mismatched tile shape makes the row look uneven. Circle or square? covers mixing the two.

Size and padding. The tile takes the icon's slot, and the logo shrinks inside it. It never grows past its untiled neighbors. Insetting the logo by about 12 percent per side, so it fills three quarters of the tile, works at most sizes:

Slot Logo inside Inset per side
16 px 12 px 2 px
24 px 18 px 3 px
32 px 24 px 4 px
48 px 36 px 6 px

At 16 px the logo is small to begin with, and a tile shrinks it further. If many of your dark logos only appear at 16 px, a mono version in a light color may serve better there.

.icon-slot {
  display: grid;
  place-items: center;
  width: var(--size, 32px);
  height: var(--size, 32px);
}

.icon-slot[data-tile] {
  background: #e4e8ee;
  border-radius: 50%; /* match the untiled icons' container */
}

.icon-slot[data-tile] > img {
  width: 75%;
  height: 75%;
}

Keep every tile the same

The tile should look like part of the system, which means one tile color, one radius per shape and one padding ratio everywhere in the product: lists, detail pages, modals.

Two temptations to resist. First, tinting each tile toward the brand's colors: every tile then looks different, and you are inventing brand backgrounds the project never approved. If you want the logo on its brand color, use a background version from the brand's own artwork. Second, scaling the tile up "so the logo is bigger". The slot size is the rule. When a tiled logo looks too small, fix the padding, not the slot.

Make selection look different from a tile. If your selected state is a light fill around the icon, tiled logos will always look selected. Use a different signal for selection, such as a row background, an outline ring, or a check mark, so that a tile only ever means "this logo needed a background".

Tile or recolor

Recoloring a dark logo to white is the other main fix. It removes the bright shape, but it changes the artwork. Neither is always right:

Situation Better choice Why
Multicolor logo with dark parts Tile Recoloring flattens the colors that identify it
Single-color black mark, and the brand publishes a white version Recolor with the official white version Stays calm in a dark UI, and it's the brand's own artwork
A monochrome context, such as a toolbar of mono icons Recolor One tile would be the only light shape in the row
A preview or download of the original artwork Tile The user needs to see the real colors
A dense table where dozens of logos are dark Recolor or a faint ring A column of bright tiles is noisy
You aren't sure which color versions the brand allows Tile The artwork stays untouched

Brand guidelines often say which color versions of a logo are acceptable. A tile keeps you on the original artwork, which is the safer default when you haven't checked. For the wider set of options, including rings and brand dark-mode versions, see designing logos that work on dark backgrounds.

Themes flip the problem

The flag is only valid for the surface it was computed against. In a light theme, the dark logos need no tile at all, and the problem moves to white and pale yellow logos, which fade on white. If your product has both themes, compute one flag per surface and choose at render time:

type Theme = 'dark' | 'light'

function tileFor(icon: { needsTile: Record<Theme, boolean> }, theme: Theme) {
  return icon.needsTile[theme] ? (theme === 'dark' ? 'light-tile' : 'dark-tile') : null
}

A final check before you ship: put a screen with mixed tiled and untiled logos in front of someone and ask what's selected. If they point at a tiled logo, the tiles are too loud. Dim the tile color, tighten the padding, or change how selection looks.

More in Icon design

All guides