<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.2">Jekyll</generator><link href="https://graypegg.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://graypegg.com/" rel="alternate" type="text/html" /><updated>2024-01-13T18:14:43+00:00</updated><id>https://graypegg.com/feed.xml</id><title type="html">ailuridæ</title><subtitle>I’m a Typescript developer based out of Montréal.</subtitle><entry><title type="html">The Private Definition of Accessible</title><link href="https://graypegg.com/2023/11/25/the-private-definition-of-accessible.html" rel="alternate" type="text/html" title="The Private Definition of Accessible" /><published>2023-11-25T17:48:00+00:00</published><updated>2023-11-25T17:48:00+00:00</updated><id>https://graypegg.com/2023/11/25/the-private-definition-of-accessible</id><content type="html" xml:base="https://graypegg.com/2023/11/25/the-private-definition-of-accessible.html"><![CDATA[<p>For the following post, I need to make the distinction between two definitions of the word “accessibility”. I’ll be doing this with a little parenthetical after the word. Accessibility (Universal) will refer to the first definition I will give. Accessibility (Developer) will refer to the second definition. If it’s placed in quotes, I’m referring to the string “accessibility” itself.</p>

<h2 id="accessibility-the-word">Accessibility: The Word</h2>

<p>“Accessible” is an adjective that I think most software engineers would be confident in describing. There would be variation in wording if you ran a poll, but I’m sure you’d see most definitions derive from something like the following:</p>

<blockquote>
  <p><em>Accessible (Universal): a thing, that anyone is capable of using, regardless of physical or mental disability.</em></p>
</blockquote>

<p>I think this captures the goals of interface design quite well even if it’s rather lofty, and would actually be a good jumping-off point as one of a few guiding principles of accessible (Universal) software development in the same vein as the agile manifesto principles function for building software projects. However, I don’t believe this is the most common understanding of “accessibility” when put into practice. When software developers are placed under constraints that require them to prove work, their definition can shift subtly. My experience has shown it normally morphs into something resembling the following:</p>

<blockquote>
  <p><em>Accessible (Developer): a thing, that conforms to visual restrictions necessary for the visually impaired, and features machine readable information and keyboard interactions for use by the blind.</em></p>
</blockquote>

<p>This is a narrow and, as far as I know, a private developers-only definition of “accessibility.” We first name two groups of users which I think is an important mutation. The visually impaired and legally blind are fully distinct from the “normal” cohort of users in this definition, as compared to the universal definition which talked of “anyone”. This may initially seem prudent! Developers work with requirements, stories, and personas. These are our personas to our definition which acts as a user story.</p>

<p>The two personas conceptualized by the accessibility (Developer) definition are extremely specific. Someone who is visually impaired uses an increased font size and requires contrast ratios to exceed a certain minimum in order to perceive them. Someone who is blind is using assistive software to read-aloud or otherwise parse the HTML and expects there to be as much information present in that space as possible. These sorts of mental images are pretty common in discussions about accessibility (Developer). While people who align with these personas exist, I don’t believe this concrete image of disability is constructive for creating interfaces.</p>

<h2 id="concrete-examples-of-disability-are-inadequate-personas">Concrete examples of disability are inadequate personas.</h2>

<p>You may hear people contextualize why accessibility (Developer) is important by invoking a disability name. An example I’ve heard before is “What if one of our customers is blind! They won’t know what this image without an alt tag is.” This is not an untrue statement. If machine readable information isn’t provided to a user that uses a machine to read-aloud the content of the screen, they will not be presented with any information about the image. A blind person is likely to use this sort of tool.</p>

<p>The only place where this well-intentioned thinking falls short for the blind user in question, is the solution. The implication my imaginary strawperson developer is making here, is that machine readable information solves this issue; in this case by adding an HTML <code class="language-plaintext highlighter-rouge">alt</code> attribute on an image tag. This is true in simple cases, however the web applications I have worked on have yet to be simple. Does this blind user hear the text you’re including in the alt tag in multiple other places? Are you making the interface itself more confusing? Do we imagine this alt tag as part of a wider interface to support this medium, or just simply as a way to “increase” accessibility (Developer)?</p>

<p>At many points in your life, for a temporary, indeterminate, or permanent amount of time, you will find yourself disabled. This can be due to injury or age, but situation is a much more common cause of disability. Someone wearing gloves in the cold could be thought of as temporarily disabled, as they have extremely low dexterity and sensation. Comparing this to our example of a blind user, you are both lacking a sense that we designed around the assumption you had. I use the word disability not to dilute that word of it’s emotional meaning, but to use it for it’s overly-literal meaning: unable to preform some specific action. You may not conceptualize disability at this level, but I think it’s worth conceptualizing “ability” without it’s associated lack-of-ailment for a moment.</p>

<p class="dont-break">
How might we talk about what needs to be done to make an accessible (Universal) product then? Imagine instead the range of options your users have to interact with your product. This to me, is a better way to visualize our personas. **Rather than assigning these bundles of disabilities a name, we can instead target ways that people may interact with our product.** I like to think of these as layers on top of what you're building. The range of interaction options I was mentioning before can be conceptualized as the depth of these layers.

<img alt="A small diagram showing three layers. One at the top showing a standard website layout with a cusor over top of it. The next layer below it showing the same layout, but connected by keyboard shortcuts for navigation anf interaction. And the final layer showing a flowchart with quote marks, representing interconnected descriptions provided by something like VoiceOver." src="/assets/layers.png" data-lines="9" style="margin-top: 5.5ex" />
</p>

<p>All of these interfaces exist on top of one another. Someone will be exposed to the top layer by default that we’re familiar with as “the interface”. This is normally designed by someone, who considered the medium in which it’s being displayed. A website is expected to respond to touch for example, as many devices that can use websites, support touch. A designer will carefully consider the size of touch targets to make things easy to tap with a finger, and prefer swipe gestures over requiring accurate finger-pecking.</p>

<p>If an interaction is impossible or difficult on someone’s device however, they instinctively look for the next layer. I call this a layer, because it’s another designed interface co-located with another, using a different set of expectations about the interaction medium. A website is expected to be navigable by keyboard for example. This shouldn’t require the use of another human interface device. The layer is dedicated to the keyboard. Our example user with cold hands in gloves will be able to use the Next/Tab key in their phone’s keyboard to jump to the next field they’re filling in. They aren’t staying in the second layer, but nothing is lost by switching to it. We have provided an alternative interaction medium which allowed them to use our product.</p>

<p>Another layer, oft-misunderstood or mixed into the keyboard layer, is a machine announced interface. Devtools in your browser of choice give you a peek into this layer under an “Accessibility” tab normally. This is a separate interface of UI with descriptions, commonly announced by a text-to-speech program but not always. Mixing this into the keyboard layer, straddles the user with the responsibility to use quite complex software just to use a keyboard. We should aim to keep the definition of these interface layers as small as possible so users can pick the one they can use most efficiently. A machine announced interface layer should not be unusable without a touch screen or keyboard for example. Should the user want to use any of these interface layers, they can without losing function. A VoiceOver user will regularly make use of tab order in the keyboard interface layer for example.</p>

<p>You might have other layers depending on your business. An example might be restaurants who have a kitchen display system. These normally must work with bumpbars, a kind of hotkey macro pad. <strong>The important thing to conceptualize here is that you’re designing multiple co-located interfaces, not one interface with accessible (Developer) sprinkles added to it that free you of any responsibility.</strong></p>

<h2 id="there-is-a-human">There is a Human</h2>

<p>If our top layer interface (the one your designer considered every pixel, swipe, and click for) used a different visual style of text box for every single input in the app, I think most people would agree that it’s difficult to use. You might have gotten into this situation because each input was subtly different: one is for an email, the other is for a password, another is for a name which must be at least 1 character long, and the final one is used to feign some simulacra of signing your name for an antiquated legal process. Just because they are different, doesn’t mean their interaction is different, they all require me to type something. This is a distinction you already innately understand, and probably find this paragraph tedious to read though.</p>

<p>You might not feel the same about this same obvious issue in other interface layers you don’t use. How many forms have you seen online with an asterisk to mark a required field? This is a simple example, but it creates a bizarre world to navigate at the machine announced layer. Imagine hearing an input described as <strong>“First name star, edit text”</strong> as it would be by VoiceOver, Apple’s very popular screen reader. Even if you include a <code class="language-plaintext highlighter-rouge">required</code> attribute (surely accruing accessibility (Developer) cred in your PR) this will still be <strong>“First name star required, edit text”</strong> to your users making use of this layer. I can’t easily recreate this experience for a user who does not use assistive software, but let me give you an example of what this sloppiness looks like in our top layer.</p>

<blockquote>
  <div class="bubble dont-break" title="A simulated example of the serial delivery of information from something like VoiceOver or JAWS. Three elements are shown but only 1 at a time.">
<div class="blink-1">star required</div>
<label>
    <span class="blink-2">First name star</span>
    <input class="blink-3" type="text" required="" />
</label>
</div>
</blockquote>

<p>The medium we’re emulating can only communicate one thing at a time, so it’s on the user to hold onto context as it goes past. What is star? Is it required? Is star an entity I have to provide in this form? This would be considered sloppy design in the visual realm, a unique splatter of colour on some input for some cryptic reason would be a better example that doesn’t rely on me trying to recreate an experience here, but when discussing a machine announced interface we assume “they will get it.” You may have even had that thought while reading this example. People that use these tools have come across this common quirk before, so surely they must have picked up on it by now. And that’s probably true! But I think we should aim to craft interfaces to the same level of quality, no matter which interaction layer a user is on.</p>

<p>These configurations, and the resulting information communicated to your users, is an interface. Many people experience their online world either partially or fully in this layer. There is a high chance that you will have to as well at least 1 time in your life. <strong>Consider the fact that a human is always present no matter the medium.</strong> Clear communication and sensible labels will go a long way towards removing barriers because the human being can make inferences. <strong>Adding more noise for the machine to read is not always the correct choice.</strong></p>

<p>The unexplained “star” is an example of a fix you could make by removing something from the machine announced layer. <code class="language-plaintext highlighter-rouge">role=presentation</code> on the asterisk and the <code class="language-plaintext highlighter-rouge">required</code> attribute on the input is worth a try in VoiceOver to see the difference it can make. Consider designing this interface layer so it makes sense, not simply assuming maximum machine information will tend towards sense.</p>

<h2 id="curb-cut-effect">Curb Cut Effect</h2>

<p>A colour contrast minimum rule is a favourite of the automated accessibility (Developer) test crowd. It’s not without it’s merit either! <a href="https://webaim.org/resources/contrastchecker/">The famous WebAIM contrast checker</a> very easily visualizes how slight changes in colour can render UI basically incomprehensible. The issue is not with the rule here at all. It’s actually to do with the narrow scope in which it’s applied.</p>

<p>As with the other interface layers I gave examples of, the mouse or touchscreen interface layer needs consideration for it’s own medium. Information is delivered to users two dimensionally, out of a screen with some limited range of brightness, colour, and size. Ensuring contrast is perceivable is important. <strong>It actually benefits anyone using a screen.</strong> You’ve probably come across some interfaces with transparent unreadable text boxes, or featureless square buttons that blend into the background that frustrated you. If you haven’t, congratulations! But I can show you a multitude of Hacker News posts with examples of valid complaints from many other people. Strict application of a contrast minimum would’ve at least forced someone to consider why they chose the frustrating option.</p>

<p>And yet, I still see readability and contrast being relegated to this accessibility (Developer) “best effort” group of tasks. Bemoaned by some minority of designers as an attack on creative freedom at the behest of the visually impaired. But if we strip away this weird private definition of the word “accessibility”, and try to find a new explanation why this matters, I think we would come to the conclusion that it’s simply good user experience design. The end result is a better, easier to use product.</p>

<p>The prime example of this effect is the curb cut: an angled slice made into the curb on the side of a road, to make access onto and off of the road possible by rolling instead of stepping. In your mind, you’re imagining wheelchairs. Someone that cannot walk onto the curb must be physically disabled, and therefore uses a wheelchair. This is so cemented in our collective consciousness that we use a symbol of a person in a wheelchair to represent the concept of “disability”. A parking spot with that symbol displayed, won’t be far from a curb cut.</p>

<p>However, this 1:1 reasoning is clearly not the full story. If you’ve ever had to use a mover’s dolley before, you’ll know how useful these curb cuts are. Same with someone on a bike, who generally values their pelvis <strong>not</strong> being blasted into shards going over a curb on thin road bike tires. The built environment was improved for everyone by adding an interface option (rolling) that we understood as being for only 1 specific kind of person.</p>

<h2 id="considering-my-interfaces-while-avoiding-the-allure-of-minmaxing-my-accessibility-developer-score">Considering My Interfaces While Avoiding the Allure of Min/Maxing My Accessibility (Developer) Score</h2>

<p>We developers are an interesting bunch. We take large problems, and break them down into small describable mini-problems that we can then automate, and provide an abstraction to make using our solution easy to use. While this process does work well for many problems, it’s not universal. Sometimes large “birds eye” solutions are necessary. Designers and artists are very familiar with this concept; holding steadfast to strict rules won’t always create a cohesive work, or even a work that’s fit for purpose. Instead, stepping back and considering the way someone uses the thing you’re making gives you a direction towards the impact/outcome you want to have, rather than trying to take the shortcut of following tips and tricks to save yourself the effort of exploration.</p>

<p>This doesn’t mean standards for interface design are bad, far from it actually, but I don’t think we can assume that following an accessibility (Developer) “best practice” standard means the result is accessible (Universal). That requires we promise respect for your users, not out of pity for some list of disabilities that someone else predetermined as the “important ones”, but rather respect for your users to use tools how they see fit. Boiling this goal down to “it passes the automated a11y test” doesn’t hold up our side of this promise often enough.</p>]]></content><author><name></name></author><category term="Rants" /><category term="english" /><summary type="html"><![CDATA[For the following post, I need to make the distinction between two definitions of the word “accessibility”. I’ll be doing this with a little parenthetical after the word. Accessibility (Universal) will refer to the first definition I will give. Accessibility (Developer) will refer to the second definition. If it’s placed in quotes, I’m referring to the string “accessibility” itself.]]></summary></entry><entry><title type="html">A Manual For font-variant-alternates</title><link href="https://graypegg.com/2023/06/30/a-manual-for-font-variant-alternates.html" rel="alternate" type="text/html" title="A Manual For font-variant-alternates" /><published>2023-06-30T16:11:58+00:00</published><updated>2023-06-30T16:11:58+00:00</updated><id>https://graypegg.com/2023/06/30/a-manual-for-font-variant-alternates</id><content type="html" xml:base="https://graypegg.com/2023/06/30/a-manual-for-font-variant-alternates.html"><![CDATA[<p><a href="/assets/fontvariant/fontsample.png"><img data-lines="5" alt="a comparison between two version of the word ailuridae written with and without font variant changes." src="/assets/fontvariant/fontsample.png" /></a> The font variant alternative css rule is generally well supported by evergreen browsers (read: all of the ones that matter) and is incredibly useful if you have a well-constructed font to work with. I’m using the ever-wonderful font Concourse for this site, and I wanted the logo on the left to match the version I had drafted in Affinity Designer with some alternative characters. <strong>This should’ve been easy.</strong> The lower case L should be the hooked variant, and the lowercase U should use the more rounded version.</p>

<p>However, all of the information you’re going to find while looking this up will be reiterations of <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant-alternates">the content found on MDN</a> which I find really confusing. There’s a whole bunch of detail left out about how the property works, and why it’s required to also use the <code class="language-plaintext highlighter-rouge">@font-feature-values</code> rule. After some digging, this is the details I was hoping to find a couple hours ago.</p>

<h2 id="opentype-features">OpenType Features</h2>
<p>The OpenType font format allows storing alternate glyphs/settings using a few different named categories called “features”. Each of these categories has some restrictions on what is changeable, but they are all indexed and configured the same way: toggling on or off using a unique ID that is a short string representing the name of the feature, and sometimes a sequential unique number if there’s multiple styles. Here’s a short sample of a few of these toggles you can pull.</p>

<table>
  <thead>
    <tr>
      <th>Feature</th>
      <th>ID</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Small capitals</td>
      <td><code class="language-plaintext highlighter-rouge">smcp</code></td>
    </tr>
    <tr>
      <td>Replace large size capitals with small caps</td>
      <td><code class="language-plaintext highlighter-rouge">c2sc</code></td>
    </tr>
    <tr>
      <td>Unicase (use only lowercase glyphs)</td>
      <td><code class="language-plaintext highlighter-rouge">unic</code></td>
    </tr>
    <tr>
      <td>Use Simplified Chinese characters</td>
      <td><code class="language-plaintext highlighter-rouge">smpl</code></td>
    </tr>
    <tr>
      <td>User superscript numbers (Ordinals)</td>
      <td><code class="language-plaintext highlighter-rouge">ordn</code></td>
    </tr>
    <tr>
      <td>Use glyph alternatives with more flourishs (Swash)</td>
      <td><code class="language-plaintext highlighter-rouge">swsh</code></td>
    </tr>
    <tr>
      <td>Use a group of style settings (Stylistic Set)</td>
      <td><code class="language-plaintext highlighter-rouge">ss01</code> - <code class="language-plaintext highlighter-rouge">ss99</code></td>
    </tr>
  </tbody>
</table>

<p>A large list of these can be found on <a href="https://en.wikipedia.org/wiki/List_of_typographic_features">wikipedia</a>, of course. <strong>It’s important to note that these have no other configuration options than on or off.</strong> It’s up to the font designer to make sure that they sort the glyphs and settings into the correct categories, and that they are configurable enough that someone won’t be stuck with a style feature that does more than they want. Also note that there is not alternative Swash set. That feature only has one feature ID, so therefore you can only have 1 entire new set of swish-y characters per font. (At least without using a stylistic set.)</p>

<p>If we want to use alternative glyphs, we first need to determine what features are implemented in a given font. This is sometimes provided from your font designer, or you can check manually using a tool like <a href="https://fontdrop.info/">fontdrop.info</a> which will give you an interactive list of toggles to see what each feature does. If you see a number of features named something like <code class="language-plaintext highlighter-rouge">ss18</code>, (Style Set 18) these are most likely your single alternate characters. This is what I was looking for when I was trying to find out how to change the L and U glyphs for my logo. Just keep messing with these until you know which stylistic sets you’d like to be enabled to get the font preview looking how you want it to.</p>

<blockquote>
  <p><i class="animal-dog"></i> <span class="bubble">If you don’t see any style set features, jump to the bottom of this page for more info.</span></p>
</blockquote>

<h2 id="the-font-feature-values-rule">The @font-feature-values rule</h2>
<p>Because these style sets are named using cryptic 4-character IDs, CSS graciously specs a rule that lets us group together the various feature IDs you want to use and assign each feature a name. Here’s what the @font-feature-values rule looks like for this website, as used by the logo on the left.</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@font-feature-values</span> <span class="n">concourse</span> <span class="p">{</span>
    <span class="k">@styleset</span> <span class="p">{</span>
        <span class="py">altu</span><span class="p">:</span> <span class="m">15</span><span class="p">;</span>
        <span class="py">altl</span><span class="p">:</span> <span class="m">17</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This is where I’ve been sinking time into reading W3C spec documents and intellisense in my editor. I don’t see this weird syntax being talked about much. So lets break down what each part does.</p>

<h3 id="font-feature-values-concourse"><code class="language-plaintext highlighter-rouge">@font-feature-values concourse</code></h3>
<p>We declare this is a font feature set for the <code class="language-plaintext highlighter-rouge">concourse</code> font. This must be the full name of the font family you wish to configure. You cannot share font feature settings between font families, but if you have multiple styles (bold, italic) of the same font family that use the same font family name, these settings will apply to those as well.</p>

<h3 id="styleset"><code class="language-plaintext highlighter-rouge">@styleset</code></h3>
<p>This block signals that everything inside it is referring to a Stylistic Set feature. There are <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@font-feature-values">other @rules for other feature categories.</a> You may need to use the <code class="language-plaintext highlighter-rouge">@character-variant</code> rule if you found no style set rules. See the bottom of this page for more info.</p>

<p>It’s also important to note, these @rules are not plural! (@styleset not @stylesets) They are always singular, despite the fact that the renamed OpenType features it defines must be individually applied when using the <code class="language-plaintext highlighter-rouge">font-variant-alternates</code> rule that we will get to. This is not one style set, but a renamed list of style sets.</p>

<h3 id="altu-15-and-altl-17"><code class="language-plaintext highlighter-rouge">altu: 15</code> and <code class="language-plaintext highlighter-rouge">altl: 17</code></h3>
<p>This was just a name that I came up with. Confusingly for the CSS spec, <strong>the properties here aren’t known CSS properties. You write in your own names here.</strong> You can write anything you want as a rule name here. The number we assign our feature to, is the Stylistic Set we want to use when we refer to that name. This is so supremely confusing to me. It really feels more complicated than it has to be. 15 here, means I want to name OpenType feature <code class="language-plaintext highlighter-rouge">ss15</code> as <code class="language-plaintext highlighter-rouge">altu</code>, because it’s the stylistic set that contains the alternate glyph for the rounded U character that I want when enabled.</p>

<h2 id="applying-the-renamed-opentype-features-to-an-element">Applying the renamed OpenType features to an element</h2>
<p>Now we have some font features, assigned to different names, and a font in which to use those. Currently, nothing has changed when rendering this font. For us to apply the configurations we want we need to use the <code class="language-plaintext highlighter-rouge">font-variant-alternates</code> rule which allows use to toggle on and off the features we named in a @font-feature-values rule. This actually introduces a really odd syntax choice where we need to re-assert what category of features we want to apply.</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">h1</span> <span class="p">{</span>
    <span class="nl">font-family</span><span class="p">:</span> <span class="n">concourse</span><span class="p">,</span> <span class="nb">sans-serif</span><span class="p">;</span>
    <span class="nl">font-variant-alternates</span><span class="p">:</span> <span class="n">styleset</span><span class="p">(</span><span class="n">altu</span><span class="p">,</span> <span class="n">altl</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>First we set the font family to the one that we wrote the @font-feature-values rule for, then we assign the variant features using the feature category’s css function. In my case, all of the alternates that I wanted were assigned to style sets. The values you pass in are the property names you gave each rule, and they can be comma separated if you want to list multiples. If they are listed, it’s the same as turing that feature ON.</p>

<p>You should now see your selected alternate characters being rendered. Yay!</p>

<h2 id="-troubleshooting"><i class="traffic-cone--exclamation"></i> Troubleshooting</h2>

<h3 id="i-dont-have-any-style-sets">I don’t have any style sets</h3>

<p>If you don’t have any style sets in your font (and you’re 100% sure that the font file isn’t malformed or missing alternate characters all-together), <strong>the alternate characters may be stored as character variants.</strong> Which each get their own feature. For whatever reason, I’ve found this to be less common, but I imagine there are fonts out there like this. (Probably quite a few, I’ve only dug into a couple fonts really.) Character Variants use the feature ID <code class="language-plaintext highlighter-rouge">cv01</code> to <code class="language-plaintext highlighter-rouge">cv99</code>, so in that way they are similar to style sets… except I lied at the start of this page. You can actually pass more information to character variants beyond just ON and OFF. You are given one whole integer to send over. This integer you send over, is the choice of which variant to use. There may be more than 2 different kinds of “a” glyph for example. This means that the CSS is slightly different for character variant rules.</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@font-feature-values</span> <span class="n">concourse</span> <span class="p">{</span>
    <span class="k">@character-variant</span> <span class="p">{</span>
        <span class="py">alta1</span><span class="p">:</span> <span class="m">4</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="nt">h1</span> <span class="p">{</span>
    <span class="nl">font-family</span><span class="p">:</span> <span class="n">concourse</span><span class="p">,</span> <span class="nb">sans-serif</span><span class="p">;</span>
    <span class="nl">font-variant-alternates</span><span class="p">:</span> <span class="n">character-variant</span><span class="p">(</span><span class="n">alta1</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The most confusing part of this is the @font-feature-values rule. <strong>The name you give the feature must end in a number.</strong> That number refers to the integer passed to the character variant feature. So in this case, I am asking for the 1st alternative. I called it alta1, so we could imagine this is an alternative single-storey “a” glyph.</p>

<p>The 4 in the value side of this rule, refers to the <code class="language-plaintext highlighter-rouge">cvXX</code> number in the ID, as it does with style sets. This is actually what tells the font we are looking for glyphs replacing a specific letter. You need to refer to your font data to find what this value is. They will show up as <code class="language-plaintext highlighter-rouge">cvXX</code> features. Just enter the number with out the cv part.</p>

<h3 id="i-dont-have-any-alternative-characters-at-all">I don’t have any alternative characters at all!</h3>
<p>Some fonts don’t have any! Though it’s also good to try using a different format first. Sometimes the WOFF2 or WOFF font may be lacking features that are in the OTF file. If you have access to a OTF file, try doing the same font inspection I mentioned <a href="#opentype-features">under the first heading</a> and see if you see any alternates. If so, you can convert an OTF font to WOFF2, or even use it in the browser as-is. Though I would suggest seeking to only serve webfonts in WOFF2 format.</p>]]></content><author><name></name></author><category term="tutorials" /><category term="css" /><category term="english" /><summary type="html"><![CDATA[The font variant alternative css rule is generally well supported by evergreen browsers (read: all of the ones that matter) and is incredibly useful if you have a well-constructed font to work with. I’m using the ever-wonderful font Concourse for this site, and I wanted the logo on the left to match the version I had drafted in Affinity Designer with some alternative characters. This should’ve been easy. The lower case L should be the hooked variant, and the lowercase U should use the more rounded version.]]></summary></entry><entry><title type="html">CAQ et le REM de l’est</title><link href="https://graypegg.com/2023/06/29/caq-et-le-rem-de-lest.html" rel="alternate" type="text/html" title="CAQ et le REM de l’est" /><published>2023-06-29T18:50:00+00:00</published><updated>2023-06-29T18:50:00+00:00</updated><id>https://graypegg.com/2023/06/29/caq-et-le-rem-de-lest</id><content type="html" xml:base="https://graypegg.com/2023/06/29/caq-et-le-rem-de-lest.html"><![CDATA[<p>Il y a quelques semaines depuis le CAQ avait dévoilé la facture pour le REM de l’Est, et je suis toujours aussi fâché
comme j’y étais. La province a décidé d’assigner le conseil une tâche impossible, et Legault vient de découvrir ce
fait. Mme Plante et M. Legault ont vraiment solidifiés leur place dans l’histoire en tant que les uns qui ont gardé
Montréal dans le passé pour une autre décennie supplémentaire. Le REM de l’Est ne va pas être bâti. Leur promesse à
creuser la ligne entière rend le projet total nul. Il sera trop cher pour la province à faire face, et s’il était même
capable à commencer le projet, il prendrait trop long à compléter l’intervalle de centre-ville. On aurait pu un lien
vers le centre-ville et l’est de l’ile, mais le futur pour Montréal est maintenant confiné à une ville divisée.</p>]]></content><author><name></name></author><category term="Rants" /><category term="transit" /><category term="français" /><summary type="html"><![CDATA[Il y a quelques semaines depuis le CAQ avait dévoilé la facture pour le REM de l’Est, et je suis toujours aussi fâché comme j’y étais. La province a décidé d’assigner le conseil une tâche impossible, et Legault vient de découvrir ce fait. Mme Plante et M. Legault ont vraiment solidifiés leur place dans l’histoire en tant que les uns qui ont gardé Montréal dans le passé pour une autre décennie supplémentaire. Le REM de l’Est ne va pas être bâti. Leur promesse à creuser la ligne entière rend le projet total nul. Il sera trop cher pour la province à faire face, et s’il était même capable à commencer le projet, il prendrait trop long à compléter l’intervalle de centre-ville. On aurait pu un lien vers le centre-ville et l’est de l’ile, mais le futur pour Montréal est maintenant confiné à une ville divisée.]]></summary></entry><entry><title type="html">Tracking time in Omnifocus</title><link href="https://graypegg.com/2020/12/06/tracking-time-in-omnifocus.html" rel="alternate" type="text/html" title="Tracking time in Omnifocus" /><published>2020-12-06T23:11:58+00:00</published><updated>2020-12-06T23:11:58+00:00</updated><id>https://graypegg.com/2020/12/06/tracking-time-in-omnifocus</id><content type="html" xml:base="https://graypegg.com/2020/12/06/tracking-time-in-omnifocus.html"><![CDATA[<p>I’ve been using <a href="https://www.omnigroup.com/omnifocus/">omnifocus</a> for a few years now, though it’s only been recently that I’ve needed to track the time I’ve spent on a per-project and sometimes per-task basis. OmniFocus doesn’t offer anything like that out of the box, since it really isn’t meant to be a time tracker, but what it does have is a very powerful script environment which we can use to get a workflow running! However, I also need to mention <em class="callout showing">right off the bat</em> that I don’t think this is a replacement for a fully-featured time tracking platform. Check out <a href="https://toggl.com">Toggl</a> or something similar if you need more than just a timer. That’s all this is. For now.</p>

<h2 id="-the-plugin"><i class="box"></i> The Plugin</h2>

<p>It’s pretty easy to use! First, select the task you’d like to start timing and run the Start Timer action from either the Automation menu or by adding it to your toolbar. (You can time multiple tasks at once!) This saves a small file as an attachment to the task that records when the timer started. There is no background task running these timers, so no worries about always having OmniFocus open!</p>

<p><img src="/assets/of-timer/of-timer-start-timer.gif" alt="Clicking a task, then clicking the Stop Timer action, which then turns grey. The estimated duration field gets filled with a value of &quot;45 minutes&quot;" /></p>

<p>Then, once you’re done working on that task for the moment, select it again and click the Stop Timer action. This will take the difference between the start time and now, and put that into the estimated duration field of that task. You can create perspectives using the estimated duration field, and I don’t see many people using it for it’s intended purpose, so I think this is a powerful spot to keep this information! (Benefits and caveats explained <a href="#why-estimated-duration">here.</a>)</p>

<p><img src="/assets/of-timer/of-timer-stop-timer.gif" alt="Clicking a task, then clicking the Stop Timer action, which then turns grey. The estimated duration field gets filled with a value of &quot;45 minutes&quot;." /></p>

<h2 id="why-estimated-duration"><i class="clock-select"></i>Why Estimated Duration?</h2>

<p>This plugin stores your tracked time in the estimated duration field. (which is evidently <strong>not</strong> estimated, if it already happened.) I know this is a weird choice but hear me out. I’ve seen a few <a href="https://twitter.com/toi_wah/status/954588596131921921">OmniFocus + OmniOutliner timer scripts</a> though they’ve always just recorded that information where the tools I use couldn’t reach it. If it’s in the note, then it’s just being treated like a string. If it’s in some weird part of the OmniFocus database or in an OmniOutliner document, I probably have to manually move that data around and bring it back to the actual task. That is very annoying to do, especially since I have trouble finding enough time to do an honest review perspective session. By placing the tracked time in Estimated Duration, I get:</p>

<h3 id="pros">Pros</h3>

<ul>
  <li>A nicely formatted time string (e.g. 34 minutes)</li>
  <li>It’s available on every task, always.</li>
  <li>It’s part of the app, so there’s UI for it.</li>
  <li>No weird OmniFocus database tweaks so it’s future-proof</li>
  <li>I can make perspectives that filter for <strong>tasks that are started</strong>, but I haven’t tracked much time on them.</li>
</ul>

<p>That last one is the big one. There are a number of Estimated Duration filters.
I took a screenshot here, though sorry for the language change. You have the option
(#1) of filtering for only items you’ve tracked <strong>any</strong> time on, then a range of
4 options (#2, #3, #4, #5) for filtering tasks where you’ve tracked <strong>under</strong> that
amount of time.</p>

<p><img src="/assets/of-timer/of-timer-filters.png" alt="A screenshot of of filters, rendered in french. The options in english would be &quot;has a estimated duration&quot; and then 4 different options of &quot;Estimated Duration is under 5mins&quot; then 15 minutes, then 30 minutes and 60 minutes." /></p>

<p>This is useful for a lot of things.</p>

<ul>
  <li>It gives you a “started” state for tasks and projects, as anything with time tracked can be considered to be “on going work”.</li>
  <li>You can write up a perspective to give you a hit list of items that extended over from yesterday (tracked time, but not complete) that should be done ASAP. (This is common for me.)</li>
  <li>Something with under 60 minutes of work probably isn’t done, but it has been worked on! I find that sometimes I set these sorts of tasks aside half-done, only to come back later and find that what I had done was good enough. Those were billable hours eh!</li>
</ul>

<p>For these reasons alone, this is now how I do time tracking. There are however, some annoyances; most of which I think will be fixed in the future.</p>

<h3 id="cons">Cons</h3>

<ul>
  <li>You lose Estimated Duration’s meaning. It’s not an estimation anymore.</li>
  <li>There’s no easy way to get this info out of OmniFocus programmatically other than CSV or TaskPaper exports. (No easy invoicing tool imports here!)</li>
  <li><strong>Projects do not sum the estimated duration of their children.</strong></li>
</ul>

<p>That last one, I’m going to open a feature request for. I think it makes sense even if I was using estimated duration as an estimate! If the parent task or project has an unset estimated duration, make it the sum of the children who do have one. This would be odd for the Omni Group team I bet, as everything else in the OmniFocus system inherits from the parent (e.g. tags and dates) where this data is sourced from the children of a task.</p>

<p><strong>To get around this for now, I’ve included an action in the plugin called “Update Project’s Duration” which just sums the estimated durations of the currently selected task or project’s children and applies it to that node.</strong> This is annoying, and manual, but for me, it’s only ever useful when quoting for someone else, and I need the example total from an old project. Otherwise, time is normally itemized in the invoice, so the total lives there.</p>

<hr />

<h2 id="installation"><i class="truck--plus"></i>Installation</h2>

<p><a href="https://graypegg.com/stuff/OFTimer.omnifocusjs.zip">You can download the OmniJS bundle from here.</a> You can also grab it off of the <a href="https://github.com/graypegg/omnifocus-timer">GitHub repo</a>.</p>

<p>Download that file, then unzip it. (Safari will unzip it for you sometimes: handy!) <strong>You should be able to just double click on it to install,</strong> though I have had trouble with that in the past. If that is an issue, you can drop the OmniJS file into your plugins folder, which is found by going to Automation in the menu bar, then Plugins, then clicking Show In Finder.</p>

<p><img src="/assets/of-timer/of-timer-install.gif" alt="The plugins folder where you need to put the plugin bundle is easy to find! Go to Automation in the menu bar, then Plugins, then Show In Finder. This is where to drop the omnijs bundle." /></p>

<p><em>You should also be able to install this on iOS though I haven’t tried it as of yet. If you do go down that route, I recommend installing to iCloud, so your plugin’s remain synced up!</em></p>]]></content><author><name></name></author><category term="tools" /><category term="productivity" /><category term="english" /><summary type="html"><![CDATA[I’ve been using omnifocus for a few years now, though it’s only been recently that I’ve needed to track the time I’ve spent on a per-project and sometimes per-task basis. OmniFocus doesn’t offer anything like that out of the box, since it really isn’t meant to be a time tracker, but what it does have is a very powerful script environment which we can use to get a workflow running! However, I also need to mention right off the bat that I don’t think this is a replacement for a fully-featured time tracking platform. Check out Toggl or something similar if you need more than just a timer. That’s all this is. For now.]]></summary></entry></feed>