A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.html 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang="fr">
  4. <!-- Has to be within the first 1024 bytes, hence before the `title` element
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset="utf-8">
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name="viewport" content="width=device-width,initial-scale=1">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>New HTML Control Lands in Safari (archive) — David Larlet</title>
  13. <meta name="description" content="Publication mise en cache pour en conserver une trace.">
  14. <!-- That good ol' feed, subscribe :). -->
  15. <link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/">
  16. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  17. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png">
  18. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png">
  19. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png">
  20. <link rel="manifest" href="/static/david/icons2/site.webmanifest">
  21. <link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c">
  22. <link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
  23. <meta name="msapplication-TileColor" content="#f7f7f7">
  24. <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
  25. <meta name="theme-color" content="#f7f7f7" media="(prefers-color-scheme: light)">
  26. <meta name="theme-color" content="#272727" media="(prefers-color-scheme: dark)">
  27. <!-- Is that even respected? Retrospectively? What a shAItshow…
  28. https://neil-clarke.com/block-the-bots-that-feed-ai-models-by-scraping-your-website/ -->
  29. <meta name="robots" content="noai, noimageai">
  30. <!-- Documented, feel free to shoot an email. -->
  31. <link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
  32. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  33. <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>
  34. <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>
  35. <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>
  36. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  37. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  38. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  39. <script>
  40. function toggleTheme(themeName) {
  41. document.documentElement.classList.toggle(
  42. 'forced-dark',
  43. themeName === 'dark'
  44. )
  45. document.documentElement.classList.toggle(
  46. 'forced-light',
  47. themeName === 'light'
  48. )
  49. }
  50. const selectedTheme = localStorage.getItem('theme')
  51. if (selectedTheme !== 'undefined') {
  52. toggleTheme(selectedTheme)
  53. }
  54. </script>
  55. <meta name="robots" content="noindex, nofollow">
  56. <meta content="origin-when-cross-origin" name="referrer">
  57. <!-- Canonical URL for SEO purposes -->
  58. <link rel="canonical" href="https://alvaromontoro.com/blog/68049/new-toggle-switch-lands-in-safari">
  59. <body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">
  60. <article>
  61. <header>
  62. <h1>New HTML Control Lands in Safari</h1>
  63. </header>
  64. <nav>
  65. <p class="center">
  66. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  67. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  68. </svg> Accueil</a> •
  69. <a href="https://alvaromontoro.com/blog/68049/new-toggle-switch-lands-in-safari" title="Lien vers le contenu original">Source originale</a>
  70. <br>
  71. Mis en cache le 2024-01-28
  72. </p>
  73. </nav>
  74. <hr>
  75. <p>Native toggle switches landed in one browser. Safari introduced this new HTML control as part of the <a href="https://webkit.org/blog/14885/release-notes-for-safari-technology-preview-185/">Safari Technology Preview 185 release</a> and then <a href="https://developer.apple.com/documentation/safari-technology-preview-release-notes/stp-release-186#New-Features">expanded it in the 186 release</a>.</p>
  76. <p>Creating a semi-native HTML toggle switch component is quite <em>hacky</em>. It involves using a checkbox, adding the "switch" ARIA role, removing its appearance with CSS, and adding styles to make it look like the classic switch or however we want —<a href="https://codepen.io/collection/aMPYMo">check this toggles collection</a>.</p>
  77. <p>And even doing all that, some things cannot be avoided. For example, developers can still set the indeterminate attribute into the base checkbox using JavaScript, which would make the toggle switch invalid.</p>
  78. <p>A native solution would prevent these problems and provide a better experience. Even when it's only an experiment on one browser and has some issues (as we'll describe soon), this attempt is welcomed, and I hope it gets traction.</p>
  79. <h2 id="how-does-it-work">
  80. How does it work?
  81. </h2>
  82. <p>Safari's implementation is as straightforward as it can be. Just add the <code>switch</code> attribute to a regular checkbox, and you'll be done!</p>
  83. <div class="highlight js-code-highlight">
  84. <pre class="highlight html"><code><span class="c">&lt;!-- this will render a checkbox --&gt;</span>
  85. <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"checkbox"</span> <span class="nt">/&gt;</span>
  86. <span class="c">&lt;!-- this will render a toggle switch --&gt;</span>
  87. <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"checkbox"</span> <span class="na">switch</span> <span class="nt">/&gt;</span>
  88. </code></pre>
  89. </div>
  90. <p>It's really that simple. There is no need for additional CSS, JS, or anything complicated, and the browser will take care of the rest, including out-of-the-box interactions and styles.</p>
  91. <figure>
  92. <p>
  93. <img src="https://alvaromontoro.com/images/blog/safari-toggle-1.webp" alt="Just add the switch attribute to a checkbox. There is some HTML code in a box: With arrows pointing to checkboxes (from the first line of code) and toggle switches (from the second line of code)" loading="lazy">
  94. </p>
  95. <figcaption>Just add the switch attribute to a checkbox!</figcaption>
  96. </figure>
  97. <p>The default visualization resembles the toggle switch of iOS, but as part of the feature, Safari includes two pseudo-elements <code>::track</code> and <code>::thumb</code> that make it easy to update the look and feel of the control. <a href="https://twitter.com/yisibl/status/1737739579418141116">@yisibl added a few examples of how they work</a> (you'll need Safari Technology Preview 185 or above to see them).</p>
  98. <h3 id="thoughts-on-this-syntax">
  99. Thoughts on this syntax
  100. </h3>
  101. <p>Having a <code>switch</code> attribute in the checkbox makes it easy, but it also may be misleading as it looks like it equates toggle switches to checkboxes. While this may seem logical to many, it is unfair to the switch control, which becomes a "sub-control" <em>tightly coupled</em> to the checkbox.</p>
  102. <p>They are not the same component: they have different values (checked/unchecked vs. on/off), one of them has an indeterminate state (checkbox, although it's not technically a state), and one is supposed to have an action associated on change (switch).</p>
  103. <p>So why couple them? Just because they look the same or behave in a "similar way"? That's wrong. Following that logic, we shouldn't have inputs of the type <code>number</code>, <code>date</code>, <code>password</code>, <code>email</code>, <code>search</code>... because we already have the text input to handle all of them.<br>
  104. </p>
  105. <div class="highlight js-code-highlight">
  106. <pre class="highlight html"><code><span class="c">&lt;!-- We don't do this --&gt;</span>
  107. <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">number</span> <span class="nt">/&gt;</span>
  108. <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">date</span> <span class="nt">/&gt;</span>
  109. <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">password</span> <span class="nt">/&gt;</span>
  110. <span class="c">&lt;!-- So why do this? --&gt;</span>
  111. <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"checkbox"</span> <span class="na">switch</span> <span class="nt">/&gt;</span>
  112. <span class="c">&lt;!-- Wouldn't this make more sense? --&gt;</span>
  113. <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"switch"</span> <span class="nt">/&gt;</span>
  114. </code></pre>
  115. </div>
  116. <p>In my opinion, a toggle switch should be its own type of input. And not a "sub-type" or "sub-control" dependent on the checkbox.</p>
  117. <h2 id="pros-and-cons">
  118. Pros and cons
  119. </h2>
  120. <p>As with every technology —especially a new one—, Safari's toggle switch has good and bad things. Here are some pros and cons of this component.</p>
  121. <h3 id="pros">
  122. Pros
  123. </h3>
  124. <ul>
  125. <li>
  126. <strong>Provides native support for the control</strong>: no need for hacky or complex solutions that require too much code and may be error-prone.</li>
  127. <li>
  128. <strong>Straightforward interface</strong>: easy to implement (add an attribute!) and easy-to-follow new pseudo-elements (<code>::track</code> and <code>::thumb</code>).</li>
  129. <li>
  130. <strong>Easy styling in CSS</strong>: with the introduction of two pseudo-elements (<code>::track</code> and <code>::thumb</code>), changing the styles of the components would become simple.</li>
  131. <li>
  132. <strong>Accessibility out of the box</strong>: the control is announced correctly by the Voice Over screen reader without needing extra ARIA labels or roles. <a href="https://adrianroselli.com/2021/10/switch-role-support.html#Update02">Adrian Roselli ran tests and shared the results</a> over time.</li>
  133. </ul>
  134. <p>
  135. <img src="https://alvaromontoro.com/images/blog/safari-toggle-2.webp" alt="Summary of pros in image format" loading="lazy">
  136. </p>
  137. <h3 id="cons">
  138. Cons
  139. </h3>
  140. <ul>
  141. <li>
  142. <strong>Non-standard feature</strong>: this is a Safari proposal and hasn't been adopted by other browsers or taken into the standard.</li>
  143. <li>
  144. <strong>Safari-only feature</strong>: as it is a new suggestion by Safari, it will work only on Safari and only in the Technology Preview version of the browser (from version 185).</li>
  145. <li>
  146. <strong>Default styles are <em>sketchy</em></strong>: the toggle looks like the regular iOS toggle, but <a href="https://front-end.social/@alvaromontoro/111763578202895753">it presents some issues when scaling and applying zoom</a>.</li>
  147. </ul>
  148. <p>Considering those cons, it is safe to say that <strong>this is not a production-ready feature</strong>. At least not yet. It could be an excellent case for progressive enhancement approaches (maybe the reason why they made it an attribute instead of a full type: falling back into a checkbox if not supported), but waiting to see how the component moves forward is better. It is still too early.</p>
  149. <p>
  150. <img src="https://alvaromontoro.com/images/blog/safari-toggle-3.webp" alt="Summary of cons in image format" loading="lazy">
  151. </p>
  152. <h2 id="final-thoughts">
  153. Final thoughts
  154. </h2>
  155. <p>Toggle switches are a great addition to a browser, and the Safari team did nicely adding it to the Technology Preview version. Still, the implementation feels a bit rushed —maybe Safari is trying to earn brownie points with developers while shaking the "The New IE Browser" label?</p>
  156. <p>One of the things that is more counterintuitive is the used syntax. Having a <code>switch</code> attribute in the checkbox makes it easy, but it also unnecessarily associates both controls and doesn't follow the same notation that other form controls follow. I wouldn't be surprised if this is one thing that changes when —not if— this proposal moves forward. So beware of support and likely changes in the future.</p>
  157. <p>As I said, this is a great addition to the form controls. I hope it triggers a deeper conversation about its addition to the standard. I look forward to what it becomes and the possibility of using it on any browser.</p>
  158. </article>
  159. <hr>
  160. <footer>
  161. <p>
  162. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  163. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  164. </svg> Accueil</a> •
  165. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  166. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use>
  167. </svg> Suivre</a> •
  168. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  169. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use>
  170. </svg> Pro</a> •
  171. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  172. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use>
  173. </svg> Email</a> •
  174. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  175. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use>
  176. </svg> Légal</abbr>
  177. </p>
  178. <template id="theme-selector">
  179. <form>
  180. <fieldset>
  181. <legend><svg class="icon icon-brightness-contrast">
  182. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use>
  183. </svg> Thème</legend>
  184. <label>
  185. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  186. </label>
  187. <label>
  188. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  189. </label>
  190. <label>
  191. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  192. </label>
  193. </fieldset>
  194. </form>
  195. </template>
  196. </footer>
  197. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  198. <script>
  199. function loadThemeForm(templateName) {
  200. const themeSelectorTemplate = document.querySelector(templateName)
  201. const form = themeSelectorTemplate.content.firstElementChild
  202. themeSelectorTemplate.replaceWith(form)
  203. form.addEventListener('change', (e) => {
  204. const chosenColorScheme = e.target.value
  205. localStorage.setItem('theme', chosenColorScheme)
  206. toggleTheme(chosenColorScheme)
  207. })
  208. const selectedTheme = localStorage.getItem('theme')
  209. if (selectedTheme && selectedTheme !== 'undefined') {
  210. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  211. }
  212. }
  213. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  214. window.addEventListener('load', () => {
  215. let hasDarkRules = false
  216. for (const styleSheet of Array.from(document.styleSheets)) {
  217. let mediaRules = []
  218. for (const cssRule of styleSheet.cssRules) {
  219. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  220. continue
  221. }
  222. // WARNING: Safari does not have/supports `conditionText`.
  223. if (cssRule.conditionText) {
  224. if (cssRule.conditionText !== prefersColorSchemeDark) {
  225. continue
  226. }
  227. } else {
  228. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  229. continue
  230. }
  231. }
  232. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  233. }
  234. // WARNING: do not try to insert a Rule to a styleSheet you are
  235. // currently iterating on, otherwise the browser will be stuck
  236. // in a infinite loop…
  237. for (const mediaRule of mediaRules) {
  238. styleSheet.insertRule(mediaRule.cssText)
  239. hasDarkRules = true
  240. }
  241. }
  242. if (hasDarkRules) {
  243. loadThemeForm('#theme-selector')
  244. }
  245. })
  246. </script>
  247. </body>
  248. </html>