Skip to main content

Website Colors: Red vs Blue

I manually extract RGB colors for 225 websites and graph them: red > blue > green > purple > yellow-brown.

To extend Gwern.net link-icons to include site-specific color when interacting with them, I collected 225 RGB hex colors from websites or their logos.

I visualize the color distributions in R in several ways: by channel, pairs of channels, color wheel, and 3D scatterplots.

The collected colors show a large polarization of website design towards either red or blue as the accent color, but little yellow-brown.

This shows the interesting primacy of red vs blue, but also suggests that maybe they have become overused, and people should explore the other colors, like yellow-brown.

Using Hacker news one day in October 2024, I saw a blog which made a point of coloring its link to its Twitter account in Twitter-blue, but on hover, to avoid distracting the reader but also confirm that you are interacting with what you think you are. I immediately thought this would be a great feature for Gwern.net, as a way to extend the existing link-icons by bring in the additional metadata of brand/logo/icon coloring, but without breaking the overall monochrome theme. Coloring on hover seemed to fit in perfectly with the overall design philosophy of semantic enrichment: it only provides the metadata when you are interacting with that particular link, and otherwise is invisible.

Visualizing The Colors

Courtesy of Claude-3 (since I don’t care enough about this topic enough to hack & slash through the pain & suffering of data visualizations in R), I plotted color patterns in a few ways:

## Read the CSV data
rgb <- read.csv("https://gwern.net/doc/cs/css/2024-11-08-gwern-gwernnetlinkicons-colorbysite.csv",
                colClasses=c("character", "character"))
## convert RGB,URL → to RGB frequencies:
color_counts <- table(rgb$RGB)
colors_df <- data.frame(
  RGB = names(color_counts),
  N = as.numeric(color_counts))

## Convert hex to RGB components
library(tidyverse)
colors_df <- colors_df %>%
  mutate(
    r = strtoi(substring(RGB, 2, 3), base=16),
    g = strtoi(substring(RGB, 4, 5), base=16),
    b = strtoi(substring(RGB, 6, 7), base=16))

Visualizing data:

library(skimr)
skim(colors_df)
# ── Data Summary ────────────────────────
#                            Values
# Name                       colors_df
# Number of rows             225
# Number of columns          5
# _______________________
# Column type frequency:
#   character                1
#   numeric                  4
# ________________________
# Group variables            None
#
# ── Variable type: character ────────────────────────────────────────────────────
#   skim_variable n_missing complete_rate min max empty n_unique whitespace
# 1 RGB                   0             1   7   7     0      225          0
#
# ── Variable type: numeric ──────────────────────────────────────────────────────
#   skim_variable n_missing complete_rate   mean    sd p0 p25 p50 p75 p100 hist
# 1 N                     0             1   1.62  1.69  1   1   1   2   20 ▇▁▁▁▁
# 2 r                     0             1 122.   95.9   0  29 107 221  255 ▇▂▂▃▆
# 3 g                     0             1  98.4  65.4   0  42  94 147  255 ▇▇▆▃▂
# 4 b                     0             1 101.   82.2   0  25  81 177  255 ▇▃▃▃▃

Small multiples for the 3 color channels, univariate histogram:

library(ggplot2)
library(patchwork)

p1 <- ggplot(colors_df, aes(x = r, weight = N)) +
  geom_histogram(fill = "red") +
  labs(title = "Red Channel Distribution") +
  theme_bw(base_size=40)

p2 <- ggplot(colors_df, aes(x = g, weight = N)) +
  geom_histogram(fill = "green") +
  labs(title = "Green") +
  theme_bw(base_size=40)

p3 <- ggplot(colors_df, aes(x = b, weight = N)) +
  geom_histogram(fill = "blue") +
  labs(title = "Blue") +
  theme_bw(base_size=40)

p1 / p2 / p3

The distribution of each color channel, considered separately, showing the U-curve of Red and Blue (but general indifference to Green).

The distribution of each color channel, considered separately, showing the U-curve of Red and Blue (but general indifference to Green).

Graphing the Red vs Green vs Blue color distributions against each other:

## Graph R vs G vs B separately
## Create 3 different 2D projections
plot_rg <- ggplot(colors_df, aes(x=r, y=g, size=N, color=RGB)) +
  geom_point(alpha=0.9) +
  scale_color_identity() +
  scale_size_continuous(range = c(8, 20)) +
  scale_x_continuous(limits = c(0, 255)) +
  scale_y_continuous(limits = c(0, 255)) +
  labs(
    title = "Red vs Green",
    x = "Red",
    y = "Green",
    size = "Frequency") +
  theme_bw(base_size=40)

plot_rb <- ggplot(colors_df, aes(x=r, y=b, size=N, color=RGB)) +
  geom_point(alpha=0.9) +
  scale_color_identity() +
  scale_size_continuous(range = c(8, 20)) +
  scale_x_continuous(limits = c(0, 255)) +
  scale_y_continuous(limits = c(0, 255)) +
  labs(
    title = "Red vs Blue",
    x = "Red",
    y = "Blue",
    size = "Frequency") +
  theme_bw(base_size=40)

plot_gb <- ggplot(colors_df, aes(x=g, y=b, size=N, color=RGB)) +
  geom_point(alpha=0.9) +
  scale_color_identity() +
  scale_size_continuous(range = c(8, 20)) +
  scale_x_continuous(limits = c(0, 255)) +
  scale_y_continuous(limits = c(0, 255)) +
  labs(
    title = "Green vs Blue",
    x = "Green",
    y = "Blue",
    size = "Frequency") +
  theme_bw(base_size=40)

library(gridExtra)
grid.arrange(plot_rg, plot_rb, plot_gb, ncol=1) # 3×1

Graphing all colors, red vs green vs blue, in 3 plots.

Graphing all colors, red vs green vs blue, in 3 plots.

Color wheel representation:

## ensure RGB values are in 0--1 scale:
colors_df <- colors_df %>%
  mutate(
    r = r/255,
    g = g/255,
    b = b/255)

## Create matrix for `rgb2hsv` (note the different matrix structure)
rgb_matrix <- matrix(c(colors_df$r, colors_df$g, colors_df$b), ncol=3, byrow=FALSE)
hsv_matrix <- rgb2hsv(t(rgb_matrix))

## Now add HSV columns
colors_df <- colors_df %>%
  mutate(
    hue = hsv_matrix[1,],
    saturation = hsv_matrix[2,],
    value = hsv_matrix[3,])

## Plot on polar coordinates
library(ggplot2)
ggplot(colors_df, aes(x = hue * 360, y = saturation, size = N, color = RGB)) +
  geom_point(alpha=0.9) +
  scale_size_continuous(range = c(8, 20)) +
  coord_polar() +
  scale_color_identity() +
  theme_bw(base_size=50) +
  labs(x = "Hue°")

Plotted around a color wheel.

Plotted around a color wheel.

3D volume scatterplot, using rgl for interactive 3D visualization:

library(rgl)

par3d(family = "sans", cex = 4) # quadruple text size as unreadably small
plot3d(colors_df$r, colors_df$g, colors_df$b,
       col = colors_df$RGB,
       size = colors_df$N/2,
       xlab = "Red", ylab = "Green", zlab = "Blue",
       type = "s",  # spheres
       alpha = 0.7)

3 example rotations of the dataset as a 3D scatterplot, showing the emptiness of parts of the cube.

3 example rotations of the dataset as a 3D scatterplot, showing the emptiness of parts of the cube.

Underused: Yellow?

Overall, the visualizations line up with my subjective impressions: red > blue > green > purple > yellow-brown.

It may be worthwhile exploring more purple or yellow-heavy designs. While purple remains a tricky color to work with, due to its extremely strong connotations of royalty, gay men, or small girls (eg. My Little Pony), or all 3 (Catholicism), yellow-brown seems more versatile. Possibly yellow has been underused for a long time because computer monitors were not up to subtler colors and we suffered under the tyranny of “web-safe colors” (oh no, not the bees! ahh!), but now that bright high-resolution displays are common on both desktop & smartphones (sometimes with larger colorspaces) and we have many fancy technologies like textures and vector graphics, a yellow palette may be more viable.


  1. I recommend using Firefox for this, because the Chromium color picker has strange UX limitations, like not being usable at all on websites with table-based layouts—it just doesn’t show up anywhere in the UI, while the Firefox dev tools color picker is always available. Afterwards, I learned that my MATE GUI desktop environment provides mate-color-select which seems like it’d work as well. Mac OS users can use “Digital Color Meter” (default install).↩︎

  2. Due to the thinness of the link underlines & smallness of the link icons, a pale or dark color, which was clear when used in a large logo or in large site design elements such as buttons, may vanish or just look like black, so they need lightness adjustments, perhaps using a better colorspace than RGB like LAB. Other challenges include the need for alternate SVG icons for cases where a single color is inadequate (what color is Microsoft?) and supporting the common case of “white-letter-on-colored-background”, which would be unreasonably burdensome to solve by manually creating SVGs one by one.↩︎

  3. Obviously, I am making no claims about the Internet in general—the color trends could be entirely different elsewhere on the Anglophone Internet, never mind the Chinese Internet etc. I am simply interested in the distribution of colors across the websites I tend to read or link to.↩︎