---
title: 'Repetition and Consistency'
source: 'https://academia.sh/en/courses/interface-fundamentals/repetition-and-consistency'
course: 'Fundamentals of Interface Design'
language: en
updated: '2026-08-17T18:11:08+00:00'
license: 'CC BY-SA 4.0'
---

# Repetition and Consistency

How repetition produces learnability; extracting a decision inventory, measuring value variety below the just-noticeable-difference threshold, and the cost of snapping to a scale.

The previous lesson measured a single screen's internal consistency. An interface,
though, is not a single screen. The catalog application's search page, results list,
record detail, and borrowing confirmation are drawn at different times, often by
different people. On the search page, 8 pixels were left between the label and the
field; on the record detail page, the same relationship uses 10 pixels. Nobody's eye
catches those two pixels. The problem is that those two pixels are a decision: made,
never defended, and now impossible to remove.

This lesson counts the interface's decisions. The number itself is not a quality
measure; the quality measure is the question of how many decisions actually produce a
distinction versus how many produce only variety.

## Repetition Is a Promise About Prediction

**Repetition** is elements that carry the same function being drawn the same way.
**Consistency** is that repetition spread across the entire interface.

Repetition's value is cognitive, not aesthetic. A user runs a constant stream of
predictions while using an interface: this dark-green filled rectangle is a button, this
underlined text is a link, this pale 14-pixel line is metadata. When these predictions
are confirmed every time, learning accumulates; half the screen becomes understandable
without a second look. A single counterexample — a filled green rectangle turning out to
be an unclickable label — breaks the chain of prediction, and the user goes back to
testing every element again.

Two rules follow from this, and the two rules are not symmetric:

- **What looks the same behaves the same.** Violating this rule leads directly to an
  error; the user acts on a pattern they have learned and gets it wrong.
- **What behaves differently looks different.** Violating this rule leads not to an
  error but to slowness; the user cannot read the distinction from the form and has to
  find it by reading the text.

The second rule also draws consistency's boundary. Consistency does not mean making
everything look alike. If the **Borrow** button and the **Delete Record** button look
the same, consistency has not been achieved — an important distinction has been erased.

## The Decision Inventory

The way to make a consistency discussion measurable is to count the values actually used
in the interface. The program below takes the catalog interface's raw values for four
properties and computes three things: how many distinct values are used, how many pairs
among those values fall below the **just noticeable difference** threshold, and how many
values would change perceptibly if snapped to a scale.

```js
// 05-inventory.mjs — the interface's decision inventory, indistinguishable pair count, and snapping to a scale

// Raw values found across the catalog interface's four screens.
const inventory = [
  {
    property: "spacing (px)",
    used: [4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48],
    scale: [4, 8, 12, 16, 24, 32, 48],
    jndThreshold: 2,
  },
  {
    property: "corner radius (px)",
    used: [2, 3, 4, 6, 8],
    scale: [4, 8],
    jndThreshold: 2,
  },
  {
    property: "border width (px)",
    used: [1, 1.5, 2, 3],
    scale: [1, 2],
    jndThreshold: 0.5,
  },
  {
    property: "font size (px)",
    used: [12, 13, 14, 15, 16, 18, 20, 24, 32],
    scale: [14, 16, 20, 24, 32],
    jndThreshold: 1,
  },
];

function indistinguishablePairs(values, threshold) {
  const pairs = [];
  for (let i = 0; i < values.length; i++) {
    for (let j = i + 1; j < values.length; j++) {
      if (Math.abs(values[i] - values[j]) <= threshold) pairs.push([values[i], values[j]]);
    }
  }
  return pairs;
}

function nearest(value, scale) {
  return scale.reduce((a, b) => (Math.abs(b - value) < Math.abs(a - value) ? b : a));
}

let beforeTotal = 0;
let afterTotal = 0;

for (const e of inventory) {
  const pairs = indistinguishablePairs(e.used, e.jndThreshold);
  const fitted = e.used.map((d) => {
    const target = nearest(d, e.scale);
    return { value: d, target, shift: Math.abs(target - d) };
  });
  const visible = fitted.filter((o) => o.shift > e.jndThreshold);
  const maxShift = Math.max(...fitted.map((o) => o.shift));

  beforeTotal += e.used.length;
  afterTotal += e.scale.length;

  console.log(e.property);
  console.log(`  values used: ${e.used.length}   scale steps: ${e.scale.length}`);
  console.log(
    `  indistinguishable pairs (diff <= ${e.jndThreshold}px): ${pairs.length}   ` +
      `example: ${pairs.slice(0, 3).map((c) => c.join("/")).join("  ")}`
  );
  console.log(`  largest snap shift: ${maxShift}px`);
  console.log(`  values requiring a visible change: ${visible.length}`);
  console.log(`    ${fitted.map((o) => `${o.value}->${o.target}`).join("  ")}`);
  console.log("");
}

console.log(`total values to learn: before ${beforeTotal}   after ${afterTotal}`);
console.log(`reduction: ${(100 * (1 - afterTotal / beforeTotal)).toFixed(1)}%`);
```

```
spacing (px)
  values used: 13   scale steps: 7
  indistinguishable pairs (diff <= 2px): 6   example: 4/6  6/8  8/10
  largest snap shift: 8px
  values requiring a visible change: 3
    4->4  6->4  8->8  10->8  12->12  14->12  16->16  20->16  24->24  28->24  32->32  40->32  48->48

corner radius (px)
  values used: 5   scale steps: 2
  indistinguishable pairs (diff <= 2px): 5   example: 2/3  2/4  3/4
  largest snap shift: 2px
  values requiring a visible change: 0
    2->4  3->4  4->4  6->4  8->8

border width (px)
  values used: 4   scale steps: 2
  indistinguishable pairs (diff <= 0.5px): 2   example: 1/1.5  1.5/2
  largest snap shift: 1px
  values requiring a visible change: 1
    1->1  1.5->1  2->2  3->2

font size (px)
  values used: 9   scale steps: 5
  indistinguishable pairs (diff <= 1px): 4   example: 12/13  13/14  14/15
  largest snap shift: 2px
  values requiring a visible change: 2
    12->14  13->14  14->14  15->14  16->16  18->16  20->20  24->24  32->32

total values to learn: before 31   after 16
reduction: 48.4%
```

## The Invisible Cost of Inconsistency

The first reading of the inventory is a reduction in count: 31 distinct values come down
to 16 scale steps, a 48.4 percent reduction. On its own, that is not an interesting
number; the real finding sits in the second rows.

In the corner-radius row, five distinct values are used, and among those five values,
**five pairs** fall below the just-noticeable-difference threshold. That is, radii of 2,
3, 4, and 6 pixels are indistinguishable from one another. Four separate decisions were
made, and none of them produces a visible distinction. In the same row, the number of
values requiring a visible change when snapped to the scale is zero: all five values
slide within the threshold.

This shows what kind of cost inconsistency produces. The cost is not visual — nobody
notices the difference between 2 pixels and 3 pixels. The cost falls on the
**decision**: for every new element, the radius value is reconsidered, argued over in
reviews, and chosen differently by different teams. A visible price paid for an
invisible difference.

Looking at the total across the four properties, only 6 of the 31 values (3 + 0 + 1 + 2)
change perceptibly when snapped to the scale. The remaining 25 settle into place within
the threshold. This says that moving to a scale is not as destructive as it seems: most
of the inconsistency is invisible inconsistency, and it can be removed at no cost.

The 6 values that do require a visible change are handled separately. In the spacing
row, snapping 40 pixels to 32 pixels is an 8-pixel shift, and it changes the layout. For
these values, the question becomes "is the scale wrong": if 40 pixels is genuinely
needed, a step is added to the scale; if not, the value is snapped. A scale is not a
dogma — it is a tool that makes exceptions visible.

## When Consistency Is Deliberately Broken

Repetition has exceptions, and exceptions are not harmful; **unrecorded** exceptions
are.

In the catalog interface, the button on the borrowing confirmation screen is larger than
the buttons in the results list. This looks like an inconsistency, but it has a
justification: the action on the confirmation screen is the only action that is
expensive to undo, and no other action exists on that screen. The size difference
produces a distinction here.

The distinguishing criterion is this: **an exception is an exception if it can state the
condition under which the rule does not apply; if it cannot, it is an error.** "A larger
size is used for the single action on a confirmation screen" is a condition — it can be
audited and repeated. "40 pixels just looked better here" is not a condition.

In practice, this distinction requires an **exception record**: next to every value that
departs from the rule, the condition for the departure is written down. When no record
is kept, two things happen at once — exceptions multiply, and nobody can tell anymore
which value is the rule and which is the exception. The previous lesson asked for
optical-alignment corrections to be documented; the reasoning is the same.

## Internal Consistency and External Consistency

Consistency has two directions, and which one wins when they conflict is decided in
advance.

**Internal consistency** is the interface following its own rule. In the catalog, a
selected filter is shown the same way everywhere.

**External consistency** is the interface following the established rules of the
environment it runs in. Rules like underlined blue text being a link, confirmation
actions sitting on the right, and the way back sitting at the top left are not any
single interface's invention; the user has learned them elsewhere.

When a conflict arises, external consistency takes priority, because the user's prior
learning outweighs what a single interface teaches on its own. An interface can,
internally consistently, show links without underlines and in the same color as the
surrounding text; that is internal consistency, and it still makes it harder for the
user to find the clickable element.

## Summary

- Repetition is elements that carry the same function being drawn the same way; its
  value is cognitive, not aesthetic, because it confirms the user's predictions and
  accumulates learning.
- The pair of rules is not symmetric: something that looks the same behaving
  differently leads to an error, and something that behaves differently looking the
  same leads to slowness.
- The decision inventory ties consistency to a number; in the measured interface, four
  properties use 31 distinct values, and a scale brings that down to 16 steps.
- Most of the inconsistency is invisible: all five pairs among the corner radius's five
  values fall below the just-noticeable-difference threshold, meaning the decision cost
  was paid but no visual distinction was produced.
- Moving to a scale changes only 6 of the 31 values perceptibly; the rest settle into
  place at no cost, so the consistency debt closes more cheaply than it appears to.
- An exception is legitimate, and gets recorded, if it can state the condition under
  which the rule does not apply; in a conflict, external consistency beats internal
  consistency.

## Next Step

The visual principles section is complete here: distinction, grouping, emphasis,
alignment, and repetition. The last two lessons pointed to a shared gap — where the
alignment axes and the scale steps come from has not yet been determined. As long as
values are chosen one at a time, the inventory swells right back up. The next section
fills that gap, starting with the **grid**: it establishes the arithmetic relationship
between container width, column count, gutter, and margin, turning alignment axes from
chosen values into derived ones.
