I was invited to the JS Party podcast to talk about all things Polypane, from the business side of things to nitty-gritty features that I’ve been working on. I had a lot of fun and I think Nick and Jerod did as well.
Polypane purveyor Kilian Valkhof joins Nick & Jerod to tell us all about his efforts building a web browser just for web development. We cover it all: from the business concerns, to the technical details, to his excellent choice not to use TypeScript! We even sneak in a feature request that already made its way into this excellent dev tool for ambitious web developers.
JS Party 327: Polypane-demonium – Listen on Changelog.com
The post JS Party podcast: Polypane-demonium first appeared on Kilian Valkhof.
As someone building a browser I need to parse a lot of URLs. Partially to validate them, but also to normalize them or get specific parts out of the URL. The URL API in browsers lets you do that, but it’s ergonomics aren’t ideal.
The problem with new URL()The “new” in front of new URL() indicates that it’s used as a constructor: calling it creates a new URL instance for you. When you give it a malformed URL however, one that it can’t parse, it throws an error. Because it throws an error, you need to write code to handle that error.
If you don’t do that, The thrown error won’t get handled and your JS stops being executed. The following code looks great but if urlstring is malformed, it will stop execution:
const urlstring = "this is not a URL";const not_a_url = new URL(urlstring);
So you'll want to wrap it in a try...catch so that the error is caught.
const urlstring = "this is not a URL";let not_a_url;try { not_a_url = new URL(urlstring);} catch { // not_a_url is already undefined so no need to actually do anything.}
That's a lot more lines of code, has more visual noise and it means you have to change not_a_url from a const to a let to be able to overwrite it. The control flow of the application ends up being more complex.
Making it slightly betterA recent addition to the URL api is URL.canParse(), a function that returns true if the URL is a parseable URL.
It's only been available cross-browser since December 2023 so it might be a little too early for general use, but it does make the code more readable.
Instead of trying and catching the error, we can first check if the URL is parseable before parsing it, and we can do that inline:
const urlstring = "this is not a URL";const not_a_url = URL.canParse(urlstring) && new URL(urlstring);
This makes not_a_url a const again, and is definitely easier to understand.
ComplainingRather than being constructive and writing my own little function to abstract that try...catch or canParse away from my regular code base, I decided to do the right thing and complain on Twitter:
Making new URL() throw when you give it an invalid URL was a terrible API choice.
Not much later Anne van Kesteren replied with a link to a GitHub issue discussing the addition of a "parse" function to URL that would not throw.
Anne added that issue in 2018 but my tweet renewed interest. Not much later, Anne added URL.parse() to the spec and implementation bugs were filed for all browser engines.
Anne himself implemented it in WebKit and it's also going to ship in Chromium 126 and Firefox 126.
Using URL.parseWith URL.parse we can go back to that original example all the way up top, and keep our control flow as simple as possible:
const urlstring = "this is not a URL";const not_a_url = URL.parse(urlstring);
The browsers with this feature will ship in the next few months (Firefox in May, Chrome in June, I've not been able to figure out when Safari will) so you'll have to wait a little before using it but I can't wait to get rid of all my try..catch calls!
The post The problem with new URL(), and how URL.parse() fixes that first appeared on Kilian Valkhof.
Yesterday on Mastodon we had a short discussion about the (terribly named) overflow media feature. Because it has the same name as a CSS property it’s easy to think it has more power than it really does. Underlying that is the issue that your page can’t change the value of a media feature: media features say something about the medium: the device, browser or user preferences.
Media featuresWhen I’m talking about media features, I mean the bit between parenthesis in a media query, like (min-width: 600px). It checks if the available width in the browser is at least 600 pixels wide and if so, it applies the styles inside the media query. You then use this to make your page adapt to the available width: The medium determines and your code adapts.
This is easy enough to reason about when it’s clear you’re dealing with device characteristics: the screen dimensions are the screen dimensions and the only time the orientation changes is when the user rotates their device.
It gets a little more confusing when you move on to user preferences, like the prefers-color-scheme media feature. That checks if the user had set a preference for light or dark mode in their OS, and you can use it to adapt your page to the user’s preference.
Your site can have a dark mode or a light mode, but the user’s preference isn’t going to change if you don’t offer one or the other.
Enter “overflow”The “overflow” property in CSS lets you control how an element should handle overflowing content, by clipping it, hiding it, showing a scrollbar or just showing it outside of the element. It’s a CSS property, so you as the developer can change it.
The overflow media feature (or rather, the feature split out into both directions: overflow-block and overflow-inline) has the same name, and does something totally different.
Media features say something about the device, and the overflow media feature says something about how the device handles overflowing. It doesn’t say anything about if the page currently is overflowing, just how it would handle overflowing.
Overflow can be used to check how the “device”, or rather the medium in this case, handles overflowing content. On a screen, in most browsers, overflow is going to be “scroll”: If the content overflows, the device deals with that by letting you scroll. But when your medium is print overflow-block is going to evaluate to “paged”. Paper doesn’t scroll, it will continue the content on the next printed page instead.
So that’s essentially what overflow can do. It tells you if your page is being shown in a situation where, if there is overflowing content, it is scrolled, paged or clipped. This holds regardless of whether your page actually has overflowing content or not.
Why is this important?Media features are about the medium, not about the page. Keeping that in mind makes things easier to reason about. If you’re trying to use the overflow media feature to check if your page has overflowing content, you’re going to be disappointed. It’s not going to tell you that. It’s going to tell you how the medium would handle it if you did.
In the future, I’ll have liedAn exciting upcoming API is the web preferences API. The web preferences API provides a way for developers to (for the user) set preferences for their site that can then override the user’s OS preferences.
This is a way for developers to offer (for example) a light mode/dark mode choice regardless of what they have set on an OS level. Currently to do this, you need to duplicate all your styling: once for inside the media query, and once for your custom implementation, behind a class for example. With the web preferences API your custom implementation will also trigger the media query. You’ll only need to write your styling once.
The web preferences API is still in development, but you can play around with it in Polypane, or other Chromiums with experimental features turned on.
The post Your page can’t change media features first appeared on Kilian Valkhof.
I've written before about the problems you can run into with CSS nesting (keep in mind that article uses an older syntax but the point still stands) and the question that @ChallengeCSS tweeted out today made me realize there's actually a few more gotcha's. Here's what they tweeted: Everyone is exited about CSS Nesting but […]
The post The gotchas of CSS Nesting first appeared on Kilian Valkhof.
Most developers prefer to keep all their CSS custom properties in one place, and a pattern that has emerged in recent years is to put those on :root, a pseudo-element that targets the topmost element in your document (so that's always <html> on web pages). But just because they're in one place and in the topmost element, it doesn't mean they're global.
I first encountered this issue with ::backdrop: Backdrop doesn't inherit from anywhere but after a recent rendering engine update to Polypane I noticed that all my custom selection colors (also powered by CSS custom properties) suddenly stopped working.
Turns out, ::selection is also not supposed to inherit styles, and Chromium 111+ is running an experiment to see what effect changing that has. Polypane runs with experimental features turned on, and so my selection styles became broken.
This is going to catch a lot of people off-guard because I, like many others, expect CSS Custom properties defined on :root to just be available everywhere.
So if :root isn't global, what is? Well, the jury's still out.
Discussions are happening in this GitHub issue: Custom properties on :root with a few options being discussed:
:root special.:document pseudo-element that does propagate custom properties.@global, @root or @document that you could define custom properties in.::selection etc inherit from their originating element (e.g. "their parent").That last item would solve both the problems people run into (it not inheriting, and it potentially inheriting directly from :root so you can't overwrite custom properties in the cascade). I hope spec writers choose to do this regardless.
Specifically, I want/expect this to work:
p { --selection-bg: #0f0; &::selection { background: var(--selection-bg); }}
When it comes to "a place to store global variables" I have no strong opinion, though I think it's interesting to keep in mind that in JavaScript there is now window, global and globalThis because the naming across contexts didn't work.
In that light, :document or @document seem potentially problematic. For that reason, I like @global or :global (I haven't actually seen global as a pseudo-element suggested yet, but it seems to be closest to how people expect things to work now).
In the mean time, you can use the suggestion I made in my ::backdrop post and replace :root with :is(:root, ::backdrop, ::selection). Sorry about that.
The post :root isn’t global first appeared on Kilian Valkhof.
There is a JavaScript pattern that I enjoy using that I don’t see a lot around the web, so I figured it would be worth sharing.
When you have a piece of business logic, frequently that depends on a a certain value being true. An if statement:
if ( status === 'active' ) { … }
This is easy to parse for me and I can quickly see what it does. What often ends up happening though is that the business logic gets a second possibility, for example status being active or status being trialing:
if ( status === 'active' || status === 'trialing') { … }
This is still relatively easy to read but there’s repetition with ‘status’ and I always need a second to think about the difference between || and && to understand the behavior. So whenever I move from checking from one value to more than one, I switch to a different pattern:
if (['active', 'trialing'].includes(status)) { … }
I make an array of all possible values and then use Array.includes() to check if the status is contained in that array.
This pattern comfortably grows to many items and can also more easily be read aloud, helping understanding.
There is no repetition so as a small bonus it’s shorter. It has also helped me learn the difference between includes, contains and has.
Partial string matchingI get a lot of mileage out of the above pattern, but it only works when you’re matching the full string. Sometimes you need to check just the beginning or the end of a string and then .includes() won’t cut it because it only accepts values, not a function.
We don’t want to go back to multiple checks and the repetition that gives so if we need to check for a part of the string we need to change the function we use:
['http://', 'https://', 'file://', 'www.'].some(s => clipboard.startsWith(s)) { … }
Array.some() takes a function and returns a Boolean. It’s a little longer but we’re still not repeating ourselves. A nice benefit is that like includes() it will stop evaluating when it returns true, so we usually don’t have to loop over all the elements.
In the examples above I inlined the array but of course you can also store it in a global variable. That gives you the additional benefit of only instantiating a single array that you can reuse and that lets you update many checks in one go, should the business requirements change.
As I said, I get a lot of use out of this pattern. I hope this helps you recognize when it’ll be useful in your code in the future!
The post A small JavaScript pattern I enjoy using first appeared on Kilian Valkhof.
The prefers-contrast media query indicates whether someone prefers more or less contrast within the boundaries of your sites design. At least, that’s what I thought it meant, and it’s also how macOS seems to implement it with their ‘increase contrast’ accessibility feature. This is in contrast to the forced-colors media query, which overwrites all your styles.
To me it was clear that they served different purposes: one was to indicate a preference for an implemented design, just with more (or less) contrast, the other wanted 100% certainty that their colors were respected. Clear difference, clear implementation.
Except that turned out to be wrong.
While macOS sees prefers-contrast as a discrete thing, the spec (and Windows) intricately links it to forced-colors. There, prefers-contrast:more matches when forced-colors with a high contrast theme is active, and prefers-contrast: custom is active with a contrast theme that has anything other than a full black or white background.
So now I’m left wondering: What on earth do spec makers expect website builders to do with prefers-contrast? If forced-colors already overwrites all the colors, what contrast is there left for us to change?
prefers-contrast is a useless media query, and I don't understand why.
This isn’t the first time I’ve voiced concerns about prefers-contrast: earlier versions of the spec had a forced value that would match only when forced-colors was active. I thought this was a really dumb idea, wrote about it and to my surprise, the forced value got removed from the spec. Victory!
…Except they put it back as custom and apparently retooled the entire media query to match with forced-colors: active.
Worse still, the spec only mentions this in the forced-colors section, while the prefers contrast section only mentions prefers-contrast: custom matching when forced-colors: active matches. Under forced colors however, this is what the latest version of the spec says:
In addition to forced-colors: active, the user agent must also match one of prefers-contrast: more or prefers-contrast: less if it can determine that the forced color palette chosen by the user has a particularly high or low contrast, and must make prefers-contrast: custom match otherwise.
Similarly, if the forced color palette chosen by the user fits within one of the color schemes described by prefers-color-scheme, the corresponding value must also match.
Contrast this to what the version before it said:
The UA will provide the color palette to authors through the CSS system color keywords and, if appropriate, trigger the appropriate value of prefers-color-scheme so that authors can adapt the page.
That's a whole new section essentially fusing prefers-contrast to forced-colors.
Coupling forced-colors and prefers-contrast like this completely breaks the ‘contract’ that the prefers-* prefix gives: a user has preference and it’s up to you to implement it. This is in contrast to other media queries, like width and, indeed, forced-colors, that tell us that something is a more intrinsic state of the device being used to access your site.
Prefers-* in media queries is no longer something you can depend upon, and CSS is a little bit less explainable and a little less consistent.
Why do this?I have no idea why they decided this was a good idea. Maybe the spec makers are confused by the name of ‘contrast themes’ on Windows and decided that contrast is contrast and no further research was needed?
I also have no any idea what to do with prefers contrast. It exists, and there is literally no reason to use it on its own.
This is doubly annoying for macOS, which has a very clear implementation for prefers-contrast: more. If you want to adapt your design for macOS, you can no longer use just that. You need to check if prefers-contrast: more is active, and if forced-colors isn’t:
@media (prefer-contrast: more) and (forced-colors: none) { /* Only now can you apply styling for the macOS implementation */}
No one is going to do that, and the spec makers know this because "adoption being low" is a common argument made by the CSS working group against any new media queries (like prefers-reduced-complexity, which is also tacked onto prefers-contrast by using it without a value). Usage being low is a great way to stop any discussion dead in the water, and is far from consistently applied throughout the specs being written.
So that leaves me with this: I no longer understand prefers-contrast. I can’t explain why you would use it, I don’t know who it’s for or what developers are expected to do with it. Do you?
The post I no longer understand prefers-contrast first appeared on Kilian Valkhof.
Earlier this month I was implementing a lightbox for devtoolstips.org using <dialog>. I'll be writing about that soon but you can find the implementation in that link, it's remarkable how little code you need. While styling, I made use of the CSS custom properties that where already defined in the CSS to style the dialog and it's backdrop. Or so I thought.
For some reason, the color of the backdrop wasn't what I expected, even though devtools picked up the right css var being set. It was just that the CSS var was not define. This puzzled me because it was clearly defined earlier in the CSS under the :root selector. So why couldn't devtools find it?
Turns out ::backdrop doesn't inherit from anywhere. It says so clearly in the spec:
"It does not inherit from any element and is not inherited from."
And honestly, that's pretty annoying. You'll either have to duplicate your vars in a specific declaration for ::backdrop, or add ::backdrop to your :root declaration containing all your CSS vars:
:is(:root, ::backdrop) { --my-var-1: #fff; --my-var-2: #000;}
If you use :root only to set CSS vars this isn't that much of an issue, but since it targets the html element anyway, I usually also add my page styling straight away.
Both the ::before and ::after pseudo elements behaved like this in the past though those got updated, and I'm not sure why the same hasn't been done for ::backdrop, it seems like an oversight.
In any case, Florens came up with the idea of introducing a :globalThis in CSS, similar to globalThis in JavaScript, which just always refers to the global environment, be it window, global or something else. That would be a great solution for the use case of CSS custom properties that you just want available throughout your CSS. We can dream.
Anyway, now you know to look out for this situation.
Spread the wordFeel free to share this tweet or toot to tell other people.
TIL that ::backdrop does not inherit from anywhere, which means CSS custom properties added to :root won't work for it.
The spec: https://t.co/YHstFAjQc1 pic.twitter.com/w1d8tEwUyi
— Kilian Valkhof (@kilianvalkhof) January 5, 2023
The post ::backdrop doesn’t inherit from anywhere first appeared on Kilian Valkhof.
Last Friday I went on the Syntax.fm Supper Club podcast to chat with Scott and Wes about everything Polypane. We go pretty deep into some of the features and in hindsight it’s funny how most of it boils down to “I needed this feature so I built it”. I had a great time geeking out about it so thank you Scott and Wes for having me!
You can find the episode and show notes here: Supper Club × Polypane with Kilian Valkhof. Fingers crossed someone can help me and Scott out with my “Sick Pick” ;)
The post I was on the Syntax.fm podcast to talk about Polypane first appeared on Kilian Valkhof.
Sometimes we want something to be true so badly, we ignore all the red flags. I had only spoken at this big of a conference once, and that was mostly by accident. So when my CFP got accepted to Modern Frontends, I was elated. A huge conference, in London, surrounded by amazing speakers. As you’ve […]
The post My experience at Modern Frontends first appeared on Kilian Valkhof.
For an article I was writing I wanted to create a quick screenshot of one of the Rotor screens that Voiceover on macOS shows. I couldn't because when you have VoiceOver active the screenshot shortcuts (cmd + shift + 3/4) no longer work because they're captured by VoiceOver instead. If you also have this problem, […]
The post Screenshotting VoiceOver on macOS first appeared on Kilian Valkhof.
At the Fronteers conference, Manuel during his presentation did an exercise on building HTML that seemed fairly straightforward. On the site of Max Böck there's a thing you can click to open up a theme selector. What's that thing? Of course, it's a button! Because it opens the theme selector at the top of the […]
The post When going somewhere does a thing: on links and buttons first appeared on Kilian Valkhof.
This morning Kitty Giraudel tweeted about an imaginary media query that would indicate right- or left-handedness and it made me imagine a future where sites can register support for one or more media features through a browser API, and the browser would offer these options in the UI. Two years ago I requested something similar […]
The post On better browsers: arbitrary media queries and browser UIs first appeared on Kilian Valkhof.
You probably know overflow: hidden, overflow: scroll and overflow: auto, but do you know overflow: clip? It's a relatively new value for the overflow property, and with Safari 16 being released later this year all evergreen browsers will support it. So what does it do? Before diving into clip, lets quickly go over what overflow […]
The post Do you know about overflow: clip? first appeared on Kilian Valkhof.
We've had inputs with the number type broadly available in browsers for about 8 years now. These inputs show a little rocker and can be used for, you guessed it, numerical input. But not every input that contains numbers should have an input type number. What makes a number input useful? By telling the browser […]
The post Are you sure that’s a number input? first appeared on Kilian Valkhof.
On the Frontend horse Livestream (Which I highly recommend you subscribe to!) I joined Alex Trost to take a look at the Frontend.horse site to add support for the many different user preference media queries that exist now: prefers-color-scheme, prefers-reduced-motion, prefers-reduced-data, prefers-contrast and forced-colors. We go into what each of the media queries does and […]
The post Digging Deep into Media Queries with Alex Trost of Frontend.horse first appeared on Kilian Valkhof.
With scroll-behavior: smooth in your CSS you can tell browsers to animate scrolling to different parts of your site, for example when linking to an ID on a page. The javascript scrollTo API has a behavior option that lets you turn on smooth scrolling for one specific scroll regardless of the CSS being set or […]
The post Preventing smooth scrolling with JavaScript first appeared on Kilian Valkhof.
CSS Specificity is usually written out as [a,b,c] for ID’s, classes and elements respectively. Even a single ID is more specific than any number of classes or elements, so it’s displayed as an array and can’t really be fitted into a single number. How do you compare two selectors to decide which has the highest […]
The post Comparing CSS Specificity values first appeared on Kilian Valkhof.
I don’t get to work on a lot of new sites nowadays, but I recently got the opportunity to set one up from scratch. For most sites I built when I was still running an agency, I would use some form of CSS Reset, most often Normalize.css, but I figured that this time round I […]
The post Your CSS reset needs text-size-adjust (probably) first appeared on Kilian Valkhof.
Last week, I got tagged twice in a Twitter thread about the new APCA color contrast algorithm, asking my opinion and when it was gonna appear in Polypane (it will). APCA has a lot of developers and designers excited, because its a much more thorough algorithm for color contrast compared to the algorithm currently in […]
The post WCAG 2 is what we have first appeared on Kilian Valkhof.
I recently sat down with the folks at Devtools.fm to talk about my experiences as an indie developer building Polypane and Superposition, my experience working with Electron and my thoughts on the framework, and on FixA11y, the browser extension I’m building in my spare time. Listen to it below: For the shownotes, transcription and Youtube […]
The post Devtools.fm podcast recording on Polypane, Electron, Superposition first appeared on Kilian Valkhof.
Native CSS nesting is coming to browsers soon. With nesting, that you might be familiar with from Sass or Less, you can greatly cut down on writing repetitive selectors. But you can also really work yourself into a corner if you’re not careful. This is an overview of how you can already use it today, […]
The post CSS Nesting, specificity and you first appeared on Kilian Valkhof.
Recently I needed a way to detect support for a media query in CSS and Javascript. To detect if a browser supports a certain CSS feature, you can use @supports () { ... }, but that doesn’t work for media queries. In this article I’ll show you how you can detect support for media queries […]
The post Detecting media query support in CSS and JavaScript first appeared on Kilian Valkhof.
The upcoming “prefers-reduced-data” media query will make your site more accessible in the “more people can now enter the building” meaning of accessibility. In this recording of my talk given at Shortstack conference you will learn strategies to start implementing this feature now and make your site available to even more people. Creating websites with […]
The post Increasing access to your website with “prefers-reduced-data” first appeared on Kilian Valkhof.
Insufficient text contrast is the most common accessibility issue on websites today. According to the WebAIM Million report for 2021, 86.4% of home pages world wide have low contrast text. What’s worse, this number has been increasing the past three years. In Polypane, I’ve made it really easy to fix these color contrast issues, with […]
The post Fixing contrast issues, on your own site and elsewhere first appeared on Kilian Valkhof.
For a while now I’ve been telling people that I want Polypane to be prescriptive, not descriptive. In this article I want to expand on that and explain what I mean when I say “prescriptive”.
I usually explain it like this: there is no shortage of tooling that will tell you everything you do wrong when building sites (in fact, some even warn you that they may hurt your feelings!) but I want to have tooling that tells me what I should be doing instead, and how to fix the issues it found. That’s what I mean with prescriptive software.
If you prefer, you can also call it opinionated software and that’s fine as well. I think software should be opinionated. Throwing everything in a huge settings panel or configuration file and calling it “choice” or “not imposing your preferences” is a product development failure.
That’s a bit harsh, sure. But you wouldn’t hire a consultant that only tells you what’s wrong but not how to improve it. Similarly, software you “hired” for a specific task should do the same.
You don’t know what you don’t know As developers we need to keep a lot of different things in mind. Just a few of the things a front-end developer needs to keep in mind when it comes to CSS beyond mastery of the language itself:
Cross-browser differences, color contrast accessibility, caching strategies, loading strategies, loading performance, motion design, typography, graceful degradation.
Those are just off the top of my head, I’m sure I can come up with more. And that’s just one aspect. This leaves out HTML and JavaScript, Interaction paradigms between different devices, SEO, Usability et cetera. And all of those have their own list of things to keep in mind.
In short, being a front-end developer means you need to know a lot about a lot. That’s not a complaint. In fact it’s one of the things that make front-end so exciting to me.
But every developer has gaps.
I don’t think we should expect developers to be experts in all areas and ideally your team covers all bases between team members, but that’s not always the case.
You can either pretend and write software that tells devs something’s wrong and expects them to know how to fix it, or you can tell them what to fix and how to fix it, so they can get on with their work.
Help devs where they are To expand on that point: because devs already have so much on their plate, the choice they have to make is either “stop working and learn about this new topic enough to be able to fix whatever issue came up” and “continue working on the thing I do know” and guess what, they’re gonna continue working. Devs usually are evaluated on the work getting done, not on what they learned along the way.
Prescriptive software helps devs where they are while they’re doing the work. You avoid context switches and you avoid training devs to ignore the very issues your software tries to help with.
The choice is between your rules and no rules If you’re a tool developer you’re so much more aware than most devs that there’s nuance to whatever you’re developing software for. There’s more than one way to skin a cat!
But anyone that has ever implemented ESLint in their organization knows what a shitshow it is. Endless debates about each and every potential configuration. “Yes we want to use the AirBnB config, but we really need to change the semicolon configuration, and eqeqeq is really not going to work for us so…” Cue discussion.
Anyone that has ever implemented Prettier in their organizations knows that it went a whole lot smoother. Prettier has formatting rules. They get applied. End of story.
ESLint is a blank slate. Prettier is opinionated.
ESLint won’t do anything until you tell it to, but Prettier has its own rules and while you can configure it, you don’t have to. It’s going to impose its own standards if you don’t.
Prettier has one big choice: “use it, or don’t use it”.
There is no big choice for ESlint. There’s a hundred different small choices. And while devs like their discussions, after 75 of them you’re just done with it. ESLint implementations often stagnate, or adherence drops because there never really was consensus but people just got tired and acquiesce.
If you’re a tool developer you’re intimately aware of the nuance in your choices. Your audience probably isn’t. (And that’s fine! They already know a lot of other things). Pushing that choice to your user will change the question from “nuanced option A or nuanced option B” to “should this be dealt with or not”. The no-deal choice is infinitely easier to make, nuance be damned.
So if you’re a tool developer thinking “who am I to decide?” then consider this: The choice is between following your advice, and doing nothing. They hired your software to do a job.
What it looks like in practice A very clear example of prescriptive versus descriptive is the Polypane contrast checker.
A year ago, I was working on global Corona checking project together with a ton of other volunteers, using Polypane to make sure the project was as accessible as possible. One of the things I was checking was color contrasts. I got frustrated that Polypane was just pointing and saying “Hey that’s wrong”. If I could calculate which color didn’t have enough contrast, surely I could calculate how much darker or lighter it should be to have enough contrast.
Polypane identifying a contrast issues and providing a color to use insteadhttps://kilianvalkhof.com/wp-content/uploads/copy-color.mp4 So I implemented that the next day and it made a huge difference. I could just stay in flow in my browser and text editor, rather than opening a design tool to pick colors and an online contrast checker to test those colors.
The tool gave me the solution for the issue it encountered, and I could just get on with my work without leaving my current context. It was prescriptive in what it thought should be done.
All I needed to do was follow it.
The post Prescriptive software is better than descriptive software first appeared on Kilian Valkhof.