Component reference
A living reference of every visual pattern on this site. All examples below are rendered live — if something looks wrong here, it looks wrong everywhere.
A living reference of every visual pattern on this site. All examples below are rendered live — if something looks wrong here, it looks wrong everywhere.
Design tokens defined as CSS custom properties on the body. The site uses a warm paper background (#fbf6ef) with dark text (#222) and blue accents.
#fbf6ef
#222
--kh-color--grey--darkest
--kh-color--grey
--kh-color--blue
--kh-color--blue--dark
#734595
--kh-color--orange
#ffb81c
#fafafa
#d0d0ce
#fff
All type is set in Recursive, a variable font with axes for weight, monospace, casual, slant, and cursive. Base size is 16px with 1.7 line height.
<h1 class="kh-text-heading--1">Heading 1 — 42px / 700 weight</h1>
<h2 class="kh-text-heading--2">Heading 2 — 30px / 500 weight</h2>
<h3 class="kh-text-heading--3">Heading 3 — 27px / 500 weight</h3>
.kh-content)#Inside .kh-content, bare heading tags inherit proportional sizing:
<div class="kh-content">
<h1>Content H1 — 42px</h1>
<h2>Content H2 — 30px</h2>
<h3>Content H3 — 27px</h3>
<h4>Content H4 — 21px</h4>
<h5>Content H5 — 19px</h5>
</div>
<p class="kh-text-body--1">Body 1 — 32px, weight 500. Used for post teasers and lead text.</p>
<p class="kh-text-body--3">Body 3 — 16px, weight 500. Used for metadata and supporting text in dark grey (#373a36).</p>
Body 1 — 32px, weight 500. Used for post teasers and lead text.
Body 3 — 16px, weight 500. Used for metadata and supporting text in dark grey (#373a36).
<p>Regular paragraph text at 16px with 1.7 line height.</p>
<p><em>Italic text uses font-variation-settings for a slanted casual style.</em></p>
<p><strong>Bold text for emphasis.</strong></p>
<p><small>Small text — 13px, used for dates and fine print.</small></p>
<p>Text with <code>inline code</code> rendered in monospace Recursive.</p>
<p>An <abbr title="Abbreviation with tooltip">ABBR</abbr> gets a dotted underline and help cursor.</p>
Regular paragraph text at 16px with 1.7 line height.
Italic text uses font-variation-settings for a slanted casual style.
Bold text for emphasis.
Small text — 13px, used for dates and fine print.
Text with inline code rendered in monospace Recursive.
An ABBR gets a dotted underline and help cursor.
The button has a distinctive 3D shadow effect that animates on hover (shifts 4px) and active (shifts 8px, shadow collapses).
<a href="#buttons" class="kh-button">Default button</a>
<a href="#buttons" class="kh-button kh-button--sm">Small button</a>
The shadow uses --kh-button-shadow-background-color (defaults to blue-dark). Border color is --kh-button-border-color (defaults to blue). These can be overridden via CSS custom properties.
<span class="kh-badge">Badge</span>
<span class="kh-badge">UPPERCASE</span>
Pill-shaped categorization chips used for topics and tags:
<span class="kh-label">web development</span>
<span class="kh-label">design systems</span>
<span class="kh-label">Eleventy</span>
<span class="kh-label">performance</span>
Orange-bordered callout boxes for asides, updates, and contextual information. The text uses a casual variant of Recursive with a slight slant.
<aside class="kh-note-box">
<span class="kh-note-box__label">Update</span>
This pattern was revised in September 2025 to use the casual axis of Recursive for a more handwritten feel.
</aside>
<aside class="kh-note-box">
<span class="kh-note-box__label">Context</span>
The label uses a bold monospace casual variant. Keep labels short: "Update", "Sidebar", "Related", "Context".
</aside>
General-purpose container with a bottom border accent. Themeable via --kh-box-theme-color--background and --kh-box-theme-color--foreground.
<div class="kh-box">
<p>A content box with default styling — light background, 4px solid bottom border, and 1rem padding.</p>
<p>Links inside <code>.kh-box__text</code> inherit the current color.</p>
</div>
A content box with default styling — light background, 4px solid bottom border, and 1rem padding.
Links inside .kh-box__text inherit the current color.
Inside .kh-content, bare blockquotes get a white background, subtle shadow, rounded corners, and a left border accent:
<div class="kh-content">
<blockquote>
<p>The best way to predict the future is to invent it. Well-structured content is the foundation of every good digital experience.</p>
</blockquote>
</div>
The best way to predict the future is to invent it. Well-structured content is the foundation of every good digital experience.
A styled blockquote with a yellow left border, opening quote mark, and a hand-drawn highlighter effect behind the text:
<blockquote class="kh-quote--featured">
<p>The work you're most proud of is rarely the flashiest — it's the system that quietly keeps working long after you've moved on.</p>
</blockquote>
The work you're most proud of is rarely the flashiest — it's the system that quietly keeps working long after you've moved on.
Inline code uses monospace Recursive with a white background and slight padding.
Fenced code blocks inside .kh-content get a white background, rounded corners, and a subtle shadow:
.kh-button {
appearance: none;
background-color: #fafafa;
border: 4px solid var(--kh-color--blue);
border-radius: 4px;
box-shadow: 8px 8px 0 var(--kh-color--blue--dark);
transition: all linear 125ms;
}
<aside class="kh-note-box">
<span class="kh-note-box__label">Note</span>
Content goes here.
</aside>
Code blocks use pre-wrap for wrapping and overflow: auto for horizontal scroll when needed.
<figure class="kh-figure">
<img class="kh-figure__image" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='300' fill='%23d0d0ce'%3E%3Crect width='600' height='300'/%3E%3Ctext x='50%25' y='50%25' dominant-baseline='middle' text-anchor='middle' fill='%23707372' font-family='system-ui' font-size='18'%3E600 × 300 placeholder%3C/text%3E%3C/svg%3E" alt="Placeholder image demonstrating the figure component">
<figcaption class="kh-figure__caption">Caption text — used for attribution and context. Grey (#373a36), weight 500.</figcaption>
</figure>
.kh-content)#Bare figure tags inside .kh-content use display: table with bottom-aligned captions:
<div class="kh-content">
<figure>
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='200' fill='%23d0d0ce'%3E%3Crect width='400' height='200'/%3E%3Ctext x='50%25' y='50%25' dominant-baseline='middle' text-anchor='middle' fill='%23707372' font-family='system-ui' font-size='16'%3E400 × 200%3C/text%3E%3C/svg%3E" alt="Placeholder image">
<figcaption>A plain figure caption in grey (#54585a).</figcaption>
</figure>
</div>
The .kh-bleed-out utility makes images break out of their container on larger screens (30% on medium, 50% on large):
<img class="kh-bleed-out" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='300' fill='%23d0d0ce'%3E%3Crect width='900' height='300'/%3E%3Ctext x='50%25' y='50%25' dominant-baseline='middle' text-anchor='middle' fill='%23707372' font-family='system-ui' font-size='18'%3EBleed-out image (wider on large screens)%3C/text%3E%3C/svg%3E" alt="Demonstration of bleed-out image effect">
Inside .kh-content, bare tables get alternating row striping with a grey header row:
<div class="kh-content">
<table>
<thead>
<tr>
<th scope="col">Property</th>
<th scope="col">Value</th>
<th scope="col">Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Background</td>
<td><code>#fafafa</code></td>
<td>Light surface color</td>
</tr>
<tr>
<td>Header bg</td>
<td><code>#d0d0ce</code></td>
<td>Warm grey</td>
</tr>
<tr>
<td>Even rows</td>
<td><code>#d8d8d8</code></td>
<td>Alternating stripe</td>
</tr>
<tr>
<td>Cell padding</td>
<td><code>8px 16px</code></td>
<td>Comfortable reading</td>
</tr>
</tbody>
</table>
</div>
| Property | Value | Notes |
|---|---|---|
| Background | #fafafa |
Light surface color |
| Header bg | #d0d0ce |
Warm grey |
| Even rows | #d8d8d8 |
Alternating stripe |
| Cell padding | 8px 16px |
Comfortable reading |
Form elements used for the site search. The search input has a custom SVG cancel button on WebKit browsers.
<div class="kh-form__item">
<label class="kh-form__label" for="demo-search">Search</label>
<input type="search" id="demo-search" placeholder="Search my site" class="kh-form__input">
</div>
<a href="#forms" class="kh-button">Search</a>
Used on the blog index and work pages to display post previews.
<article class="kh-summary">
<div class="kh-summary__date">7 Feb 2026</div>
<h3 class="kh-summary__title">
<a href="#summary-cards" class="kh-summary__link">Example post title with balanced text wrapping</a>
</h3>
<p class="kh-summary__text">A one-sentence teaser that summarizes the post content and entices the reader to click through.</p>
</article>
A one-sentence teaser that summarizes the post content and entices the reader to click through.
A more compact variant with date on its own row and two-column layout on wider screens:
<article class="kh-summary kh-summary--news">
<div class="kh-summary__date">7 Feb 2026</div>
<h3 class="kh-summary__title">
<a href="#summary-cards" class="kh-summary__link">News-style summary with tighter spacing</a>
</h3>
<p class="kh-summary__text">Used on the blog index. Grid layout stacks on mobile, goes side-by-side on screens wider than 600px.</p>
</article>
Used on the blog index. Grid layout stacks on mobile, goes side-by-side on screens wider than 600px.
Summaries can include a thumbnail image that snaps to the right column on medium+ screens:
<article class="kh-summary kh-summary--news">
<div class="kh-summary__date">7 Feb 2026<span class="kh-summary__author">Filed in: design systems, performance</span></div>
<h3 class="kh-summary__title">
<a href="#summary-cards" class="kh-summary__link">Post with a thumbnail image</a>
</h3>
<a href="#summary-cards" class="kh-summary__image">
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='147' fill='%23d0d0ce'%3E%3Crect width='220' height='147'/%3E%3Ctext x='50%25' y='50%25' dominant-baseline='middle' text-anchor='middle' fill='%23707372' font-family='system-ui' font-size='14'%3E220×147%3C/text%3E%3C/svg%3E" alt="Example thumbnail">
</a>
<p class="kh-summary__text">The image uses a 3:2 aspect ratio with object-fit cover. Constrained to 220px wide.</p>
</article>
The image uses a 3:2 aspect ratio with object-fit cover. Constrained to 220px wide.
Used on the CV page to display key impact numbers. Cards have a subtle hover lift effect.
<div class="kh-metrics-grid">
<div class="kh-metric">
<span class="kh-metric__number">20+</span>
<span class="kh-metric__label">YEARS EXPERIENCE</span>
</div>
<div class="kh-metric">
<span class="kh-metric__number">0.45s</span>
<span class="kh-metric__label">PAGE LOAD TIME</span>
</div>
<div class="kh-metric">
<span class="kh-metric__number">3 weeks</span>
<span class="kh-metric__label">EDITORIAL TIME SAVED / MONTH</span>
</div>
</div>
A timeline-style list for career milestones, with bold labels and bottom borders:
<div class="kh-career-snapshot">
<ul class="kh-snapshot-list">
<li><strong>2023 – present</strong> Platform Architect at UNDRR</li>
<li><strong>2018 – 2023</strong> Web Design Architect at EMBL</li>
<li><strong>2015 – 2018</strong> Lead Developer at EMBL-EBI</li>
</ul>
</div>
| Token | Value | Usage |
|---|---|---|
$kh-breakpoint--sm |
600px | Small screens up |
$kh-breakpoint--md |
846px | Medium screens up |
$kh-breakpoint--lg |
1024px | Large screens up |
$kh-breakpoint--xl |
1300px | Extra large |
$kh-breakpoint--sm-down |
599px | Below small |
$kh-breakpoint--md-down |
845px | Below medium |
$kh-breakpoint--lg-down |
1023px | Below large |
.kh-grid)#The base grid uses CSS Grid with auto-flow columns. Children reset their margin and max-width.
<div class="kh-grid" style="--kh-page-grid-gap: 1rem;">
<div style="background: #d0d0ce; padding: 1rem; border-radius: 4px;">Column 1</div>
<div style="background: #d0d0ce; padding: 1rem; border-radius: 4px;">Column 2</div>
<div style="background: #d0d0ce; padding: 1rem; border-radius: 4px;">Column 3</div>
</div>
.kh-grid__col-3)#Explicit three-column layout. Collapses to single column below 846px. Use .kh-grid__col--span-1 and .kh-grid__col--span-2 for asymmetric layouts:
<div class="kh-grid kh-grid__col-3" style="--kh-page-grid-gap: 1rem;">
<div class="kh-grid__col--span-1" style="background: #d0d0ce; padding: 1rem; border-radius: 4px;">Span 1</div>
<div class="kh-grid__col--span-2" style="background: #ffb81c; padding: 1rem; border-radius: 4px;">Span 2 (wider)</div>
</div>
.kh-grid-stylized)#The signature layout pattern: a left gutter (16rem on desktop) with main content to the right. Used for most page sections. This page uses it for every section.
<div class="kh-grid-stylized" style="border: 2px dashed #d0d0ce; padding: 1rem;">
<div style="background: #d0d0ce; padding: 1rem; border-radius: 4px; text-align: center;">← Gutter (16rem)</div>
<div style="background: #ffb81c; padding: 1rem; border-radius: 4px;">Main content area</div>
</div>
.kh-stack)#Vertical rhythm utility. Adds 1rem margin between sibling children. Use .kh-stack--800 for 2rem spacing:
<div class="kh-stack" style="border: 2px dashed #d0d0ce; padding: 1rem;">
<div style="background: #d0d0ce; padding: 1rem; border-radius: 4px;">Item 1</div>
<div style="background: #d0d0ce; padding: 1rem; border-radius: 4px;">Item 2 (1rem gap)</div>
<div style="background: #d0d0ce; padding: 1rem; border-radius: 4px;">Item 3 (1rem gap)</div>
</div>
.kh-cluster)#Horizontal flex layout with wrapping and center alignment. Used for navigation and grouped elements:
<div class="kh-cluster">
<span class="kh-label">Item 1</span>
<span class="kh-label">Item 2</span>
<span class="kh-label">Item 3</span>
<span class="kh-label">Item 4</span>
<span class="kh-label">Item 5</span>
</div>
.kh-u-fullbleed)#Makes a section's background extend to the full viewport width while keeping content constrained. Used for the post title bar and footer:
<div class="kh-u-fullbleed kh-u-background-color--yellow--dark" style="padding: 2rem 0;">
<p style="max-width: 70ch;"><strong>Full bleed section.</strong> The yellow background extends edge-to-edge while the text stays within the content width.</p>
</div>
Full bleed section. The yellow background extends edge-to-edge while the text stays within the content width.
Utility classes for margin and padding. The naming follows a sizing scale.
| Class | Property | Value |
|---|---|---|
.kh-u-margin__bottom--200 |
margin-bottom | 0.5rem |
.kh-u-margin__bottom--600 |
margin-bottom | 1.5rem |
.kh-u-margin__top--1200 |
margin-top | 3rem |
.kh-u-padding__bottom--200 |
padding-bottom | 0.75rem |
.kh-u-padding__bottom--400 |
padding-bottom | 1rem |
.kh-u-padding__top--500 |
padding-top | 1.5rem |
.kh-u-padding__top--600 |
padding-top | 2rem |
.kh-u-padding__top--800 |
padding-top | 3rem |
The .kh-content class constrains content to max-width: 70ch for readable line lengths. Add .kh-content--wide to remove the constraint.
Recursive exposes five variable axes. These helper classes apply preset combinations:
<p class="kh-font-headline" style="font-size: 32px;">Headline style — weight 800, casual 1, mono 0</p>
<p class="kh-font-code">Code style — mono 1, casual 0, no slant, no cursive</p>
<p class="kh-logo" style="font-size: 20px;">Logo style — weight 800, mono 1, casual 0</p>
Headline style — weight 800, casual 1, mono 0
Code style — mono 1, casual 0, no slant, no cursive
Logo style — weight 800, mono 1, casual 0
Extra-large headings using .kh-font-headline--display. When two display headlines are adjacent, the first becomes 80px with a light weight:
<h2 class="kh-font-headline kh-font-headline--display">Display headline — 60px</h2>
| Axis | Code | Range | Default | Usage |
|---|---|---|---|---|
| Weight | wght |
300–800 | 400 | Light to extra-bold |
| Monospace | MONO |
0–1 | 0 | Proportional to monospace |
| Casual | CASL |
0–1 | 0 | Formal to hand-drawn |
| Slant | slnt |
-15–0 | 0 | Upright to italic |
| Cursive | CRSV |
0–1 | 0.5 | Controls cursive letterforms |
The .kh-video wrapper provides a responsive 16:9 container. Iframes, objects, and embeds are positioned absolutely to fill the container:
<div class="kh-video">
<div style="position:absolute;top:0;left:0;width:100%;height:100%;background:#d0d0ce;display:flex;align-items:center;justify-content:center;color:#707372;font-size:18px;">16:9 video placeholder</div>
</div>
A hidden link that becomes visible on focus, allowing keyboard users to skip to main content:
<a href="#main-content" class="kh-u-sr-only kh-skip-link">Skip to main content</a>
Tab to the top of this page to see it in action.
The .kh-u-sr-only class visually hides content while keeping it accessible to screen readers:
<h2 class="kh-u-sr-only">Section title visible only to screen readers</h2>
All interactive elements get a 1px dashed outline with 4px offset on focus. This applies to:
.kh-contentkh-* classThe site's CSS can be toggled off via a checkbox in the footer (#kh-css-toggle). All custom styles are scoped under body:has(#kh-css-toggle:checked), so unchecking it reveals the bare HTML structure — useful for testing structural accessibility.
Animations (the dappled-light ambience effect and venetian blind sway) are gated behind @media (prefers-reduced-motion: no-preference) and disabled by default.
The ambient background effects are disabled entirely under @media (prefers-contrast: high).
| Class | Behavior |
|---|---|
.kh-u-show-for-mobile-only |
Visible below 600px, hidden above |
.kh-u-show-for-medium-up |
Visible 846px and up |
.kh-u-show-for-medium-only |
Visible 846px – 1023px only |
.kh-u-show-for-large |
Visible 1024px and up |
.kh-u-show-for-print-only |
Hidden on screen, visible when printed |
.kh-u-do-not-print |
Visible on screen, hidden when printed |
.kh-u-sr-only |
Visually hidden, accessible to screen readers |
| Class | Effect |
|---|---|
.kh-u-text--nowrap |
Prevents text from wrapping |
.kh-u-text-color--grey |
Sets text color to #707372 |
| Class | Effect |
|---|---|
.kh-u-background-color--yellow--dark |
Background #ffb81c |
The .kh-link class provides blue link styling with purple visited state, independent of .kh-content context:
<a href="/example" class="kh-link">Styled link</a>
| Class | Purpose |
|---|---|
.kh-navigation |
Navigation wrapper, pushed to right with margin-left: auto |
.kh-navigation__list |
Flex list with gap spacing, no bullets |
.kh-navigation__item |
Inline-flex list item |
.kh-navigation__link |
Link with no underline, underlines on hover |
.kh-navigation__link--active |
Bold weight for current page |
Links in .kh-content lose their decoration on print. Elements with .kh-u-do-not-print are hidden. The .ken-link--print class shows the href URL below the link text.
All custom properties are scoped to body:has(#kh-css-toggle:checked):
| Property | Default |
|---|---|
--kh-color--grey |
#707372 |
--kh-color--grey--darkest |
#373a36 |
--kh-color--blue |
#3b6fb6 |
--kh-color--blue--dark |
#193f90 |
--kh-color--orange |
#f49e17 |
| Property | Default | Notes |
|---|---|---|
--kh-body-width |
81.25em |
Max page width |
--kh-page-grid-gap |
1rem / 2rem |
Grid gap (responsive) |
--kh-grid-stylized-module--prime |
16rem |
Left gutter width |
| Property | Default | Notes |
|---|---|---|
--kh-stack-margin |
1rem |
Vertical stack gap |
--kh-text-margin--bottom |
16px |
Text element bottom margin |
--kh-box-padding |
1rem |
Box component padding |
--kh-cluster-margin |
0.5rem |
Cluster item spacing |
| Property | Purpose |
|---|---|
--kh-box-theme-color--background |
Box background override |
--kh-box-theme-color--foreground |
Box text color override |
--kh-button-background-color |
Button background |
--kh-button-border-color |
Button border |
--kh-button-shadow-background-color |
Button shadow |
Printed direct from AllAboutKen.com