17 Apr 2020

You're designing for the web wrong: Part 1

This is my method for executing big hairy data led layouts using only a html template and one swift file. If GitHub is your thing, the files and this post are there also.

Todays web design process goes something like this:

  1. Draw/concieve a layout
  2. Execute this in Sketch/Illustrator/Affinity
  3. Publish to a Zeplin/Adobe XD
  4. Developer ignores majority of finesse and builds what they see. This is natural.
  5. Rounds of iteration between designer and developer to tweak front end
  6. Designer sees the real thing and decides to change it. This is natural.

There's a lot of suck in here. Lets remove some.

The set up

We are going to write a script in swift to take a html template and inject some data. This way you can test how your design will hold up with extreme title lengths, or change heading sizes and see it reflect across the layout, increase the amount of data by factors and see it all for real on a device. In short, I don't think it is possible to design well in a static paradigm when the final product exists in a dynamic state.

The objective is to get to step six as soon as possible so more time is spent polishing a design than getting it over the line. Swift tries to be friendly, so if you have not written a lot of code you should still find it readable. If you've ever done some wordpress or janked around in myspace - you got this.


You want some data that repeats. If it's a layout design this will happen as part of your UX process, you'll identify points of data and what importance should be where. In this example we'll use Pokemon. So name, type, dex entry.

Pull together some bare bones HTML - this depends on the fidelity of your prototype and your html chops. If you are purely messing with layout at different breakpoints you can get away with less. Although I don't think defining some good css typography should be beyond any designer today.

But to get started, this is enough:




The %@ is the magic incarnation. Swift can target that and inject our content.

Make a swift file. You can make this in any text editor. Xcode will give you helpful syntax highlighting, or if you are sadistic you can use vim. Nano is used here for variety. Also, command line stuff is dope.

nano assemble.swift

Then we need to import the Foundation framework, which is one line:

import Foundation

Structs. Think of this like a template for data, you define the slots and what shape they are: Numbers, Strings, Dates.

As Swift is type safe you need to be upfront about what goes where.

struct Pokemon {
	var name: String
	var number: Int
	var type = [String]() // Pokemon can have many types, so use an array
	var dexEntry: String

And start defining some content like this:

var venusaur = Pokemon(name: "Venusaur", number: 1, type: ["Grass", "Poison"], dexEntry: "It can go for days without eating a single morsel. In the bulb on its back, it stores energy.")
var charmander = Pokemon(name: "Charmander", number: 4, type: ["Fire"], dexEntry: "The flame at the tip of its tail makes a sound as it burns. You can only hear it in quiet places.")
var squirtle = Pokemon(name: "Squirtle", number: 7, type: ["Water"], dexEntry: "Shoots water at prey while in the water. Withdraws into its shell when in danger.")

A content loop. Create an array, and feed it all the structs we created. Then step through each Pokemon in the array and create some html - this is what we will inject into the html template.

// 3.   An array of data for us to use
var pokemonArray = [venusaur, charmander, squirtle]

// 4.   Build some content by adding strings, and then returning it for use elsewhere
func assembleTeam() -> String {
    var content = ""
    for pokemon in pokemonArray {
        var name = "\t<h2>%@</h2>\n"
        name = String(format: name, pokemon.name)
        var number = "\t<p>%@</p>\n"
        number = String(format: number, String(pokemon.number))
        var entry = "\t<p>%@</p>\n"
        entry = String(format: entry, String(pokemon.dexEntry))
    return content

Don't be intimidated. Nearly done. This snippet is receiving the content the function above returns and looks for template.html which contains the magic %@ incarnation - it then swaps %@ for our content and writes out index.html.

// 5.   Feed some content to be injected into a template
func writeTemplate(content: String) {
    // the location of our template containing '%@'
    let path = String(NSString(string:"template.html"))
    do {
        let template = try String(contentsOfFile: path, encoding: String.Encoding.utf8)
        let file = String("output.html") // the file we will export
        do {
            try content.write(toFile: file, atomically: false, encoding: String.Encoding.utf8)
            print ("🔥 boom. successfully wrote: \(file)")
        catch {
            print ("🤨 dang. unable to write \(file)")
    } catch {
        print("🤨 can't find \(path)")

Then we call the function we just wrote and give it some content to parse:

// This function will write index.html using template.html as it's source, and calling assembleTeam() to return a string of content
writeTemplate(content: assembleTeam())

Save and close your swift file and we're kind of done. All being well you can run this from your command line and it will write output.html:

swift assemble.swift

For clean codes sake all this happens in the directory the script is being executed from. Github has fancy code highlighting and you can download the files.

I've tried to keep this as self contained as possible, but if anything has gone whoosh feel free to HMU on twitter or insta.


At this point we have an array of data that can be any length we wish, and a way to render it in html. Now we are free to get on with essential tasks like tweaking spacing between cells and finding the perfect shade of pink for all devices. 👙

Depending on the fidelity of your prototype you can hand that over, or you can take your learnings and document them with confidence in your design app of choice. You can also use this to A/B test layouts, or stress test a design against extreme content without manually producing iterations for multiple breakpoints.


Chancee is a designer who codes from London Town.

They have worked for the likes of Nike, Vodafone, Sky, Disney and Pearsons, won awards from Promax, BAFTAs, the Appys and The Drum. Spoken at The Waldorf and Southampton University - despite swearing like a sailor. Available for hire to draw pretty curves and code clever things.


Music: 23Cities: 12Hip Hop: 12Heavy Rotation: 11SovietTough: 11Crypto: 9Design: 9Architecture: 9Space: 7Code: 7NFTs: 6Low Power: 6GameDev: 6Twitter: 6Robust Computing: 5No Bullshit: 5OpenBSD: 4Hacking: 4Javascript: 4Walkman: 3Headphones: 3Engineering: 3CSS: 3History: 3Google: 3Sci-Fi: 3Development: 3Trains: 3Web3: 2Low power: 2Swift: 2Cloud: 2Apple Music: 2Politics: 2Carbon: 2LowTech: 2Solar: 2SP-404: 2Protocols: 2Skateboard: 2London: 2Housing: 2Halfway house: 2Machine Learning: 2Bitcoin: 2Africa: 2Wall Street: 2RSS: 2Transport: 2Aesop Rock: 2Disney: 2Comics: 2Fashion: 2


May 2024

Selling 'Ghost In The Shell'

Vim - Inserting inline dates shortcut

xkcd - Machine

Apr 2024

Heavy Rotation April 2024

Blockhead Listening Party

Mar 2024

Heavy Rotation March 2024

X-Men 97 Is To Return

Crypto and ‘TradFi’: a friendship of convenience

The mysterious rise of the Chinese e-commerce giant behind Temu

Twitter Debt

Oumuamua, Our first interstellar visitor

Feb 2024

Heavy Rotation February 2024

JavaScript Bloat in 2024

Knots on Mars!

World’s least profitable blog

Jan 2024

Heavy Rotation January 2024

SP-404 Resources

How a 27-year-old busted the myth of Bitcoin’s anonymity

Dec 2023

Heavy Rotation December 2023

The future is probably federated

Heavy Rotation November 2023

Plagiarism and You(Tube)

Nov 2023

Integrated Tech Solutions: Aesop Rock

The Design Museum: Skateboard

Oct 2023

Heavy Rotation October 2023

Vim syntax highlighting

DJ Shadow - Action Adventure

Twitter Bank

No, we didn't forget any zeros

"No more trains!"

Tupac Shakur murder: video released of suspect’s arrest for 1996 murder

Sep 2023

Heavy Rotation September 2023

"How we fit an NES game into 40 Kilobytes"

Financial siren

Saving the sounds of Afghanistan

Rain Gardens

Aug 2023

Fuck around and find out award: Antoinette Sandbach

Heavy Rotation August 2023

The long drawn out implosion of NFTs

Kowloon Walled City

Jul 2023

Heavy Rotation July 2023

How palette and lighting works in The Settlers II

Hidari: The Stop-Motion Samurai Film

Jun 2023

Heavy Rotation June 2023

Babylon 5: The Road Home. Official Trailer

Sounds of Fashaga

May 2023

The secret Babylon 5 project is...an animated movie

Mar 2023


Jan 2023

Panic enters the Mastodon arena

Adobe is collecting all of its customers' pictures into a machine learning training set.

Gluten Free Weed Edibles

Nov 2022

UK Treasury joins chat app Discord and is met with torrent of abuse

my website is one binary

Twitter Impodes

Jul 2022

Eevee Beat Tape Discography

The mars company

Another recruit joins the Walkman ranks

Jun 2022

ProleteR: Curses from Past Times

Cocaine, class and me

May 2022

Financial Times's Gideon Rachman on the Ukraine Conflict

Why African fashion is having its moment

DJ Cable: Throw Back Thursdays

Apr 2022

Web3.0: A Libertarian Dystopia

Mar 2022

From Downtown

Edited latecomer's guide to crypto

Feb 2022

iPod Shennanigans

Jan 2022

Line goes up

Fuck NFTs

Web3 is going just great

Aesop Rock x Blockhead. Garbology

Dec 2021

Playdate Art: Scale

Website carbon

Humble ‘retro’ corded headphones are making an unexpected return, for both aesthetic and practical reasons

Moving files around for Crayon Munchers

Low Tech Magazine

How it all happened

Nov 2021

Space War

Oct 2021

HomeLab MkII

Human History Gets a Rewrite

Aug 2021

Autonomous Monastic State

Jul 2021

Back to the future, baby!

Jun 2021

Gemini and robust computing

Rust and LEDs

One Man’s Amazing Journey to the Center of the Bowling Ball

May 2021

Go slow and fix things

The Oral History of the Chelsea Hotel

Good developers know how, great ones know why

"Fuck the bread, the bread is over"

The Promise and Perils of Insect Farming

Apr 2021

It fell of a lorry

Inside a halfway house

Hacking an iPod

Indian drop calls

Why bumblebees love cats, or, why everything is a system.

Sony NW-A55L FTW

Mar 2021

Climate models and Fortran

Plain text protocols

150 Watt Office

High Potassium Posting

Feb 2021

Fuck google: Part II

Fuck google

City cycles

Eating the super-rich

Jan 2021

Four seasons

Dec 2020

"This time, damn it, we’re going to get to the surface"

Chrome is bad

Designing 2D graphics in the Japanese industry

Bad launch leads to real world relativistic math

Nov 2020



Abandon stream: Part 2

Oct 2020

Fuck Boris

American Viziers

Sep 2020


Motherless Brooklyn

Riding rails

Basic Printing in OpenBSD

Slaughter at the bridge: Uncovering a colossal Bronze Age battle

Technicolor portals

Aug 2020

Abandon stream

Behind the Accidentally Resilient Design of Athens Apartments

Jul 2020

The Walkman Forty Years on

Jun 2020

I Dream of Canteens

May 2020

OpenBSD Git server

Unreleased De La Soul Acapellas

Apr 2020

Animating SVGs: Strokes

You're designing for the web wrong: Part 1

A newspaper made from RSS feeds

Marvellous glass

Charlie Sloth Rap Show

Swift: Google's bet on differentiable programming

Mar 2020

OpenBSD Everything

Master & Dynamic: MW60

Where are the voyagers now

Lethal Bizzle is back!

Feb 2020

Low cost, low power NAS

A CSS history tour

Debugging a live saturn V

Two up, Two down in London Town

Jan 2020

Into the indie-verse