Hvordan siden er laget
Reisebyrået er oppdiktet. Avgjørelsene er ikke. Her står de som betydde noe — og de som var feil før de ble rettet.
Sist oppdatert 27. september 2026
Én regel, og alt følger av den
Lyset først. Siden er satt som en film i skumringen: lerretet er natt, og det eneste varme er lyset i fotografiene og én gyllen aksent. Første skjerm er en pirog i motlys utenfor Saly, i full høyde, med tittelen øverst der himmelen er gjort mørk.
Tre setninger er hele regelen. Natten bærer alt, og ingen flate er lysere enn fotografiene. Gullet brukes bare der noe skal leses først eller trykkes på. Og satsen har to stemmer: Cormorant, en høy og lys antikva, stor og tynn som en filmtittel, og Jost, en geometrisk grotesk, til brødtekst og til de sperrede merkelappene.
En regel som denne er verdt mer enn smaken til den som tegner. Den svarer på spørsmål ingen har stilt ennå, og den svarer likt hver gang.
Siden har vært fem andre ting før dette: en sesongkatalog trykt i to dekkende farger, så frostet glass over et fotografi, så flate felt som vekslet mellom sand og blekk, så ett mørkt lerret med én limeaksent, så et lyst lerret i sand og terrakotta. Punktene under er skrevet om hver gang flatene ble byttet. Det som står igjen, står igjen fordi det fortsatt er sant.
Aksenten har flyttet seg fem ganger
Hver gang av samme grunn, og ingen av dem var smak: fargen ble aldri valgt for seg selv, den ble valgt av bunnen den skulle stå på.
Første gang: okeren var en lys og fin oransje som ga 2,83:1 mot papiret, under kravet på 4,5:1. Den ble mørknet til 4,85:1 og satt der så lenge bunnen var lys.
Andre gang: bunnen ble mørk. Den samme mørke okeren ga 2,70:1 mot glasset — den var jo valgt for å holde mot et lyst papir — og måtte løftes tilbake omtrent dit den startet, til en sol som holdt 6,4:1 mot blekket.
Tredje gang: bunnen ble mørkere igjen. Limen holdt 16,5:1 mot det mørke lerretet og var første gang aksenten kunne være både flate og sats.
Fjerde gang: lerretet ble lyst, og limen falt til 1,3:1 mot sand. Terrakottaen holdt 5,4:1 begge veier.
Femte gang: lerretet ble natt igjen, og terrakottaen falt med det — den var valgt for å holde mot sand, og mot natten gir den 3,4:1. Gullet holder 11,3:1 mot natten, og natten holder like mye tilbake på gullflaten, så det bærer både knappene og det ene kursive ordet i tittelen.
- Lys oker på papir, forkastet
- 2,83:1
- Mørk oker på papir, trykkutgaven
- 4,85:1
- Mørk oker på glass, under kravet
- 2,70:1
- Sol på blekk, flate felt
- 6,40:1
- Lime på mørkt lerret
- 16,5:1
- Lime på sand, falt
- 1,30:1
- Terrakotta på sand
- 5,40:1
- Terrakotta på natt, falt
- 3,43:1
- Gull på natt, nå
- 11,3:1
Poenget er ikke hvilken farge som vant. Det er at fargen flyttet seg hver gang bunnen gjorde det, og at det er regnestykket som bestemte hvor den landet.
- Sats mot lerretet
- 17,0:1
- Aksent mot lerretet
- 11,3:1
- Lerretet som sats på aksentflate
- 11,3:1
- Dempet sats mot lerretet
- 10,1:1
Mot et fotografi kan ingenting regnes ut av paletten, så der er tallene målt på den ferdige siden, piksel for piksel, av kontrast.py. Tittelen står 15,3:1 mot himmelen på telefon og 16,7:1 på skjerm. Ingressen under den står 14,8:1, knappeteksten på gullflaten 10,5:1, og kreditteringen nede i hjørnet 7,6:1. Det svakeste på hele forsiden er de små merkelappene som skal tre tilbake, på 5,7:1 — kravet er 4,5.
Prøvelappen står ved siden av tallet fordi en tabell om kontrast som bare oppgir tall, ber leseren tro på dem. Regn etter før du rører en av fargene.
Lys, og litt bevegelse
Skumringen tillot noe den forrige utgaven ikke gjorde: litt bevegelse. Fotografiet i heroen glir langsomt inn over seksten sekunder, tittelen tones opp, og det som kommer inn i bildet lenger ned løfter seg noen piksler. Ber systemet ditt om mindre bevegelse, står alt stille fra første bilde.
Dybden kommer fra lyset. Sløret over fotografiet er multiplisert inn i bildet i stedet for lagt oppå, så den oransje himmelen blir dyp rav mot toppen og ikke grå. Gløden rundt knappene, solen på termometeret og ruta på kloden er det som lyser.
- Telefonen får sitt eget utsnitt. Et liggende bilde som dekker en stående skjerm viser en tredel av bredden, og nettleseren velger fil etter skjermbredden — det ga et bilde blåst opp over to ganger. Nå skjæres det stående utsnittet ut av originalen i 1290 × 2796 punkter og gis til stående skjermer.
- Fotografiene fikk høyere kvalitet og en bredde til, 2400 punkter. På mørk bunn synes blokkartefaktene i skyggene mye tydeligere enn de gjorde på sand.
- Hvert bilde og hver skrift har innholdshash i filnavnet. De caches i et år; får en fil nytt innhold, får den også ny adresse.
- Et bilde forsvant. Det som sto øverst i forrige utgave, merket som kysten på Petite Côte, er ifølge Unsplash tatt i Ada i Ghana. Bildene av kysten nå er fra Saly, og stedet står på Unsplash-siden til hvert av dem.
Skriftene er byttet: Fraunces, Inter og JetBrains Mono er ute, Cormorant og Jost er inne. Monospace finnes ikke lenger på siden — tallene står i Cormorant, og merkelappene er sperret Jost.
To bygde sider, ikke en knapp som bytter teksten
Første versjon byttet språk med JavaScript på samme adresse. Det gir tre problemer som ikke lar seg fikse uten å bygge: den engelske teksten finnes ikke for søkemotorer, ingen kan lenke til den, og valget forsvinner ved neste sidelasting.
Nå er norsk på «/» og engelsk på «/en/», med hreflang mellom seg. Det koster et byggesteg og løser alle tre.
NO og EN øverst til høyre er derfor vanlige lenker mellom de to adressene, ikke en bryter. Står du på vilkårene, går EN til vilkårene på engelsk, ikke til forsiden.
Automatisk språkvalg er også ute, og det er verdt en advarsel: et norsk system melder «nb-NO», ikke «no». Den gamle testen sammenlignet de to første bokstavene mot «no» og sendte dermed hver eneste norske besøkende til den engelske utgaven.
Delebildet: 507 kB som ingen så
Bildet som vises når noen deler lenken, ble tegnet i ren Python og lagt tilfeldig korn over for å ligne trykk. Det så riktig ut. Det veide 507 kB — mer enn resten av siden til sammen.
Støy har ingen gjentakelse, så komprimeringen får ikke tak i den. Og WhatsApp henter ikke delebilder over rundt 300 kB, så forhåndsvisningen falt stille ut der. Ingen feilmelding; bare ingen bilde.
- Med tilfeldig korn
- 507 kB
- Med radfiltrering i tillegg
- 656 kB — verre
- Med rasterskjerm i stedet
- 16 kB
- Samme raster, tegnet på natt
- 22 kB
- Fotografiet som JPEG, nå
- 76 kB
Radfiltrering er triksene man leser om, og her gjorde den vondt verre: filteret lagrer differansen mot nabopikselen, og differansen mellom to tilfeldige tall er like tilfeldig.
Løsningen ble et raster i stedet: et mønster som gjentar seg per definisjon og derfor pakkes nesten gratis.
Rasteret er også borte. I en samtale leste det som utklipp, ikke som stedet. Delebildet er nå et utsnitt av fotografiet i heroen, med navnet i Cormorant og den gylne hårstreken, lagret som JPEG. Som PNG veide det samme bildet 840 kB — igjen over grensen.
Det som ikke lastes
Ingen npm, ingen byggeverktøy, ingen rammeverk, ingen CDN-er, ingen informasjonskapsler, ingen analyse, ingen sporing. Skriftene ligger i repoet. Nettleseren din snakker med ett domene mens du er her.
- Avhengigheter
- 0
- Python-kilde
- 5 500 linjer, bare stdlib
- Forsiden over nettet, uten bilder
- 38 kB pakket
- Skriftene, to familier i tre filer
- 76 kB
Det er ikke en påstand man skal måtte tro på. En Content-Security-Policy sperrer alt utenfra, så påstanden kan ikke bli usann uten at noen skrur den av først.
Fellene som kostet mest tid
- «1fr» har min-content som gulv. Ett langt ord i versaler var bredere enn spalten sin, og hele rutenettet vokste ut av arket på 280 px. «minmax(0,1fr)» løser det, og det er verdt å lete etter hver gang noe stikker ut på smal skjerm.
- Geometri i CSS er ikke geometri i SVG. Pinnene på kartet skaleres med transform, ikke ved å sette «r» — geometriattributter som CSS er ustøttet i eldre WebKit.
- Kystlinjen måtte tegnes som en åpen strek, atskilt fra den fylte landformen. Streker man den lukkede formen, streker man opp kantene langs viewBox-en også, og kartet får en ramme rundt seg.
- requestAnimationFrame strupes i bakgrunnsfaner, så en talltelling kan bli avbrutt midt i. Riktig verdi står i HTML-en fra før, og en timeout faller tilbake til den. Et halvferdig tall skal aldri bli stående.
- På iPhone ga et fast lag med blending, uskarphet i toppen og et opacity-skriv per frame hakking under scroll. Ingenting som ligger fast har blending eller uskarphet lenger — kornet og toppen er vanlige lag — og opasiteten kvantiseres til trinn av 0,02.
Uten JavaScript står alt
Alt innholdet står i HTML-en: rommene, stedene, helgene, spørsmålene og månedene huset er åpent er fullt lesbare med JavaScript slått av. Bildene er vanlige bilder til skriptet gjør dem trykkbare, og filmene har en vanlig lenke i stedet for spilleren. Kartene er tegninger, ikke applikasjoner.
Kloden under første skjerm er det ene unntaket, og den er bygget som et tillegg: flykartet ligger i HTML-en hele tiden, og kloden legger seg over det først når den har fått tegnet et bilde. Uten JavaScript, uten canvas, eller om de 33 kB med punktdata og tegnekode aldri kommer fram, blir kartet stående. Ber systemet ditt om mindre bevegelse, står kloden stille.
Skjemaet er det eneste som ikke virker uten skript, og det lagrer ingenting — det åpner e-postprogrammet ditt med teksten ferdig utfylt, og du sender den selv.
Datoene daterer seg selv
Avgangene er oppgitt med måned og dag, uten årstall. Bygget legger på året ut fra når det kjører, og viser bare avganger som ligger foran i tid. Sesongen regnes november–mars, så et bygg i februar plukker resten av inneværende sesong og fortsetter inn i neste.
Det er den slags detalj ingen legger merke til når den virker, og alle legger merke til når en side står med fjorårets datoer i mars.