← Back
Design System · Blog Post Guidelines

Blog Post
Guidelines

v 1.0 Required template Blog Long-form writing WCAG AA / AAA
§01 The Mandate

Every new blog post uses the same template.

Any page added to the Blog section must be built from Blog Post Template. It is the canonical layout for long-form writing on the portfolio: the only shape posts take, the only component vocabulary they use, and the source of every typographic and color decision a reader sees. Project pages (My Apps and Projects) follow a different template — see Case Study Guidelines.

Open the Blog Post Template /Design-System/new-post-template.html

Why a dedicated post template

Blog posts and case studies look similar at a glance — same site, same color palette, same dark hero strip — but read very differently. A case study sells the work; a blog post sells an idea. The post template is organised around skimmer-first ordering (TL;DR + table of contents above the body), an author byline instead of a project credits list, and article-style body sections (Background → The idea → How it works → Trade-offs → Closing) in place of case-study phases (challenge → process → outcomes). Same CSS classes; different scaffolding.

§02 Folder Structure

Where new posts live.

All long-form posts live under /blog/. Assets — featured images, diagrams, screenshots — go in portfolio-assets/blog/<PostSlug>/.

/blog/<Post-Slug>.html

Examples already in the portfolio: blog/Improving-on-Developing-Workflows.html, blog/Designing-for-Outcomes.html. Breadcrumb starts with Blog ›; sidebar's "Blog" item is marked active. Slug uses Title-Case-Kebab — easier to read in the URL bar than all-lowercase, and consistent with the two existing posts.

/portfolio-assets/blog/<PostSlug>/

Every post that ships with visuals gets its own asset folder. PascalCase for the folder name. Reference assets via ../portfolio-assets/blog/<PostSlug>/<file> from the post HTML. Text-only posts can skip the folder entirely.

Home-page preview

Every published post must have a .blog-preview-cell in index.html's Blog section. The grid is two cells wide at desktop — reuse the existing markup and update the title, tags, excerpt, date, and reading time.

§03 Workflow

From template to published post in six steps.

  1. Copy Design-System/new-post-template.html into /blog/ and rename it to <Post-Slug>.html. Slug uses Title-Case-Kebab and matches the URL (e.g. blog/On-The-Cost-Of-Components.html).
  2. Add the sidebar. The template ships without one. Copy <aside class="sidebar"> from any existing post (e.g. blog/Designing-for-Outcomes.html) and keep the .active flag on the Blog nav item.
  3. Update the top bar. Both the Back button's href and the breadcrumb link should point at ../index.html#blog. The breadcrumb's current page text becomes the post's title.
  4. Drop assets into /portfolio-assets/blog/<PostSlug>/. Replace every image-placeholder block in the template with a real <img> or delete the section if the post is text-only. Optimize to ≤ 500 KB per image before committing.
  5. Write the TL;DR first. The 3-5 bullet TL;DR block is the page's most-read element — write it before the body so it sets the spine of the argument. Every body section should map back to one of those bullets.
  6. Wire the home page. Add a .blog-preview-cell to the .blog-grid in index.html's Blog section, with tags, excerpt, date, reading time, and a link to the new post. Update the previous post's footer "Next →" to point at the new post so the reading flow stays circular.
§04 Required & Optional Sections

What every blog post must contain.

Required sections form the spine of every post. Optional sections are tools for depth on individual pieces. The order in new-post-template.html is the recommended ordering — reorder freely, but don't drop a required section.

01Top bar (Back + breadcrumbs)Required
02Hero — category, title, dek, byline metaRequired
03TL;DR / Key takeawaysRequired
04Table of contentsOptional
05Hero imageOptional
06BackgroundRequired
07Body §01 — The ideaRequired
08Pull-quote (mid-article)Optional
09Body §02 — How it works (feature-list)Required
10Image with captionOptional
11Body §03 — Trade-offsRequired
12Two-up comparisonOptional
13Key insight (decision-block)Optional
14External quote / testimonialOptional
15Closing thoughtsRequired
16Reflection pull-quoteOptional
17Further readingOptional
18CTA rowRequired
19Footer — Up next postRequired
§05 Component Vocabulary

Reuse, don't reinvent.

Posts are assembled from the same component vocabulary used by case studies — same CSS, repurposed for article content. If a layout you need isn't in the list below, add it to the design system first (in project.css or components.css) — then use it. Don't ship one-off inline styles.

Layout primitives — project.css

.project-page.full-width · .project-topbar · .cs-overview · .cs-overview-head · .project-image · .project-section · .project-cta-row · .project-footer. (The .cs-overview-image square-image slot is typically omitted on posts — the hero leads with category + title + dek.)

Article body — project.css

.project-body for prose paragraphs. H2 section headings use .section-h; numbered eyebrow labels above each H2 use .section-eyebrow (e.g. "01 · Background"). For numbered step-by-step explanations inside a body section, use .feature-list + .feature-item (01/02/03 numbered list).

Image layouts — project.css

.image-with-caption for single mid-article visuals · .layout-two-up for side-by-side comparisons · .layout-three-up for option-set illustrations · .image-text-split for 50/50 prose + image. Avoid .layout-asymmetric in posts — it's a case-study showcase device.

Highlight blocks — project.css

.project-callout (mid-article pull-quote and closing reflection — white italic on Taupe) · .decision-block (pale-peach surface — repurposed for the TL;DR block and any mid-article "Key insight") · .testimonial-block (external quote with attribution). Two pull-quotes per post is the ceiling — more and they stop feeling intentional.

Hero meta — reuses home.css and components.css

Byline meta line reuses .blog-cell-meta for a small inline "Date · Reading time · Author" row. Tag chips reuse .sidebar-tag (the same chip style used in the sidebar and on home-page .blog-preview-cell cards). Avoid .overview-stats + .stat cards in the post hero — they read as project outcomes, not article metadata.

Table of contents — uses .credits-list

The two-column .credits-list + .credits-row pattern doubles as the table of contents and the "Further reading" list. Left column: section number (01, 02, …) or link type (Related post, Article, Talk, Tool). Right column: link to the anchor or external URL. Anchor IDs on each body section (#background, #the-idea, #how-it-works, etc.) must match the TOC hrefs.

Buttons — components.css

Blog-post CTAs are softer than case-study CTAs. Default to .btn.btn-outline.btn-taupe.btn-md for the single CTA ("Reply with your take", "Book a 20-min call"). Reserve .btn-solid for case studies — a blog post asks for engagement, not a click-through to a product.

§06 Accessibility

Contrast and color rules.

Same rules as the rest of the portfolio — WCAG AA across the board, AAA on body text. The shortcut: Black for prose, Taupe only for labels, rails, and decorative chrome. Full matrix lives in Colors §03.

Body text = Black

Every .project-body paragraph, every .decision-text, every list item, every caption uses --text-primary (#000000). AAA contrast on White, Sand, and Peach. No exceptions for blog body copy — readability is the whole game.

Reading time is honesty, not decoration

Estimate honestly: 220–250 words per minute for adult readers, less for posts with diagrams that demand inspection. A 1,500-word post with three diagrams is 8 min read, not 6. Misjudged reading times train readers to ignore them.

Tag chips are content, not decoration

Tag chips in the hero must match the tags on the home page .blog-preview-cell and the post category for search. Three tags is the recommended count — one general topic (Design Systems), one specific topic (Tokens), one project or industry anchor (Numerade). Anything more and they read as keyword stuffing.

Image alt text is required

Every <img> needs an alt attribute that describes the content meaningfully — not "diagram" or "screenshot". Decorative-only .image-placeholder blocks can use aria-hidden="true" instead.

§07 Writing Conventions

House style for the blog.

Title — one promise, eight words or fewer

Titles name the specific takeaway the reader will get. "Improving on Developing Workflows" → readers know exactly what the post is about before they click. Avoid clever-but-vague titles ("On craft", "Some thoughts on systems") — they don't earn the scroll.

Dek — two sentences, ends in the promise

The .overview-desc paragraph under the title is the elevator pitch. First sentence: what the post is about. Second sentence: the angle that makes this post worth reading vs. the dozen others on the same topic. End with the promise.

TL;DR — 3-5 bullets, each starts with a verb

The .decision-block at the top of the body is the single most-read element on the page. Many readers will bounce after reading just this. Each bullet starts with a strong verb ("Build", "Choose", "Avoid", "Measure"). Include a counter-bullet — the trade-off or "but" — to keep the take honest.

H2 sections — number them

Each .section-eyebrow above an H2 carries the section number (e.g. "01 · Background", "02 · The idea"). Anchors on each section (id="background", id="the-idea") match the table-of-contents hrefs. Sub-sections inside an H2 use H3 — keep H3 styling consistent with the inline pattern already in new-post-template.html.

Pull-quotes — at most two, the second is the closer

Use .project-callout sparingly. One mid-article quote to break scanning rhythm; one closing quote — the "screenshot-worthy" line you'd want shared on social. More than two and they stop carrying weight.

Trade-offs section is non-negotiable

Every post must include a Trade-offs / nuance section. Posts that only sell an approach read as marketing; posts that name what the approach gives up read as honest. Lead the section with the limitation up front: "this falls apart on teams of more than thirty", "we paid for this speed with weeks of churn six months later."

Closing — hand the reader the next move

Don't restate the TL;DR. The reader has it. The closing section gives them a question, an experiment to try in their own work, or the related thread you didn't pull. Optional second paragraph: a personal note or the contradiction with how you used to think about this.

§08 Naming & Assets

Conventions that keep the blog navigable.

HTML files — Title-Case-Kebab

blog/Improving-on-Developing-Workflows.html, blog/Designing-for-Outcomes.html. Words capitalised, joined by hyphens, no underscores. Easier to read in a URL bar than all-lowercase; matches the two existing posts.

Asset folders — PascalCase, post-slug match

portfolio-assets/blog/ImprovingOnDevelopingWorkflows/, portfolio-assets/blog/DesigningForOutcomes/. The folder name strips the hyphens from the file slug. Matches the case-study convention used in portfolio-assets/projects/<ProjectName>/.

Asset file names — descriptive, prefix-first

<PostSlug>-Hero.png, <PostSlug>-TokenDiagram.png, <PostSlug>-BeforeAfter.png. Slug prefix first so files sort together in image previews.

Image weight budget — ≤ 500 KB per file

Re-export to WebP or JPEG at ~1600 px wide before committing. The portfolio has already learned this the hard way — diagrams and token-map illustrations that ship at 4 MB punish anyone reading on cellular.

§09 Usage Rules
Build from the template

Copy Design-System/new-post-template.html for every new blog post. Don't start from a blank file or from an existing post — the template is the source of truth.

Use the vocabulary

Layouts and highlight blocks come from project.css, home.css, and components.css. Don't introduce one-off inline styles for spacing, color, or layout — extend the system instead.

Required sections in

Topbar, hero, TL;DR, background, body §01 (idea), body §02 (how it works), body §03 (trade-offs), closing, CTA, footer. Always present, in roughly that order. Optional sections can be added or dropped per post.

A
Black for prose

All body, heading, and caption text uses Black for AAA contrast on every background in the palette. Taupe is reserved for labels, rails, button outlines, and dividers. See Colors for the matrix.

Wire the home page

A new post isn't shipped until it has a .blog-preview-cell on index.html's Blog grid, with the title, tags, excerpt, date, and reading time matching the post hero. The excerpt is usually the dek, lightly trimmed.

Wire the footer

The post footer's Next → button links to the next post (or back to the first post for a circular flow). Updating the previous post's footer to point at the new one is part of shipping — not an afterthought.

Design System

Now go write a post.

Open the template, copy it into /blog/, follow the workflow, and ship. The system handles the rest.

Open the Template