In dit artikel reflecteert de auteur op de effectiviteit van syntax highlighting in code-editors. Geïnspireerd door een artikel van Nikita Prokopov, concludeert de auteur dat teveel kleuren afleidend werken en niet functioneel zijn.
Na diverse experimenten met licht-thema's, waarbij kleuren vaak te dominant waren, ontwikkelt de auteur een grayscale-aanpak. Het doel hiervan is om visueel contrast te creëren zonder kleur te gebruiken, waardoor de focus verschuift naar de semantische waarde van de code:
- Hoge prioriteit (opvallend): Commentaren, variabele- en functiedefinities en control flow-elementen (zoals
return en throw), omdat deze essentieel zijn voor het snel scannen van de logica.
- Lage prioriteit (subtiel): Veelvoorkomende keywords (
let, const) en interpunctie, die functioneel noodzakelijk zijn maar minder bijdragen aan het begrip van de code.
Door deze hiërarchie in helderheid aan te brengen, ontstaat er een ritme dat helpt bij het sneller lokaliseren van belangrijke informatie en het verminderen van visuele ruis.
Mijn code highlighten op basis van hoeveel ik erom geef
TL;DR Na meerdere mislukte pogingen om een licht kleurthema te maken dat niet afleidde, heb ik geprobeerd er een te maken dat volledig in grijstinten is. Het doel was om bepaalde elementen meer of minder te laten opvallen tegenover de basis van zwarte variabelen en functieaanroepen op een witte achtergrond. Relatief subtiele wijzigingen in de helderheid van de tekst en achtergrond waren voldoende om een soepelere en efficiëntere leeservaring te creëren.
***
Ik las een artikel van Nikita Prokopov over hoe "iedereen syntax highlighting verkeerd doet" [1]. Het viel me op dat ik eigenlijk nooit echt had nagedacht over hoe mijn code gehighlight wordt. Ik ben vrij basic en gebruik het standaard VSCode Dark Theme sinds ik heel lang geleden ben overgestapt van JetBrains. Ik ben zo gewend geraakt aan hetzelfde thema en dezelfde kleuren dat ik er door de jaren heen blind voor ben geworden.
Vooral dit gedeelte uit het bericht van Nikita viel me op:
Hier is een andere test. Sluit je ogen (nog niet! Maak eerst deze zin af) en probeer je te herinneren welke kleur jouw kleurthema gebruikt voor klassenamen?
Kun je dat?
Als het antwoord op beide vragen "nee" is, dan is je kleurthema niet functioneel. Het geeft je misschien een gevoel van comfort (in de zin van: ik voel me veilig, als het gehighlight is, is het waarschijnlijk code), maar je kunt het niet als instrument gebruiken. Het helpt je niet.
Wat is de oplossing? Gebruik een absoluut minimum aan kleuren. Zo weinig dat ze allemaal tegelijk in je hoofd passen.
Ik weet dat er wat blauw is, ander blauw, en zeker wat paars... maar ik weet niet echt welke wat is. Oké, ze zeggen dus dat als ik het me niet kan herinneren, dat komt omdat er te veel kleuren in mijn thema zitten. Nou, laten we gewoon een nieuwe maken met minder kleuren, hoe moeilijk kan dat zijn?
Je kunt waarschijnlijk raden waar dit naartoe gaat, maar het blijkt dat het echt heel moeilijk is als je een licht thema probeert te maken! In feite moeten kleuren, om contrast te hebben met een witte achtergrond, donkerder zijn dan ze in een donker thema zouden zijn. Donkere kleuren zijn minder levendig en hebben daardoor minder perceptuele impact.
Na wat experimenteren merkte ik dat het lastig was om een thema te maken dat paste bij deze site (grotendeels een '1-bit esthetiek'). Het was niet zo dat de kleuren niet werkten om bepaalde secties te laten opvallen, maar dat ze dingen te veel lieten opvallen.
Die ervaring zette me aan het denken...
Waarom zou code überhaupt gehighlight moeten worden?
Het voor de hand liggende antwoord lijkt een combinatie van twee dingen te zijn:
- Ik wil code kunnen onderscheiden (selectieve aandacht).
- Ik wil bepaalde code snel visueel kunnen vinden (snel lokaliseren).
Hoewel ik het nog steeds eens ben met dit uitgangspunt, concludeerde ik na een hoop experimenten dat ik, om te bepalen hoe ik elementen zou laten opvallen en vindbaar zou maken, eerst moest beantwoorden welke elementen die behandeling verdienen. Ik liet die vraag in mijn hoofd rondzingen terwijl ik wanhopig probeerde om een kleurthema werkend te krijgen.
Op dit punt in het proces vond ik geen enkel licht thema leuk—ze waren ofwel te moeilijk leesbaar of te monotoon (althans, vergeleken met de absolute impact van donkere thema's).
Dit bracht me tot een verdere vraag...
Moet highlighting eigenlijk wel in kleur zijn?
Wat als we zouden proberen te kijken hoe ver we kunnen komen zonder kleurcontrast te gebruiken, en alleen tonen gebruiken?
De eerste stap: verwijder alle kleur-syntax en maak het rauw, zwart op wit.
Gestript tot niets
/** Await all values in a property and preserve original types */
async function resolveProperties<
const T extends Record<string, unknown>,
>(properties: T): Promise<{ [K in keyof T]: Awaited<T[K]> }> {
const entries = await Promise.all(
Object.entries(properties).map(async ([key, value]) => [
key,
await value,
] as const),
);
return Object.fromEntries(entries) as {
[K in keyof T]: Awaited<T[K]>;
};
}
Ik... wow, ik haat dit echt. Het is zo vlak dat ik het gevoel heb dat ik elk teken individueel moet lezen om mijn ogen correct te kunnen navigeren! In tegenstelling tot proza, dat je meestal lineair leest, spring je bij code heen en weer op basis van welke verbonden elementen je verkent. Dit is waarom het aspect van 'snel lokaliseren' zo belangrijk is!
We moeten hier dus een vorm van contrast toevoegen.
Om te voorkomen dat dit bericht eindeloos doorgaat, slaan we de fase van het experimenteren over en gaan we direct naar de eindresultaten.
Opmerking: Je kunt in het highlight-venster op het vakje linksboven klikken om de highlighting aan of uit te zetten. Ook kun je klikken voor dynamische highlighting van dezelfde woorden en de huidige bracket-scope.
Voorbeeld van grayscale highlighting
/** Await all values in a property and preserve original types */
async function resolveProperties<
const T extends Record<string, unknown>,
>(properties: T): Promise<{ [K in keyof T]: Awaited<T[K]> }> {
const entries = await Promise.all(
Object.entries(properties).map(async ([key, value]) => [
key,
await value,
] as const),
);
return Object.fromEntries(entries) as {
[K in keyof T]: Awaited<T[K]>;
};
}
(De typings en het gebruik van generics kunnen er ongeacht de highlighting-aanpak wat druk uitzien.)
De basistekst blijft gewoon zwart op wit, omdat we een middelpunt nodig hebben om onze focus op te centreren. Variabele- en functiereferenties blijven op de basislijn, omdat dat het grootste deel van de code is en je niet op het grootste deel van alles speciale aandacht kunt besteden. De zaken die afwijken zijn, in volgorde van belangrijkheid:
- Commentaren: deze bevatten beschrijvingen op hoog niveau (sneller dan de code lezen) en externe context (het "waarom" waar het lezen van code geen antwoord op kan geven). Dit is het meest scanbare onderdeel in elk groot codebestand.
- Variabele- en functiedefinities: bij het aanmaken van iets is het vooral nuttig dat dit opvalt, zodat ik alle gemaakte objectnamen kan scannen. Dit ondersteunt mijn eerste scan van de code om uit te zoeken wat er aan de hand is.
- Call Stack Flow:
return, throw, yield zijn allemaal branch-terminators en markeren waar code in de scope van de functie kan stoppen of de uitvoering kan pauzeren. Deze zijn structureel en zouden visueel snel te vinden moeten zijn.
Aan de andere kant realiseerde ik me dat ik, net zoals ik meer aandacht wil besteden aan sommige gebieden, ook minder aandacht wil besteden aan andere.
- Veelvoorkomende keywords zoals
let, const: ik hoef hier in principe nooit meer naar te kijken nadat ik ze aanvankelijk heb getypt. Deze zouden bijna onzichtbaar kunnen zijn zonder dat het voor mij uitmaakt.
- Interpunctie: haken, puntkomma's als statement-terminators, dubbele punten, komma's. Deze zijn vereist om de taal te laten functioneren, maar ze zijn niet echt betekenisvol, tenzij er een fout is door onjuiste typtijd. We maken deze net iets lichter dan de basistekst, zodat ze visueel iets naar de achtergrond verdwijnen.
Naast de statische highlighting is er de dynamische, klik-gebaseerde highlighting voor dezelfde woorden en het lokaliseren van scope/brackets.
Het idee is dat de highlighting je ogen moet laten springen tussen de stukken die het meest belangrijk zijn bij het lezen, zodat je je kunt concentreren op de semantische delen en over de puur syntactische delen heen kunt scannen. Het moet duidelijk genoeg zijn om echte waarde te bieden, maar subtiel genoeg zodat delen waar ik niet naar probeer te kijken, me niet afleiden van waar ik wel naar kijk.
Commentaren en meer Control Flow
type Job = {
id: string;
label: string;
enabled: boolean;
};
async function* completedJobs(jobs: Job[]): AsyncGenerator<string> {
for (const job of jobs) {
if (!job.enabled) continue;
// Keep the request lazy so disabled jobs never wake the service.
const response = await fetch(`/api/jobs/${job.id}`);
if (!response.ok) continue;
const result = (await response.json()) as {
status: "complete" | "failed";
message: string;
};
if (result.status !== "complete") continue;
yield `${job.label} (${job.id}): ${result.message}`;
}
}
Hier kun je een natuurlijker voorbeeld zien van het ritme dat door de highlighting wordt gecreëerd.
Over het algemeen was het optimaliseren van highlighting op basis van waar ik aandacht aan wilde besteden een zeer interessante oefening om uit te vogelen waar ik precies aandacht aan wilde besteden.
***
Bronverwijzingen
[1] I am sorry, but everyone is getting syntax highlighting wrong Nikita Prokopov, 15 oktober 2025. Prokopov betoogt dat syntax highlighting moet benadrukken wat het meest belangrijk is, in plaats van alles gelijkmatig te highlighten. Hij pleit ook voor een veel spaarzamer gebruik van highlighting dan in populaire thema's. "Als alles gehighlight is, is niets gehighlight" (queue Syndrome).
Mijn code highlighten op basis van hoeveel ik erom geef
TL;DR Na meerdere mislukte pogingen om een licht kleurthema te maken dat niet afleidde, heb ik geprobeerd er een te maken dat volledig in grijstinten is. Het doel was om bepaalde elementen meer of minder te laten opvallen tegenover de basis van zwarte variabelen en functieaanroepen op een witte achtergrond. Relatief subtiele wijzigingen in de helderheid van de tekst en achtergrond waren voldoende om een soepelere en efficiëntere leeservaring te creëren.
***
Ik las een artikel van Nikita Prokopov over hoe "iedereen syntax highlighting verkeerd doet" [1]. Het viel me op dat ik eigenlijk nooit echt had nagedacht over hoe mijn code gehighlight wordt. Ik ben vrij basic en gebruik het standaard VSCode Dark Theme sinds ik heel lang geleden ben overgestapt van JetBrains. Ik ben zo gewend geraakt aan hetzelfde thema en dezelfde kleuren dat ik er door de jaren heen blind voor ben geworden.
Vooral dit gedeelte uit het bericht van Nikita viel me op:
Hier is een andere test. Sluit je ogen (nog niet! Maak eerst deze zin af) en probeer je te herinneren welke kleur jouw kleurthema gebruikt voor klassenamen?
Kun je dat?
Als het antwoord op beide vragen "nee" is, dan is je kleurthema niet functioneel. Het geeft je misschien een gevoel van comfort (in de zin van: ik voel me veilig, als het gehighlight is, is het waarschijnlijk code), maar je kunt het niet als instrument gebruiken. Het helpt je niet.
Wat is de oplossing? Gebruik een absoluut minimum aan kleuren. Zo weinig dat ze allemaal tegelijk in je hoofd passen.
Ik weet dat er wat blauw is, ander blauw, en zeker wat paars... maar ik weet niet echt welke wat is. Oké, ze zeggen dus dat als ik het me niet kan herinneren, dat komt omdat er te veel kleuren in mijn thema zitten. Nou, laten we gewoon een nieuwe maken met minder kleuren, hoe moeilijk kan dat zijn?
Je kunt waarschijnlijk raden waar dit naartoe gaat, maar het blijkt dat het echt heel moeilijk is als je een licht thema probeert te maken! In feite moeten kleuren, om contrast te hebben met een witte achtergrond, donkerder zijn dan ze in een donker thema zouden zijn. Donkere kleuren zijn minder levendig en hebben daardoor minder perceptuele impact.
Na wat experimenteren merkte ik dat het lastig was om een thema te maken dat paste bij deze site (grotendeels een '1-bit esthetiek'). Het was niet zo dat de kleuren niet werkten om bepaalde secties te laten opvallen, maar dat ze dingen te veel lieten opvallen.
Die ervaring zette me aan het denken...
Waarom zou code überhaupt gehighlight moeten worden?
Het voor de hand liggende antwoord lijkt een combinatie van twee dingen te zijn:
- Ik wil code kunnen onderscheiden (selectieve aandacht).
- Ik wil bepaalde code snel visueel kunnen vinden (snel lokaliseren).
Hoewel ik het nog steeds eens ben met dit uitgangspunt, concludeerde ik na een hoop experimenten dat ik, om te bepalen hoe ik elementen zou laten opvallen en vindbaar zou maken, eerst moest beantwoorden welke elementen die behandeling verdienen. Ik liet die vraag in mijn hoofd rondzingen terwijl ik wanhopig probeerde om een kleurthema werkend te krijgen.
Op dit punt in het proces vond ik geen enkel licht thema leuk—ze waren ofwel te moeilijk leesbaar of te monotoon (althans, vergeleken met de absolute impact van donkere thema's).
Dit bracht me tot een verdere vraag...
Moet highlighting eigenlijk wel in kleur zijn?
Wat als we zouden proberen te kijken hoe ver we kunnen komen zonder kleurcontrast te gebruiken, en alleen tonen gebruiken?
De eerste stap: verwijder alle kleur-syntax en maak het rauw, zwart op wit.
Gestript tot niets
/** Await all values in a property and preserve original types */
async function resolveProperties<
const T extends Record<string, unknown>,
>(properties: T): Promise<{ [K in keyof T]: Awaited<T[K]> }> {
const entries = await Promise.all(
Object.entries(properties).map(async ([key, value]) => [
key,
await value,
] as const),
);
return Object.fromEntries(entries) as {
[K in keyof T]: Awaited<T[K]>;
};
}
Ik... wow, ik haat dit echt. Het is zo vlak dat ik het gevoel heb dat ik elk teken individueel moet lezen om mijn ogen correct te kunnen navigeren! In tegenstelling tot proza, dat je meestal lineair leest, spring je bij code heen en weer op basis van welke verbonden elementen je verkent. Dit is waarom het aspect van 'snel lokaliseren' zo belangrijk is!
We moeten hier dus een vorm van contrast toevoegen.
Om te voorkomen dat dit bericht eindeloos doorgaat, slaan we de fase van het experimenteren over en gaan we direct naar de eindresultaten.
Opmerking: Je kunt in het highlight-venster op het vakje linksboven klikken om de highlighting aan of uit te zetten. Ook kun je klikken voor dynamische highlighting van dezelfde woorden en de huidige bracket-scope.
Voorbeeld van grayscale highlighting
/** Await all values in a property and preserve original types */
async function resolveProperties<
const T extends Record<string, unknown>,
>(properties: T): Promise<{ [K in keyof T]: Awaited<T[K]> }> {
const entries = await Promise.all(
Object.entries(properties).map(async ([key, value]) => [
key,
await value,
] as const),
);
return Object.fromEntries(entries) as {
[K in keyof T]: Awaited<T[K]>;
};
}
(De typings en het gebruik van generics kunnen er ongeacht de highlighting-aanpak wat druk uitzien.)
De basistekst blijft gewoon zwart op wit, omdat we een middelpunt nodig hebben om onze focus op te centreren. Variabele- en functiereferenties blijven op de basislijn, omdat dat het grootste deel van de code is en je niet op het grootste deel van alles speciale aandacht kunt besteden. De zaken die afwijken zijn, in volgorde van belangrijkheid:
- Commentaren: deze bevatten beschrijvingen op hoog niveau (sneller dan de code lezen) en externe context (het "waarom" waar het lezen van code geen antwoord op kan geven). Dit is het meest scanbare onderdeel in elk groot codebestand.
- Variabele- en functiedefinities: bij het aanmaken van iets is het vooral nuttig dat dit opvalt, zodat ik alle gemaakte objectnamen kan scannen. Dit ondersteunt mijn eerste scan van de code om uit te zoeken wat er aan de hand is.
- Call Stack Flow:
return, throw, yield zijn allemaal branch-terminators en markeren waar code in de scope van de functie kan stoppen of de uitvoering kan pauzeren. Deze zijn structureel en zouden visueel snel te vinden moeten zijn.
Aan de andere kant realiseerde ik me dat ik, net zoals ik meer aandacht wil besteden aan sommige gebieden, ook minder aandacht wil besteden aan andere.
- Veelvoorkomende keywords zoals
let, const: ik hoef hier in principe nooit meer naar te kijken nadat ik ze aanvankelijk heb getypt. Deze zouden bijna onzichtbaar kunnen zijn zonder dat het voor mij uitmaakt.
- Interpunctie: haken, puntkomma's als statement-terminators, dubbele punten, komma's. Deze zijn vereist om de taal te laten functioneren, maar ze zijn niet echt betekenisvol, tenzij er een fout is door onjuiste typtijd. We maken deze net iets lichter dan de basistekst, zodat ze visueel iets naar de achtergrond verdwijnen.
Naast de statische highlighting is er de dynamische, klik-gebaseerde highlighting voor dezelfde woorden en het lokaliseren van scope/brackets.
Het idee is dat de highlighting je ogen moet laten springen tussen de stukken die het meest belangrijk zijn bij het lezen, zodat je je kunt concentreren op de semantische delen en over de puur syntactische delen heen kunt scannen. Het moet duidelijk genoeg zijn om echte waarde te bieden, maar subtiel genoeg zodat delen waar ik niet naar probeer te kijken, me niet afleiden van waar ik wel naar kijk.
Commentaren en meer Control Flow
type Job = {
id: string;
label: string;
enabled: boolean;
};
async function* completedJobs(jobs: Job[]): AsyncGenerator<string> {
for (const job of jobs) {
if (!job.enabled) continue;
// Keep the request lazy so disabled jobs never wake the service.
const response = await fetch(`/api/jobs/${job.id}`);
if (!response.ok) continue;
const result = (await response.json()) as {
status: "complete" | "failed";
message: string;
};
if (result.status !== "complete") continue;
yield `${job.label} (${job.id}): ${result.message}`;
}
}
Hier kun je een natuurlijker voorbeeld zien van het ritme dat door de highlighting wordt gecreëerd.
Over het algemeen was het optimaliseren van highlighting op basis van waar ik aandacht aan wilde besteden een zeer interessante oefening om uit te vogelen waar ik precies aandacht aan wilde besteden.
***
Bronverwijzingen
[1] I am sorry, but everyone is getting syntax highlighting wrong Nikita Prokopov, 15 oktober 2025. Prokopov betoogt dat syntax highlighting moet benadrukken wat het meest belangrijk is, in plaats van alles gelijkmatig te highlighten. Hij pleit ook voor een veel spaarzamer gebruik van highlighting dan in populaire thema's. "Als alles gehighlight is, is niets gehighlight" (queue Syndrome).