Foundations · 05

Iconography

The manual draws its icons the same way it draws everything else: 1 px contours, the isometric rhombus, the four angles. This is that plate built for the screen — one 24 × 24 box, one live area, one stroke weight that never changes. The CF arrow stays what it always was, a filled glyph and a thing apart; every icon here is drawn.

The set

Forty-three glyphs in six families: direction, operators, primitives, the solid weight, objects and instruments. Hover a tile to see the construction grid it was built on, or turn the keylines on for all of them. Click any tile to copy its markup.

Against the plate

The set is the manual's Icon System plate, and it is worth being able to check that claim rather than take it. The plate is four rows; this is what each one is and where it went.

Plate rowIsIn the set
01 — nine solid marksthe second weight: four chevrons, the X, the rhombus, the nested rhombus, the dot, the ring*-solid ×7 plus cf-dot, which was already solid
02 — ten line marksthe same marks drawn, plus the cylinder; the chevrons are doubled herethe four doubles, cf-converge, and the primitives
03 — eight objectsglobe, coin, cut sphere, node, triangle, pyramid, house, wedgeall eight
04 — nine instrumentssignal, X, cube, plane, layers, pin, hourglass, overlap, expandall nine
This set used to have twenty-two of them. The four families that shipped first covered the plate's line weight and about half its objects, and the gap was not visible from inside the set — every glyph in it was correct, so nothing looked wrong. Twenty-one were added: the solid weight, the three missing double chevrons and cf-converge, and the objects and instruments the plate draws and the set did not — globe, cut sphere, coin, triangle, wedge, house, overlap, signal, expand.

Two glyphs in the set are not on the plate and are deliberate: cf-plus and cf-minus. An accordion needs them, they are 90° axes and nothing else, and inventing them is cheaper than borrowing a foreign icon set for two marks. Everything else here is drawn from the plate.

Two weights

The plate's first two rows are the same nine marks twice — once solid, once drawn. That is not a style choice to pick between: they do different jobs. The line weight is the working set, and it is what an interface uses at 16 px and up. The solid weight is the mark at label scale, where a 1 px contour inside a 12 px glyph stops resolving and a drawn rhombus turns into a grey smudge.

The solid marks are not redrawn — they are one construction: the isometric rhombus with a rhombus notch cut out of one of its four vertices. Cut the bottom vertex and the rhombus becomes a chevron pointing up; cut the left one and it points right. The ends stay pointed because they are the rhombus's own vertices, which is exactly what the plate draws and what a stroked-and-capped band could not give you.

line · a contour, 1 px at every size
solid · the rhombus, notched
both at 16 px — where the second weight earns its place
The holes are cut by fill-rule, not painted. cf-ring-solid and cf-diamond-nested-solid have a hole in the middle, and the obvious way to get one — a second shape in the page colour — does not work here: the page is a vertical wash from CF-Grau to white, so a patch matching it at one scroll position matches nothing at any other. Both are a single path with two subpaths and fill-rule="evenodd", so the hole is genuinely a hole and whatever is behind the icon shows through it.

Construction

Every glyph is drawn in a 24 × 24 box with a 2 px margin, so the live area is 20 × 20. Inside it sit three keylines, and an icon is built on one of them: the isometric rhombus (20 × 10), the isometric circle — an ellipse at 2:1 — and the upright square (18 × 18, inset because a square reads heavier than a rhombus of the same width). Diagonals use only 26.57°, 63.43°, 45° and 90°. A 26.57° line rotated by 90° is a 63.43° line, which is why the four chevrons are one drawing turned four times rather than four drawings.

ElementValue
Box24 × 24
Margin2 — nothing crosses it
Live area20 × 20
Rhombus keyline20 × 10 (2:1)
Circle keylinerx 10 / ry 5 (2:1)
Square keyline18 × 18, optically inset
Angles26.57° · 63.43° · 45° · 90°
Stroke1 px, non-scaling-stroke
Caps / joinssquare / miter
Why the stroke never scales. The contour is 1 px at 16 px and still 1 px at 80 px, because vector-effect="non-scaling-stroke" is set on every shape in the sprite. This is the same rule the process illustrations follow — a contour that thickens with the artwork stops being a contour and becomes a shape.

Sizes

Four sizes on the 4 px unit. 16 px is the floor: below it the counters inside the isometric objects close up and the glyph turns into a smudge. Use the object icons at 40 px and above; the direction and operator glyphs work at any size.

16 · --sm
24 · default
40 · --lg
80 · --xl
80 · --bold (2 px)

The light layer

One icon per screen may stop being a line and become a source. .cf-icon--light switches the contour to lime and lets it glow — the Licht-Ebene applied to a glyph, a temporary effect rather than a fill.

Dark surfaces only, and decorative only. Lime is 18.5:1 on black and 1.4:1 on CF-Grau. A lit icon on the page surface is invisible to a good many people and fails the 3:1 minimum for UI contours, so it must never be the only thing carrying a meaning — always a black contour, or a lit one next to a label.
An icon may be lit; a letter may not. The system forbids lime letterforms on a dark surface — lime is light, not ink — and this is the other side of that line rather than an exception to it. A contour is a place light lands in the composition; a glyph is something the reader has to resolve, and a saturated near-white edge blooms exactly where the eye is trying to read. So the light layer stays on icons, caps, rings and edges, and the label beside the lit icon is white.
Why a glow and not a gradient. The obvious move is to stroke the contour with --gradient-light. It cannot be done through a sprite: a paint server referenced from inside a <use> shadow tree resolves inconsistently across engines — the stroke computes to url(#…) and then paints nothing at all. An icon that silently disappears in one browser is worse than one that never promised the gradient, so the light layer here is lime plus --glow-lime. If a single hero-scale glyph genuinely needs the gradient, inline that one symbol instead of referencing it.

In use

An icon sits next to a label, or it carries an accessible name of its own. It never floats without either.

Werk Ludwigshafen
  • Sensordaten aus der Anlage
  • Instandhaltungshistorie
  • Betriebsparameter — laufend
<!-- next to a label: the icon is decoration, hide it -->
<span class="icon-inline">
  <svg class="cf-icon cf-icon--sm" aria-hidden="true"><use href="#cf-pin"></use></svg>
  <span>Werk Ludwigshafen</span>
</span>

<!-- alone: the name goes on the control, not on the svg -->
<button type="button" aria-label="Dialog schließen">
  <svg class="cf-icon" aria-hidden="true"><use href="#cf-close"></use></svg>
</button>

The sprite

One file defines the set: assets/js/cf-icons.js. Unlike docs.js it ships. Include it once per page and it injects the sprite after <body>, or paste the block below into the page template and drop the script.

<script src="/design-system/assets/js/cf-icons.js"></script>

Its markup, generated from the same array the gallery above reads — there is no second copy of any glyph anywhere in the system:


  

Anatomy

ClassEffectWhen
.cf-icon24 px box, 1 px currentColor contour, no fillalways
.cf-icon--sm16 pxinline with 14 px body copy, inside buttons
.cf-icon--md24 pxthe default; explicit when it sits next to a modifier
.cf-icon--lg40 pxlist markers, card headers, the object glyphs
.cf-icon--xl80 pxsection openers, empty states
.cf-icon--bold2 px contourlarge format, or a surface too busy for 1 px
.cf-icon--lightlime contour + glowone per screen, dark surfaces, decorative
.cf-icon--motion+4 px on the parent's hover or :focus-visibleonly inside a link or button

Drawing a new one

The set is meant to grow, and it grows in one place: the ICONS array in assets/js/cf-icons.js. An entry records the id, a label, what the glyph is for, and the keyline it was built on — that last field is not bookkeeping, it is the constraint. If a new glyph cannot name the keyline it stands on, it does not belong to this system yet.

{ id: 'cf-cube', label: 'Cube', use: 'An asset, a machine, one unit of anything',
  keyline: 'rhombus 16 x 8 + 8 px extrusion',
  shapes: '<path d="M12 4 L20 8 L12 12 L4 8 Z"/>…' }

Write the shapes without stroke or size attributes — those come from .cf-icon. The build step that would normally add vector-effect to every shape is four lines of JavaScript in the same file, so a new glyph inherits the 1 px rule for free.

Rules

Do

  • Draw on a keyline. Rhombus, ellipse or square — name it in the entry.
  • Keep to the four angles. A rotation of a sanctioned angle is sanctioned.
  • Contour before fill. The only solid marks in the set are dots.
  • Hide decorative icons with aria-hidden="true" and name the control instead.
  • One weight per context — do not mix 1 px and 2 px in the same row.

Don't

  • No third-party icon set, ever. If it is not in the array, it is not drawn yet.
  • No rounded caps, no rounded joins, no corner radii.
  • No perspective and no true 30° isometry — this system is 2:1, at 26.57°.
  • No lit icon on CF-Grau, and never a lit icon carrying meaning on its own.
  • No icon inside a button next to the CF arrow — one mark per control.