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 16KB

3 jaren geleden
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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>
  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>Write-only Twitter (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="#f0f0ea">
  24. <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
  25. <meta name="theme-color" content="#f0f0ea">
  26. <!-- Documented, feel free to shoot an email. -->
  27. <link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
  28. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  29. <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>
  30. <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>
  31. <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>
  32. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  33. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  34. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  35. <script>
  36. function toggleTheme(themeName) {
  37. document.documentElement.classList.toggle(
  38. 'forced-dark',
  39. themeName === 'dark'
  40. )
  41. document.documentElement.classList.toggle(
  42. 'forced-light',
  43. themeName === 'light'
  44. )
  45. }
  46. const selectedTheme = localStorage.getItem('theme')
  47. if (selectedTheme !== 'undefined') {
  48. toggleTheme(selectedTheme)
  49. }
  50. </script>
  51. <meta name="robots" content="noindex, nofollow">
  52. <meta content="origin-when-cross-origin" name="referrer">
  53. <!-- Canonical URL for SEO purposes -->
  54. <link rel="canonical" href="https://laurakalbag.com/write-only-twitter/">
  55. <body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick">
  56. <article>
  57. <header>
  58. <h1>Write-only Twitter</h1>
  59. </header>
  60. <nav>
  61. <p class="center">
  62. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  63. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-home"></use>
  64. </svg> Accueil</a> •
  65. <a href="https://laurakalbag.com/write-only-twitter/" title="Lien vers le contenu original">Source originale</a>
  66. </p>
  67. </nav>
  68. <hr>
  69. <p>A couple of weeks ago, <a href="https://ar.al">Aral</a> asked me if I could write a user stylesheet for web browsers to make Twitter nothing but a compose box.</p>
  70. <p><a href="#how-the-stylesheet-works">Jump straight to how it works</a></p>
  71. <p>I totally get it. <a href="/whats-wrong-with-twitter/">Twitter sucks your time and soul</a>. But sometimes you need to use it to share what you’re working on, or promote events. Essentially, you want to use Twitter but you don’t want it to use you. The way to do this is to hide every part of Twitter’s interface that doesn’t help you compose a tweet, or otherwise likely to distract or derail you.</p>
  72. <h2 id="the-power-of-css-pseudo-classes">The power of CSS pseudo classes</h2>
  73. <p>As part of my work on <a href="https://better.fyi/trackers/">Better’s blocking rules</a>, I sometimes have to hide parts of the page using CSS. Hiding ads isn’t really Better’s purpose, we try to block the tracking and behavioural advertising scripts before they put anything on the page. But occasionally, sites have rolled their own obnoxious first-party targeted ad system that is inseparable from the rest of their site’s functionality. On such occasions, I roll up my sleeves, and get my <a href="https://css-tricks.com/pseudo-class-selectors/">pseudo CSS selectors</a> out to set these elements to <code>display: none</code>. Because, of course, these sites design their HTML and CSS to avoid blockers like Better.</p>
  74. <h3 id="the-problem-with-user-stylesheets">The problem with user stylesheets</h3>
  75. <p>Hiding parts of Twitter’s interface is a similar problem. Luckily, a lot of Twitter’s interface has semantic naming (amongst the gazillion nested <code>div</code>s and robot-generated CSS classes) for accessibility purposes, so it’s simple enough to hook into these elements for a user stylesheet. The problem with user stylesheets is that they’re a blunt instrument, aimed at making global changes across every site you visit. Really useful for making font sizes big on every site you visit, but if you use it to hide any element with the class of “<code>timeline</code>”, chances are you’ll break a lot of websites you visit.</p>
  76. <h3 id="a-solution-to-target-specific-websites">A solution to target specific websites</h3>
  77. <p>My solution was to chain what I suspect are fairly unique element selectors in a likely unique sequence, ensuring that these rules will only apply to twitter.com, even though the stylesheet will be used on every site visited.</p>
  78. <div class="highlight"><pre class="chroma"><code class="language-css" data-lang="css"><span class="c">/* Hide the Home timeline and Explore timeline */</span>
  79. <span class="nt">div</span><span class="o">[</span><span class="nt">data-at-shortcutkeys</span><span class="o">]</span> <span class="nt">header</span><span class="o">[</span><span class="nt">role</span><span class="o">=</span><span class="s2">"banner"</span><span class="o">]</span> <span class="o">+</span> <span class="nt">main</span><span class="o">[</span><span class="nt">role</span><span class="o">=</span><span class="s2">"main"</span><span class="o">]</span> <span class="nt">div</span><span class="o">[</span><span class="nt">aria-label</span><span class="o">=</span><span class="s2">"Timeline: Your Home Timeline"</span><span class="o">],</span>
  80. <span class="nt">div</span><span class="o">[</span><span class="nt">data-at-shortcutkeys</span><span class="o">]</span> <span class="nt">header</span><span class="o">[</span><span class="nt">role</span><span class="o">=</span><span class="s2">"banner"</span><span class="o">]</span> <span class="o">+</span> <span class="nt">main</span><span class="o">[</span><span class="nt">role</span><span class="o">=</span><span class="s2">"main"</span><span class="o">]</span> <span class="nt">div</span><span class="o">[</span><span class="nt">aria-label</span><span class="o">=</span><span class="s2">"Timeline: Explore"</span><span class="o">]</span> <span class="p">{</span>
  81. <span class="k">display</span><span class="p">:</span> <span class="kc">none</span> <span class="cp">!important</span><span class="p">;</span>
  82. <span class="p">}</span>
  83. </code></pre></div>
  84. <p>As you can tell from the selectors I’ve used, it is fragile as anything. As soon as Twitter decides to change the <code>aria-label</code> for its home timeline, the stylesheet will no longer effectively hide the home timeline. But, as with a lot of Better’s blocking rules, this is a balance between using a fragile rule that works against a big corporation that tends to be pretty slow in rolling out changes to its interface.</p>
  85. <p>After a couple of weeks of using this stylesheet in my primary browser and not noticing any issues with other sites, I’m fairly confident in sharing this stylesheet with anyone else who might find it useful.</p>
  86. <h2 id="how-the-stylesheet-works">How the stylesheet works</h2>
  87. <p>I ended up creating two stylesheets, one for Aral’s way of working (<code>write-only.css</code>), and one for my way of working (<code>read-some.css</code>).</p>
  88. <p><a href="https://source.small-tech.org/laura/write-only-twitter/-/blob/master/write-only.css"><code>write-only.css</code></a> is a user stylesheet for the browser that hides absolutely everything except the Home feed compose box on Twitter.</p>
  89. <figure>
  90. <pre><code>&lt;img class="landscape" sizes="(min-width: 1380px) 750px, (min-width: 820px) 719px, (min-width: 740px) calc(-33.33vw + 875px), (min-width: 340px) calc(92.63vw - 39px), calc(100vw - 32px)" srcset="/write-only-twitter/write-only-twitter/social_hu3843e09fa51a0152293fbbf1ad71c1cb_33928_300x0_resize_mitchellnetravali_2.png 300w,/write-only-twitter/write-only-twitter/social_hu3843e09fa51a0152293fbbf1ad71c1cb_33928_500x0_resize_mitchellnetravali_2.png 500w,/write-only-twitter/write-only-twitter/social_hu3843e09fa51a0152293fbbf1ad71c1cb_33928_800x0_resize_mitchellnetravali_2.png 800w,/write-only-twitter/write-only-twitter/social.png 1118w" src="social.png" alt="Web page showing just Twitter’s compose box, no other parts of Twitter’s interface."&gt;
  91. &lt;figcaption&gt;
  92. &lt;p&gt;&lt;code&gt;write-only.css&lt;/code&gt; in action.&lt;/p&gt;
  93. &lt;/figcaption&gt;
  94. </code></pre>
  95. </figure>
  96. <p>My Twitter use varies, particularly as I sometimes use it for Better support, so I need to be able to access a bit more of Twitter’s interface.</p>
  97. <p><a href=""><code>read-some.css</code></a> is a user stylesheet for the browser that hides:</p>
  98. <ul>
  99. <li>Home timeline</li>
  100. <li>Explore timeline</li>
  101. <li>List timelines</li>
  102. </ul>
  103. <p>but keeps:</p>
  104. <ul>
  105. <li>Mentions</li>
  106. <li>Messages</li>
  107. <li>Settings etc</li>
  108. </ul>
  109. <p>And let me tell you, having this stylesheet on my desktop Safari for the last couple of weeks has made a huge difference. Now I can check our @mentions without getting further distracted. Even when my muscle memory types “twitter.com” when I’m procrastinating or seeking distraction, the page loads so minimally, I take one look at it and close the tab. It no longer appears in my “Frequently Visited” sites!</p>
  110. <figure>
  111. <pre><code>&lt;img class="landscape" sizes="(min-width: 1380px) 750px, (min-width: 820px) 719px, (min-width: 740px) calc(-33.33vw + 875px), (min-width: 340px) calc(92.63vw - 39px), calc(100vw - 32px)" srcset="/write-only-twitter/write-only-twitter/read-some_hu1fd5ca1b59b76b36250d12d5d1634087_45368_300x0_resize_mitchellnetravali_2.png 300w,/write-only-twitter/write-only-twitter/read-some_hu1fd5ca1b59b76b36250d12d5d1634087_45368_500x0_resize_mitchellnetravali_2.png 500w,/write-only-twitter/write-only-twitter/read-some_hu1fd5ca1b59b76b36250d12d5d1634087_45368_800x0_resize_mitchellnetravali_2.png 800w,/write-only-twitter/write-only-twitter/read-some.png 1118w" src="read-some.png" alt="Web page showing Twitter’s interface without the timeline of tweets or What’s Happening sidebar."&gt;
  112. &lt;figcaption&gt;
  113. &lt;p&gt;&lt;code&gt;read-some.css&lt;/code&gt; in action.&lt;/p&gt;
  114. &lt;/figcaption&gt;
  115. </code></pre>
  116. </figure>
  117. <h2 id="where-to-find-the-stylesheets">Where to find the stylesheets</h2>
  118. <p>You can <a href="https://source.small-tech.org/laura/write-only-twitter">download the Write-Only Twitter stylesheets and find out more about them on our Small Tech repository</a>. I’ll update them when needed. There’s not instructions for every browser in there, but it shouldn’t be too hard for you to find that information if you need it. Personally I recommend Safari for everyday browsing as you can use <a href="https://better.fyi">Better Blocker</a> to block trackers while you browse 😉</p>
  119. </article>
  120. <hr>
  121. <footer>
  122. <p>
  123. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  124. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-home"></use>
  125. </svg> Accueil</a> •
  126. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  127. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-rss2"></use>
  128. </svg> RSS</a> •
  129. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  130. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-user-tie"></use>
  131. </svg> Pro</a> •
  132. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  133. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-mail"></use>
  134. </svg> Email</a> •
  135. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  136. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-hammer2"></use>
  137. </svg> Légal</abbr>
  138. </p>
  139. <template id="theme-selector">
  140. <form>
  141. <fieldset>
  142. <legend><svg class="icon icon-brightness-contrast">
  143. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-brightness-contrast"></use>
  144. </svg> Thème</legend>
  145. <label>
  146. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  147. </label>
  148. <label>
  149. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  150. </label>
  151. <label>
  152. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  153. </label>
  154. </fieldset>
  155. </form>
  156. </template>
  157. </footer>
  158. <script>
  159. function loadThemeForm(templateName) {
  160. const themeSelectorTemplate = document.querySelector(templateName)
  161. const form = themeSelectorTemplate.content.firstElementChild
  162. themeSelectorTemplate.replaceWith(form)
  163. form.addEventListener('change', (e) => {
  164. const chosenColorScheme = e.target.value
  165. localStorage.setItem('theme', chosenColorScheme)
  166. toggleTheme(chosenColorScheme)
  167. })
  168. const selectedTheme = localStorage.getItem('theme')
  169. if (selectedTheme && selectedTheme !== 'undefined') {
  170. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  171. }
  172. }
  173. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  174. window.addEventListener('load', () => {
  175. let hasDarkRules = false
  176. for (const styleSheet of Array.from(document.styleSheets)) {
  177. let mediaRules = []
  178. for (const cssRule of styleSheet.cssRules) {
  179. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  180. continue
  181. }
  182. // WARNING: Safari does not have/supports `conditionText`.
  183. if (cssRule.conditionText) {
  184. if (cssRule.conditionText !== prefersColorSchemeDark) {
  185. continue
  186. }
  187. } else {
  188. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  189. continue
  190. }
  191. }
  192. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  193. }
  194. // WARNING: do not try to insert a Rule to a styleSheet you are
  195. // currently iterating on, otherwise the browser will be stuck
  196. // in a infinite loop…
  197. for (const mediaRule of mediaRules) {
  198. styleSheet.insertRule(mediaRule.cssText)
  199. hasDarkRules = true
  200. }
  201. }
  202. if (hasDarkRules) {
  203. loadThemeForm('#theme-selector')
  204. }
  205. })
  206. </script>
  207. </body>
  208. </html>