|
|
@@ -0,0 +1,288 @@ |
|
|
|
<!doctype html><!-- This is a valid HTML5 document. --> |
|
|
|
<!-- Screen readers, SEO, extensions and so on. --> |
|
|
|
<html lang="fr"> |
|
|
|
<!-- Has to be within the first 1024 bytes, hence before the `title` element |
|
|
|
See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset --> |
|
|
|
<meta charset="utf-8"> |
|
|
|
<!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 --> |
|
|
|
<!-- The viewport meta is quite crowded and we are responsible for that. |
|
|
|
See: https://codepen.io/tigt/post/meta-viewport-for-2015 --> |
|
|
|
<meta name="viewport" content="width=device-width,initial-scale=1"> |
|
|
|
<!-- Required to make a valid HTML5 document. --> |
|
|
|
<title>You can't capture the nuance of my form fields (archive) — David Larlet</title> |
|
|
|
<meta name="description" content="Publication mise en cache pour en conserver une trace."> |
|
|
|
<!-- That good ol' feed, subscribe :). --> |
|
|
|
<link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/"> |
|
|
|
<!-- Generated from https://realfavicongenerator.net/ such a mess. --> |
|
|
|
<link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png"> |
|
|
|
<link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png"> |
|
|
|
<link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png"> |
|
|
|
<link rel="manifest" href="/static/david/icons2/site.webmanifest"> |
|
|
|
<link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c"> |
|
|
|
<link rel="shortcut icon" href="/static/david/icons2/favicon.ico"> |
|
|
|
<meta name="msapplication-TileColor" content="#f7f7f7"> |
|
|
|
<meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml"> |
|
|
|
<meta name="theme-color" content="#f7f7f7" media="(prefers-color-scheme: light)"> |
|
|
|
<meta name="theme-color" content="#272727" media="(prefers-color-scheme: dark)"> |
|
|
|
<!-- Documented, feel free to shoot an email. --> |
|
|
|
<link rel="stylesheet" href="/static/david/css/style_2021-01-20.css"> |
|
|
|
<!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. --> |
|
|
|
<link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin> |
|
|
|
<link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin> |
|
|
|
<link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin> |
|
|
|
<link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin> |
|
|
|
<link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin> |
|
|
|
<link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin> |
|
|
|
<script> |
|
|
|
function toggleTheme(themeName) { |
|
|
|
document.documentElement.classList.toggle( |
|
|
|
'forced-dark', |
|
|
|
themeName === 'dark' |
|
|
|
) |
|
|
|
document.documentElement.classList.toggle( |
|
|
|
'forced-light', |
|
|
|
themeName === 'light' |
|
|
|
) |
|
|
|
} |
|
|
|
const selectedTheme = localStorage.getItem('theme') |
|
|
|
if (selectedTheme !== 'undefined') { |
|
|
|
toggleTheme(selectedTheme) |
|
|
|
} |
|
|
|
</script> |
|
|
|
|
|
|
|
<meta name="robots" content="noindex, nofollow"> |
|
|
|
<meta content="origin-when-cross-origin" name="referrer"> |
|
|
|
<!-- Canonical URL for SEO purposes --> |
|
|
|
<link rel="canonical" href="https://drewdevault.com/2021/06/27/You-cant-capture-the-nuance.html"> |
|
|
|
|
|
|
|
<body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all"> |
|
|
|
|
|
|
|
|
|
|
|
<article> |
|
|
|
<header> |
|
|
|
<h1>You can't capture the nuance of my form fields</h1> |
|
|
|
</header> |
|
|
|
<nav> |
|
|
|
<p class="center"> |
|
|
|
<a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home"> |
|
|
|
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use> |
|
|
|
</svg> Accueil</a> • |
|
|
|
<a href="https://drewdevault.com/2021/06/27/You-cant-capture-the-nuance.html" title="Lien vers le contenu original">Source originale</a> |
|
|
|
</p> |
|
|
|
</nav> |
|
|
|
<hr> |
|
|
|
<p>Check out this text box:</p> |
|
|
|
<style> |
|
|
|
textarea { |
|
|
|
width: 100%; |
|
|
|
} |
|
|
|
</style> |
|
|
|
<p><textarea rows="10" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false">Consectetur qui consequatur voluptatibus voluptatem sit sint perspiciatis. Eos aspernatur ad laboriosam quam numquam quo. Quia reiciendis illo quo praesentium. Dolor porro et et sit dolorem quisquam totam quae. |
|
|
|
Ea molestias a aspernatur dignissimos suscipit incidunt. Voluptates in vel qui quaerat. Asperiores vel sit rerum est ipsam. Odio aut aut voluptate qui voluptatem. |
|
|
|
Quia consequatur provident fugiat voluptatibus consequatur. Est sunt aspernatur velit. Officiis a dolorum accusantium. Sint est ut inventore.</textarea></p> |
|
|
|
<p>Here are some of the nuances of using this text box on my operating system |
|
|
|
(Linux) and web browser (Firefox):</p> |
|
|
|
<ul> |
|
|
|
<li>Double clicking selects a word, and triple-clicking selects the whole line. If |
|
|
|
I double- or triple-click-and-hold, I can drag the mouse to expand the |
|
|
|
selection word-wise or line-wise, not just character-wise. This works with the |
|
|
|
paragraphs of text in the body of this blog post, too.</li> |
|
|
|
<li>Holding control and pressing right will move move word-wise through the file. |
|
|
|
It always moves to the start or end of the next or prior word, so pressing |
|
|
|
“control+left, control+left, control+right” will end up in a different |
|
|
|
position than “control+left” alone. Adding “shift” to any of these will mutate |
|
|
|
the text selection.</li> |
|
|
|
<li>Clicking any of the whitespace after the end of the text will put the cursor |
|
|
|
after the last character, even if you click to the left of the last character. |
|
|
|
This makes it easy to start appending text to the end.</li> |
|
|
|
<li>Clicking and dragging from any point, I can drag the mouse straight upward, |
|
|
|
exceeding the bounds of the text box or even the entire web browser, to select |
|
|
|
all text from that point to the start of the text box. (Thanks minus for |
|
|
|
mentioning this one)</li> |
|
|
|
<li>Selecting text and middle clicking anywhere will paste the text at the clicked |
|
|
|
location. This uses a separate, distinct clipboard from the one accessed with |
|
|
|
ctrl+c/ctrl+v. I can also use shift+insert to paste text from this secondary |
|
|
|
clipboard (this is called the “primary selection”).</li> |
|
|
|
</ul> |
|
|
|
<p>I rely on all of these nuances when I use form controls in my everyday life. |
|
|
|
This is just for English, by the way. I often type in Japanese, which has an |
|
|
|
entirely alien set of nuances. Here’s what that looks like on Android (mobile is |
|
|
|
another beast entirely, too!):</p> |
|
|
|
<video src="https://l.sr.ht/u274.webm" muted autoplay loop controls> |
|
|
|
If you're seeing this, your browser doesn't support HTML5 video, or webm, idk. |
|
|
|
</video> |
|
|
|
<p>Here’s another control:</p> |
|
|
|
<p><select></p> |
|
|
|
<option>Alabama</option> |
|
|
|
<option>Alaska</option> |
|
|
|
<option>Arizona</option> |
|
|
|
<option>Arkansas</option> |
|
|
|
<option>California</option> |
|
|
|
<option>Colorado</option> |
|
|
|
<option>Connecticut</option> |
|
|
|
<option>Delaware</option> |
|
|
|
<option>Florida</option> |
|
|
|
<option>Georgia</option> |
|
|
|
<option>Hawaii</option> |
|
|
|
<option>Idaho</option> |
|
|
|
<option>Illinois</option> |
|
|
|
<option>Indiana</option> |
|
|
|
<option>Iowa</option> |
|
|
|
<option>Kansas</option> |
|
|
|
<option>Kentucky</option> |
|
|
|
<option>Louisiana</option> |
|
|
|
<option>Maine</option> |
|
|
|
<option>Maryland</option> |
|
|
|
<option>Massachusetts</option> |
|
|
|
<option>Michigan</option> |
|
|
|
<option>Minnesota</option> |
|
|
|
<option>Mississippi</option> |
|
|
|
<option>Missouri</option> |
|
|
|
<option>Montana</option> |
|
|
|
<option>Nebraska</option> |
|
|
|
<option>Nevada</option> |
|
|
|
<option>New Hampshire</option> |
|
|
|
<option>New Jersey</option> |
|
|
|
<option>New Mexico</option> |
|
|
|
<option>New York</option> |
|
|
|
<option>North Carolina</option> |
|
|
|
<option>North Dakota</option> |
|
|
|
<option>Ohio</option> |
|
|
|
<option>Oklahoma</option> |
|
|
|
<option>Oregon</option> |
|
|
|
<option>Pennsylvania</option> |
|
|
|
<option>Rhode Island</option> |
|
|
|
<option>South Carolina</option> |
|
|
|
<option>South Dakota</option> |
|
|
|
<option>Tennessee</option> |
|
|
|
<option>Texas</option> |
|
|
|
<option>Utah</option> |
|
|
|
<option>Vermont</option> |
|
|
|
<option>Virginia</option> |
|
|
|
<option>Washington</option> |
|
|
|
<option>West Virginia</option> |
|
|
|
<option>Wisconsin</option> |
|
|
|
<option>Wyoming</option> |
|
|
|
<p></select></p> |
|
|
|
<p>There’s an invisible edit buffer, so I can type “Pennsylvania” (or just P) to |
|
|
|
select what I want. I can type “New” and then press down to select “New Jersey”. |
|
|
|
If I make a mistake and I’ve kept track of what I’ve typed in my head, I can use |
|
|
|
backspace to make a correction, and it just works. I have lived in both of these |
|
|
|
places, and worked both of these keystrokes into my muscle memory. Filling out a |
|
|
|
form with my address on it and using an input box like this to select my state |
|
|
|
of residence takes me less than a second.</p> |
|
|
|
<p>You cannot capture all of this nuance in a home-grown form control, or even |
|
|
|
anything close to it, but many JavaScript programmers do it anyway. Whenever I |
|
|
|
encounter a custom form control, the time required to complete the form |
|
|
|
increases from under a second to as much as a minute.</p> |
|
|
|
<p>For myself, this is just very annoying. Imagine the same situation if you were |
|
|
|
blind. The standard form inputs work everywhere, and are designed with |
|
|
|
accessibility in mind, so you’re used to them and can easily fill in forms which |
|
|
|
use the standard browser controls. But, when you hit a JavaScript-powered |
|
|
|
organic cage-free non-GMO text box, you’re screwed.</p> |
|
|
|
<p>There are hundreds of little nuances that users learn to use their computers |
|
|
|
efficiently. The exact features a user relies on will vary between operating |
|
|
|
systems, browsers, hardware, natural languages, physical ability, and personal |
|
|
|
preferences and experience. There are dozens of tiny workflows that people |
|
|
|
depend on every day that have never even occurred to you.</p> |
|
|
|
<p>Making a custom form control with JavaScript is going to make life worse for a |
|
|
|
lot of people. Just don’t do it. The browser’s built-in controls are quite |
|
|
|
sufficient.</p> |
|
|
|
</article> |
|
|
|
|
|
|
|
|
|
|
|
<hr> |
|
|
|
|
|
|
|
<footer> |
|
|
|
<p> |
|
|
|
<a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home"> |
|
|
|
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use> |
|
|
|
</svg> Accueil</a> • |
|
|
|
<a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2"> |
|
|
|
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use> |
|
|
|
</svg> Suivre</a> • |
|
|
|
<a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie"> |
|
|
|
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use> |
|
|
|
</svg> Pro</a> • |
|
|
|
<a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail"> |
|
|
|
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use> |
|
|
|
</svg> Email</a> • |
|
|
|
<abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2"> |
|
|
|
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use> |
|
|
|
</svg> Légal</abbr> |
|
|
|
</p> |
|
|
|
<template id="theme-selector"> |
|
|
|
<form> |
|
|
|
<fieldset> |
|
|
|
<legend><svg class="icon icon-brightness-contrast"> |
|
|
|
<use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use> |
|
|
|
</svg> Thème</legend> |
|
|
|
<label> |
|
|
|
<input type="radio" value="auto" name="chosen-color-scheme" checked> Auto |
|
|
|
</label> |
|
|
|
<label> |
|
|
|
<input type="radio" value="dark" name="chosen-color-scheme"> Foncé |
|
|
|
</label> |
|
|
|
<label> |
|
|
|
<input type="radio" value="light" name="chosen-color-scheme"> Clair |
|
|
|
</label> |
|
|
|
</fieldset> |
|
|
|
</form> |
|
|
|
</template> |
|
|
|
</footer> |
|
|
|
<script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script> |
|
|
|
<script> |
|
|
|
function loadThemeForm(templateName) { |
|
|
|
const themeSelectorTemplate = document.querySelector(templateName) |
|
|
|
const form = themeSelectorTemplate.content.firstElementChild |
|
|
|
themeSelectorTemplate.replaceWith(form) |
|
|
|
|
|
|
|
form.addEventListener('change', (e) => { |
|
|
|
const chosenColorScheme = e.target.value |
|
|
|
localStorage.setItem('theme', chosenColorScheme) |
|
|
|
toggleTheme(chosenColorScheme) |
|
|
|
}) |
|
|
|
|
|
|
|
const selectedTheme = localStorage.getItem('theme') |
|
|
|
if (selectedTheme && selectedTheme !== 'undefined') { |
|
|
|
form.querySelector(`[value="${selectedTheme}"]`).checked = true |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const prefersColorSchemeDark = '(prefers-color-scheme: dark)' |
|
|
|
window.addEventListener('load', () => { |
|
|
|
let hasDarkRules = false |
|
|
|
for (const styleSheet of Array.from(document.styleSheets)) { |
|
|
|
let mediaRules = [] |
|
|
|
for (const cssRule of styleSheet.cssRules) { |
|
|
|
if (cssRule.type !== CSSRule.MEDIA_RULE) { |
|
|
|
continue |
|
|
|
} |
|
|
|
// WARNING: Safari does not have/supports `conditionText`. |
|
|
|
if (cssRule.conditionText) { |
|
|
|
if (cssRule.conditionText !== prefersColorSchemeDark) { |
|
|
|
continue |
|
|
|
} |
|
|
|
} else { |
|
|
|
if (cssRule.cssText.startsWith(prefersColorSchemeDark)) { |
|
|
|
continue |
|
|
|
} |
|
|
|
} |
|
|
|
mediaRules = mediaRules.concat(Array.from(cssRule.cssRules)) |
|
|
|
} |
|
|
|
|
|
|
|
// WARNING: do not try to insert a Rule to a styleSheet you are |
|
|
|
// currently iterating on, otherwise the browser will be stuck |
|
|
|
// in a infinite loop… |
|
|
|
for (const mediaRule of mediaRules) { |
|
|
|
styleSheet.insertRule(mediaRule.cssText) |
|
|
|
hasDarkRules = true |
|
|
|
} |
|
|
|
} |
|
|
|
if (hasDarkRules) { |
|
|
|
loadThemeForm('#theme-selector') |
|
|
|
} |
|
|
|
}) |
|
|
|
</script> |
|
|
|
</body> |
|
|
|
</html> |