<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Kyle Gach</title>
  <subtitle>Writing about web design &amp; development, with a focus on accessibility</subtitle>
  <link href="https://kylegach.com/feed/atom.xml" rel="self"/>
  <link href="https://kylegach.com/"/>
  <updated>2021-07-05T16:42:30+00:00</updated>
  <id>https://kylegach.com/</id>
  <author>
    <name>Kyle Gach</name>
    <email>kyle.gach@gmail.com</email>
  </author>
  
  <entry>
    <title>Ensuring Web Accessibility of UI Components, from Quick to Thorough</title>
    <link href="https://kylegach.com/writing/ensuring-web-accessibility-of-ui-components-from-quick-to-thorough/"/>
    <updated>2021-07-05T16:42:30+00:00</updated>
    <id>https://kylegach.com/writing/ensuring-web-accessibility-of-ui-components-from-quick-to-thorough/</id>
    <content type="html">&lt;p&gt;Let’s start with the thorough: the only way to completely ensure a UI component is accessible is to test it with a variety of users in a real context. That requires both a fully-coded component and, typically, a working app in which to test it. It also requires proper UX research and testing, finding a suitably comprehensive variety of participants, etc. That process can be very expensive, and the necessary changes found by such a process are costly, too.&lt;/p&gt;
&lt;p&gt;By considering accessibility throughout the process of designing and building a component, you can avoid expensive changes later. Here are ways of thinking about accessibility as you make a component, ordered from quick (and cheap) to thorough (and expensive).&lt;/p&gt;
&lt;h2&gt;1. Style Native Elements&lt;/h2&gt;
&lt;p&gt;Web technology specifications and browsers have already done an enormous amount of work to make their native elements (button, select, table, etc) accessible. The quickest path to making accessible components is to leverage that work and build on top of what’s already available. For example, &lt;a href=&quot;https://www.filamentgroup.com/lab/select-css.html&quot;&gt;style a select element&lt;/a&gt; instead of &lt;a href=&quot;https://sarahmhigley.com/writing/select-your-poison/&quot;&gt;building your own&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In addition to being quick and easy, it’s also the most appropriate path, as building on top of semantic HTML helps the &lt;a href=&quot;https://webaim.org/blog/the-a-t-experiment/&quot;&gt;variety of assistive technologies&lt;/a&gt; understand the structure and behavior of your component.&lt;/p&gt;
&lt;h2&gt;2. Use an Accessible Library&lt;/h2&gt;
&lt;p&gt;Another way to get started fast and build on the efforts of others is to base your component on a library that has already done the work to be accessible. For React, you could look at &lt;a href=&quot;https://www.radix-ui.com/&quot;&gt;radix-ui&lt;/a&gt; or &lt;a href=&quot;https://react-spectrum.adobe.com/react-aria/index.html&quot;&gt;react-aria&lt;/a&gt;; for Vue, &lt;a href=&quot;https://vue.chakra-ui.com/&quot;&gt;Chakra UI&lt;/a&gt;; for web components, &lt;a href=&quot;https://genericcomponents.netlify.app/&quot;&gt;generic&lt;/a&gt; or &lt;a href=&quot;https://lion-web.netlify.app/&quot;&gt;Lion&lt;/a&gt;; among many others for those technologies and more. Pick whichever library meets your needs, but be sure to check (using the steps below) that it’s actually accessible.&lt;/p&gt;
&lt;h2&gt;3. Make Your Own&lt;/h2&gt;
&lt;p&gt;If you cannot accomplish what you need with native elements and cannot find a library suitable for your needs, then you’ll need to make your own component. As you work, you can check each of the aspects below to help ensure what you’re building is accessible to all of your users.&lt;/p&gt;
&lt;h3&gt;A. Copy work from good resources&lt;/h3&gt;
&lt;p&gt;Instead of starting from scratch, look for proven patterns that you can copy and adapt for your needs. The &lt;a href=&quot;https://www.w3.org/TR/wai-aria-practices-1.1/&quot;&gt;WAI-ARIA Authoring Practices&lt;/a&gt; provides many patterns (which they call “widgets”) of common UI interactions, such as accordions, breadcrumbs, and tabs, written with simple HTML, CSS, and JavaScript. They’re an excellent reference if your component fits (or closely fits) one of the documented patterns.&lt;/p&gt;
&lt;p&gt;You could also consider referencing the source code of an open source accessible library or finding other resources, such as this &lt;a href=&quot;https://www.smashingmagazine.com/2021/03/complete-guide-accessible-front-end-components/&quot;&gt;Complete Guide To Accessible Front-End Components&lt;/a&gt; or the &lt;a href=&quot;https://www.a11yproject.com/&quot;&gt;A11y Project&lt;/a&gt;. The web accessibility community is open and generous with their expertise and learning, so before you start building anything, be sure to do some research to find prior solutions and discussions.&lt;/p&gt;
&lt;h3&gt;B. Start with native elements whenever possible&lt;/h3&gt;
&lt;p&gt;Even if you’re building your own component, doing so on top of native elements can save a lot of effort. For example, the &lt;a href=&quot;https://www.w3.org/TR/wai-aria-practices-1.1/examples/tabs/tabs-1/tabs.html&quot;&gt;WAI-ARIA Authoring Practices example for Tabs&lt;/a&gt; is built with button elements, which are automatically keyboard navigable, correctly accept “space” and “enter” key events, handle tap interactions, etc.&lt;/p&gt;
&lt;h3&gt;C. Adequate color contrast&lt;/h3&gt;
&lt;p&gt;While users of all abilities should be considered while designing and building for the web, probably the biggest portion of those with disabilities have impaired vision of some kind. Thus, you can have a big impact by making sure the colors you use have &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/Understanding_WCAG/Perceivable/Color_contrast&quot;&gt;sufficient contrast&lt;/a&gt; between foreground and background. There are many tools you can use to ensure enough contrast, such as browser extensions (like &lt;a href=&quot;https://www.getstark.co/blog/hello-world&quot;&gt;Stark for Chrome&lt;/a&gt;) and native apps (like &lt;a href=&quot;https://usecontrast.com/&quot;&gt;Contrast for Mac&lt;/a&gt;). Browser developer tools (&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Tools/Accessibility_inspector#check_for_accessibility_issues&quot;&gt;Firefox&lt;/a&gt;, &lt;a href=&quot;https://www.smashingmagazine.com/2020/08/accessibility-chrome-devtools/#contrast-ratio&quot;&gt;Chrome&lt;/a&gt;) are also getting better and better at exposing accessibility information like color contrast ratios.&lt;/p&gt;
&lt;p&gt;One of the easiest ways to ensure good contrast ratios between colors is to use a color palette &lt;a href=&quot;https://www.radix-ui.com/docs/colors/palette-composition/understanding-the-scale&quot;&gt;designed with accessibility in mind&lt;/a&gt;, such as &lt;a href=&quot;https://www.radix-ui.com/colors&quot;&gt;Radix Colors&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;D. Don’t rely on color alone&lt;/h3&gt;
&lt;p&gt;As you’re designing, make sure your component does not use color alone to signify a state change or communicate meaning, such as a status. For example, a table containing links to items with an associated status should not merely color the link text. One solution would be to add icons alongside the link text.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://kylegach.com/img/ensuring-web-accessibility-of-ui-components-from-quick-to-thorough-1.png&quot; alt=&quot;Side-by-side display of table columns, the left is using color alone, the right is using color and icons&quot;&gt;
  &lt;figcaption&gt;
    The table column on the left is inaccessible, because it uses color alone to communicate information about each item. The items on the right use color as well as an icon with a unique shape to communicate the same information.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3&gt;E. Document flow is sensible&lt;/h3&gt;
&lt;p&gt;As you’re building, try to imagine how the document structure flows from one element to another. Do headings come before their associated content? If a control affects another part of the page, does that control come before whatever it affects? Does the visual order match the DOM order? As an extra step, turn off styles in your browser and check that your component still makes sense.&lt;/p&gt;
&lt;h3&gt;F. Interactive elements are keyboard navigable&lt;/h3&gt;
&lt;p&gt;If an element of your component is clickable, then users should be able to tab to it and activate it with the keyboard as well. The tab order is closely related to document flow and is very important. It can be &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Tools/Accessibility_inspector#show_web_page_tabbing_order&quot;&gt;checked with tools like Firefox’s Accessibility Inspector&lt;/a&gt;. Tab and focus management can be nuanced for complex components, and the &lt;a href=&quot;https://www.w3.org/TR/wai-aria-practices-1.1/&quot;&gt;WAI-ARIA Authoring Practices&lt;/a&gt; can be a particularly helpful reference for knowing how something should function to match most user’s expectations.&lt;/p&gt;
&lt;h3&gt;G. Most elements should have an accessible name&lt;/h3&gt;
&lt;p&gt;You can use browser dev tools (&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Tools/Accessibility_inspector#features_of_the_accessibility_panel&quot;&gt;Firefox&lt;/a&gt;, &lt;a href=&quot;https://developer.chrome.com/docs/devtools/accessibility/reference/#pane&quot;&gt;Chrome&lt;/a&gt;) to check the accessible name of the elements in your component. Before pulling up a tool, though, look at your component and try to identify all of the information that is conveyed visually. Then make sure that that information is also conveyed non-visually (for example, that an image displaying an icon has an alt attribute describing that icon’s meaning).&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://kylegach.com/img/ensuring-web-accessibility-of-ui-components-from-quick-to-thorough-2.png&quot; alt=&quot;Screenshot of the code for two form inputs, rendered output, and accessibility inspector panel&quot;&gt;
  &lt;figcaption&gt;
    Firefox’s Accessibility Inspector is showing that the second input has no accessible name, because it is not correctly associated with the label.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3&gt;H. Zooming doesn’t break the design&lt;/h3&gt;
&lt;p&gt;Using in-browser commands, zoom your component in to 200% and out to 50%. Is it still usable? This will usually surface aspects of your component with fixed dimensions, which should generally be avoided.&lt;/p&gt;
&lt;p&gt;If you’ve used non-relative units in your styles (like px), then you’ll need to also confirm that changing the &lt;a href=&quot;https://www.24a11y.com/2019/pixels-vs-relative-units-in-css-why-its-still-a-big-deal/&quot;&gt;browser’s zoom level in preferences doesn’t adversely affect your component&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;4. Check with Tools&lt;/h2&gt;
&lt;p&gt;As you’re building, and especially once you have a usable version of your component, there are many tools available to audit your work for accessibility issues and suggest fixes. One of the most popular is &lt;a href=&quot;https://www.deque.com/axe/&quot;&gt;axe&lt;/a&gt;, which is available as a browser extension and &lt;a href=&quot;https://developer.chrome.com/docs/devtools/accessibility/reference/#audits&quot;&gt;built into Chrome dev tools&lt;/a&gt; and &lt;a href=&quot;https://developers.google.com/web/tools/lighthouse/&quot;&gt;Lighthouse&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’re building your component in &lt;a href=&quot;https://storybook.js.org/&quot;&gt;Storybook&lt;/a&gt;, axe is built into the &lt;a href=&quot;https://github.com/storybookjs/storybook/tree/next/addons/a11y&quot;&gt;a11y addon&lt;/a&gt;, to provide automatic audits as you work. You can also often integrate these audits into your continuous integration (CI) pipeline (for example, &lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci/&quot;&gt;lighthouse-ci&lt;/a&gt;), preventing components from releasing with known accessibility problems.&lt;/p&gt;
&lt;p&gt;Other tools you can use are assistive technologies (AT) themselves, such as screen readers like &lt;a href=&quot;https://support.apple.com/guide/voiceover/welcome/mac&quot;&gt;VoiceOver for Mac&lt;/a&gt; or &lt;a href=&quot;https://www.nvaccess.org/about-nvda/&quot;&gt;NVDA for Windows&lt;/a&gt;. While there’s certainly a learning curve to using these tools, they will surface issues that cannot be found with automated checks and will help you empathize with how users of AT will understand and interact with your component.&lt;/p&gt;
&lt;h2&gt;5. Check with Users&lt;/h2&gt;
&lt;p&gt;There is no substitute for testing the actual component, in an actual product, with real people, with a variety of capabilities and impairments. User testing will help you discover aspects of your component not covered by the above steps or not even considered in your design. As designers and developers, it can be difficult to think of our work in the way that our users experience it. User testing can help break down these barriers to understanding. By using the above steps to make your component as accessible as you can before testing, you enable those testers to provide valuable feedback that might otherwise be lost in the noise of other issues.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>A Helpful Baseline (Measuring Site Quality with Lighthouse CI)</title>
    <link href="https://kylegach.com/writing/a-helpful-baseline-measuring-site-quality-with-lighthouse-ci/"/>
    <updated>2020-08-28T15:05:30+00:00</updated>
    <id>https://kylegach.com/writing/a-helpful-baseline-measuring-site-quality-with-lighthouse-ci/</id>
    <content type="html">&lt;p&gt;There is much to improve about this site. (If you’re reading this close to the publish date, that will be obvious, as you view the nearly naked prose and utter lack of design.) But making improvements without measuring the impact of the changes can risk making it worse. So, before I do any more work, I need a baseline from which to measure my changes against.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/tools/lighthouse/&quot;&gt;Lighthouse&lt;/a&gt; is a helpful tool to audit a website in five main criteria: performance, accessibility, best practices, SEO, and progressive web app (PWA). Those align nicely with my &lt;a href=&quot;https://kylegach.com/writing/v2-goals/&quot;&gt;goals for the site&lt;/a&gt;, making it an ideal fit for my needs. Lighthouse also does something quite neat and very much in line with the “learn, then teach” spirit of this site. Reporting the audit successes &amp;amp; failures would be useful on its own, but the Lighthouse team went much further and provide the &lt;em&gt;why&lt;/em&gt; behind each check, many with a “learn more” link. This greatly shortens the path from “oh no, not good” to “I learned a thing!”.&lt;/p&gt;
&lt;p&gt;There are many ways to run Lighthouse. The easiest is probably using the &lt;a href=&quot;https://developers.google.com/web/tools/lighthouse/#devtools&quot;&gt;built-in Audits panel of Chrome’s DevTools&lt;/a&gt;. That’s fine for a manual workflow, but I want to automate the audits, to ensure they run against &lt;em&gt;every&lt;/em&gt; change to the site and surface the results well. For that, I’ll use &lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci/&quot;&gt;Lighthouse CI&lt;/a&gt;, which I can run within my &lt;a href=&quot;https://kylegach.com/writing/building-and-deploying-with-github-actions/&quot;&gt;GitHub Workflow&lt;/a&gt;. Doing so is fairly straightforward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add Lighthouse step to workflow (&lt;a href=&quot;https://github.com/kylegach/kylegach.com/pull/20/commits/dcf8600432b865fd17789a2b0f0e72e68380a16b&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Though it’s all in one commit, this contains multiple tasks.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Change the Deploy step to always build a deploy preview, which can then be audited&lt;/li&gt;
&lt;li&gt;Add the Lighthouse step (following &lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci/blob/master/docs/getting-started.md#configure-your-ci-provider&quot;&gt;Lighthouse CI’s instructions&lt;/a&gt;), using the preview link from the previous step&lt;/li&gt;
&lt;li&gt;Add some basic &lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci/blob/master/docs/configuration.md&quot;&gt;Lighthouse configuration&lt;/a&gt;
&lt;ol&gt;
&lt;li&gt;Add &lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci/blob/master/docs/configuration.md#preset&quot;&gt;recommended assertions&lt;/a&gt; (using the “no-pwa” variety until I can begin address those criteria)&lt;/li&gt;
&lt;li&gt;Publish reports to a &lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci/blob/master/docs/configuration.md#target&quot;&gt;temporary, public location&lt;/a&gt; (for free!)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Add a second deploy step (really, move the previous one) that conditionally deploys a preview or the production site, upon success of the prior steps&lt;/li&gt;
&lt;li&gt;Refactor the &lt;a href=&quot;https://kylegach.com/writing/helpful-deploy-messages/&quot;&gt;Create Deploy Message step&lt;/a&gt;, to build up slightly different messages for each deploy step&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Turn off failing assertions (&lt;a href=&quot;https://github.com/kylegach/kylegach.com/pull/20/commits/60565e123716ac4158d464a16d606c7ab0daca06&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;While I haven’t done anything to intentionally make the performance or accessibility of this site worse (to then improve in a helpful blog post), I haven’t done anything extra to improve those things either. Thus, the recommended assertions return [four failed checks]. For now, I’ll disable those checks to get a passing audit, and will address each of them as my very next tasks.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now whenever I push a change to the site, a Lighthouse run is kicked off as part of my CI/CD workflow, and the results are published as both a status check (if pushing to a branch with a pull request) and a &lt;a href=&quot;https://lighthouse-dot-webdotdevsite.appspot.com//lh/html?url=https%3A%2F%2Fkylegach.com&quot;&gt;detailed report&lt;/a&gt; (not that &lt;em&gt;exact&lt;/em&gt; report, as the generated one is only hosted temporarily; that link is from a manual audit using &lt;a href=&quot;https://web.dev/measure/&quot;&gt;https://web.dev/measure/&lt;/a&gt;, and if it continues to work, it will probably not reflect the state of the site when this post was published).&lt;/p&gt;
&lt;p&gt;Most importantly, I can now continue to improve the site knowing that my changes are truly having a positive impact on the things I care about.&lt;/p&gt;
&lt;h2&gt;Follow-up&lt;/h2&gt;
&lt;p&gt;I’m happy with this initial implementation, but there are aspects to improve.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Only run the second deploy step if pushing to master (in other words, if deploying to production) to avoid creating a duplicate deploy preview. GitHub workflows cannot have conditional steps, only &lt;a href=&quot;https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idif&quot;&gt;conditional jobs&lt;/a&gt;. So I’d first have to split the steps into various jobs, and that would require &lt;a href=&quot;https://docs.github.com/en/actions/configuring-and-managing-workflows/persisting-workflow-data-using-artifacts#passing-data-between-jobs-in-a-workflow&quot;&gt;passing data between jobs&lt;/a&gt; unless I duplicate a lot of the steps and logic.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After splitting steps into different jobs, the Lighthouse job could be conditional, allowing it to be skipped — for example, by adding “[skipLighthouse]” to a commit message—which would be nice for writing only updates (like publishing this post).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Publish reports to a more permanent location, using &lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci/blob/master/docs/server.md&quot;&gt;Lighthouse CI Server&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tweak assertions, perhaps making use of a &lt;a href=&quot;https://github.com/GoogleChrome/budget.json&quot;&gt;performance budget&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Helpful Deploy Messages</title>
    <link href="https://kylegach.com/writing/helpful-deploy-messages/"/>
    <updated>2020-05-27T17:50:10+00:00</updated>
    <id>https://kylegach.com/writing/helpful-deploy-messages/</id>
    <content type="html">&lt;p&gt;How to make deploy messages much more useful when &lt;a href=&quot;https://kylegach.com/writing/building-and-deploying-with-github-actions/&quot;&gt;building &amp;amp; deploying with GitHub Actions&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;To recap the previous post, this site is now &lt;em&gt;built&lt;/em&gt; with &lt;a href=&quot;https://help.github.com/en/actions/&quot;&gt;GitHub Actions&lt;/a&gt; and (still) &lt;em&gt;deployed&lt;/em&gt; by &lt;a href=&quot;https://netlify.com/&quot;&gt;Netlify&lt;/a&gt;. When I was building in Netlify, each deploy had a helpful label that included (1) the branch being built, (2) the sha (a unique id for a commit) of the latest commit, and (3) the message of that commit. If I were to ever somehow deploy a bad build of the site, having well-labeled deploys makes it super easy to roll back to a working build (yet another benefit of a static site). Unlabeled deploys? Not so much. And I lost those helpful labels with my move to building on GitHub. The &lt;a href=&quot;https://cli.netlify.com/&quot;&gt;Netlify CLI&lt;/a&gt; (which I am using indirectly, via the &lt;a href=&quot;https://github.com/marketplace/actions/netlify-actions/&quot;&gt;Netlify Actions&lt;/a&gt; action) accepts a message option, and it &lt;em&gt;seemed&lt;/em&gt; like I had access to each of the three pieces of information I needed, so I should be able to recreate the experience I want. Let’s find out!&lt;/p&gt;
&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;It works! Here’s the relevant workflow code (&lt;a href=&quot;https://github.com/kylegach/kylegach.com/blob/master/.github/workflows/ci-cd.yml&quot;&gt;full source&lt;/a&gt;). Place these as steps in your job:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt; — The code below worked well for my needs at the time of publishing this post. If you keep reading, you’ll realize, as I did, that because GitHub Actions is still in beta, the tool and the various resources created by the community can become outdated quickly. Please cross-reference what you see here with &lt;a href=&quot;https://help.github.com/en/actions/&quot;&gt;GitHub’s documentation&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;- name: Checkout
  uses: actions/checkout@v2
  with:
    # Necessary to grab the HEAD commit from the source branch when
    # acting on a PR. Otherwise, `git log` will only contain the merge commit
    ref: ${{ github.event.pull_request.head.sha }}

- name: Create Deploy Message
  run: |
    # Grab the branch path from the appropriate (PR vs. push) property on context
    FULL_PATH_REF=&amp;quot;${{ github.event.pull_request.head.ref || github.ref }}&amp;quot;
    # Strip &amp;quot;refs/heads/&amp;quot; from the start
    REF=${FULL_PATH_REF#refs\/heads\/}
    # Get the short form of the SHA
    SHA=$(git rev-parse --short ${{ github.event.pull_request.head.sha || github.sha }})
    # Yank the commit message from the log, using the SHA
    COMMIT_MSG=$(git log -n 1 --format=%s $SHA)
    # Create the deploy message
    DEPLOY_MESSAGE=&amp;quot;$REF@$SHA: $COMMIT_MSG (${{ github.workflow }} workflow)&amp;quot;
    # Set it in env
    echo &amp;quot;::set-env name=DEPLOY_MESSAGE::$DEPLOY_MESSAGE&amp;quot;

# Build the site (omitted for brevity)...

# Deploy either preview or production
- name: Deploy
  uses: nwtgck/actions-netlify@v1.1.0
  with:
    # Pass the message
    deploy-message: ${{ env.DEPLOY_MESSAGE }}
    # more options...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The Goal&lt;/h2&gt;
&lt;p&gt;I want to construct a message with a structure like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;branch-name&amp;gt;@&amp;lt;sha&amp;gt;: &amp;lt;commit-message&amp;gt; (&amp;lt;workflow-name&amp;gt; workflow)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Part 0: GitHub Workflow Overview&lt;/h2&gt;
&lt;p&gt;Workflows are divided into “jobs” (currently, my workflow only has one job, build-and-deploy), and those jobs are further divided into “steps”. Each step has &lt;a href=&quot;https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idsteps&quot;&gt;a few properties&lt;/a&gt;, and the one most relevant for this post is &lt;code&gt;run&lt;/code&gt;, which operates as a shell. I’m using the default workflow shell, &lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/&quot;&gt;bash&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Workflows also &lt;a href=&quot;https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#about-contexts-and-expressions&quot;&gt;evaluate expressions&lt;/a&gt;, like referencing a variable, using this syntax: &lt;code&gt;${{ expression }}&lt;/code&gt;, which I’ll use a lot here.&lt;/p&gt;
&lt;h2&gt;Part 1: Branch Name&lt;/h2&gt;
&lt;p&gt;In &lt;code&gt;git&lt;/code&gt; terms, a branch is nothing more than a pointer to a specific commit, and that commit is known as the &lt;code&gt;ref&lt;/code&gt;. Thankfully, GitHub provides the &lt;a href=&quot;https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context&quot;&gt;&lt;code&gt;github&lt;/code&gt; context&lt;/a&gt; for use within workflows, which includes the &lt;code&gt;ref&lt;/code&gt;. This workflow runs when either of these “events” occur (1) pushing to the master branch or (2) submitting or updating a pull requst (PR) against the master branch. Operating on two different event types presents the first challenge. I want to avoid running different code for different events, but each event type stores information in the &lt;code&gt;github&lt;/code&gt; context differently. By using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Short-Circuit_Evaluation&quot;&gt;short-circuit evaluation&lt;/a&gt;, I can reference the appropriate context property:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# Grab the branch path from the appropriate (PR vs. push) property on context
FULL_PATH_REF=&amp;quot;${{ github.event.pull_request.head.ref || github.ref }}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;github.event.pull_request.head.ref&lt;/code&gt; stores the branch name like &lt;code&gt;&amp;quot;branch-name&amp;quot;&lt;/code&gt;, but &lt;code&gt;github.ref&lt;/code&gt; stores it with the pull path: &lt;code&gt;&amp;quot;refs/heads/branch-name&amp;quot;&lt;/code&gt;. As there’s no harm in attempting to replace something that can’t be found, I can run this code, using &lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html&quot;&gt;parameter expansion&lt;/a&gt;, on both cases to produce the non-pathed branch name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# Strip &amp;quot;refs/heads/&amp;quot; from the start
REF=${FULL_PATH_REF#refs\/heads\/}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Part 2: SHA&lt;/h2&gt;
&lt;p&gt;Looking over the &lt;a href=&quot;https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context&quot;&gt;shape of the &lt;code&gt;github&lt;/code&gt; context&lt;/a&gt;, this one seemed easy: there’s a &lt;code&gt;github.sha&lt;/code&gt; property directly available in both events. Two reasons this isn’t so simple.&lt;/p&gt;
&lt;p&gt;First, I’m interested in the latest commit that was built. &lt;code&gt;github.sha&lt;/code&gt; is associated with that commit only for the push event. For PR events, &lt;code&gt;github.sha&lt;/code&gt; points to the merge commit in the temporary branch GitHub creates (see &lt;a href=&quot;https://help.github.com/en/actions/reference/events-that-trigger-workflows#pull-request-event-pull_request&quot;&gt;workflow docs&lt;/a&gt;). Instead, similar to Part 1, I need to look at the &lt;code&gt;github.event.pull_request.head.sha&lt;/code&gt; property, which does point to the commit of interest.&lt;/p&gt;
&lt;p&gt;Second, both of those properties store the full sha (for example, &lt;code&gt;3b34510197cde6e3a53525d64415832f7ba34ab8&lt;/code&gt;), but I want the shortened, 8 character form: &lt;code&gt;3b345101&lt;/code&gt;. After some searching, I found the &lt;code&gt;rev-parse&lt;/code&gt; &lt;code&gt;git&lt;/code&gt; command to do the trick.&lt;/p&gt;
&lt;p&gt;Putting those concerns together, and executing with a bit of &lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html&quot;&gt;command substitution&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# Get the short form of the SHA
SHA=$(git rev-parse --short ${{ github.event.pull_request.head.sha || github.sha }})
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Part 3: Commit Message&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;git log&lt;/code&gt; will output a reverse-chronological list of commits on the current branch. And, as I found after some searching, &lt;code&gt;git log -n 1&lt;/code&gt; will output the nth most-recent commit(s)—in this case, 1. Finally, the &lt;code&gt;--format=%s&lt;/code&gt; argument will restrict output to only the subject (the first line of the message) for the commit. Putting it all together:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# Yank the commit message from the log, using the SHA
COMMIT_MSG=$(git log -n 1 --format=%s $SHA)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works great for push events. But reminder how, in Part 2, I learned that PR events’ &lt;code&gt;github.sha&lt;/code&gt; pointed to a merge commit in the temporary merge branch? That’s because the &lt;a href=&quot;https://github.com/marketplace/actions/checkout/&quot;&gt;Checkout Action&lt;/a&gt; checks out that merge branch when acting on a PR event. I can pass a &lt;code&gt;ref&lt;/code&gt; to the action to check out the code at that commit instead, and I already have the &lt;code&gt;ref&lt;/code&gt; that points to the relevant branch from Part 2: &lt;code&gt;github.event.pull_request.head.sha&lt;/code&gt;. So, modifying the workflow with this in mind, I can get the commit message of interest:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;- name: Checkout
  uses: actions/checkout@v2
  with:
    # Necessary to grab the HEAD commit from the source branch when
    # acting on a PR. Otherwise, `git log` will only contain the merge commit
    ref: ${{ github.event.pull_request.head.sha }}

- name: Create Deploy Message
  run: |
    # Grab the branch path from the appropriate (PR vs. push) property on context
    FULL_PATH_REF=&amp;quot;${{ github.event.pull_request.head.ref || github.ref }}&amp;quot;
    # Strip &amp;quot;refs/heads/&amp;quot; from the start
    REF=${FULL_PATH_REF#refs\/heads\/}
    # Get the short form of the SHA
    SHA=$(git rev-parse --short ${{ github.event.pull_request.head.sha || github.sha }})
    # Yank the commit message from the log, using the SHA
    COMMIT_MSG=$(git log -n 1 --format=%s $SHA)


# Build the site (omitted for brevity)...

# Deploy (omitted for brevity)...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Part 4: Deploy Message&lt;/h2&gt;
&lt;p&gt;All of the pieces of the message are now ready to construct the whole. I’ve been assigning each value to a variable, e.g. &lt;code&gt;REF&lt;/code&gt;, which I can reference here like &lt;code&gt;$REF&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# Create the deploy message
DEPLOY_MESSAGE=&amp;quot;$REF@$SHA: $COMMIT_MSG (${{ github.workflow }} workflow)&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that I have the message, I need to make it available to the deploy step. For that, I can graduate the &lt;code&gt;DEPLOY_MESSAGE&lt;/code&gt; variable to an &lt;em&gt;environment&lt;/em&gt; variable, using &lt;a href=&quot;https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable&quot;&gt;set-env&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# Set it in env
echo &amp;quot;::set-env name=DEPLOY_MESSAGE::$DEPLOY_MESSAGE&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the deploy step, I can reference that environment variable with &lt;code&gt;${{ env.DEPLOY_MESSAGE }}&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Part 5: All Together&lt;/h2&gt;
&lt;p&gt;Here’s the workflow with each part integrated:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;- name: Checkout
  uses: actions/checkout@v2
  with:
    # Necessary to grab the HEAD commit from the source branch when
    # acting on a PR. Otherwise, `git log` will only contain the merge commit
    ref: ${{ github.event.pull_request.head.sha }}

- name: Create Deploy Message
  run: |
    # Grab the branch path from the appropriate (PR vs. push) property on context
    FULL_PATH_REF=&amp;quot;${{ github.event.pull_request.head.ref || github.ref }}&amp;quot;
    # Strip &amp;quot;refs/heads/&amp;quot; from the start
    REF=${FULL_PATH_REF#refs\/heads\/}
    # Get the short form of the SHA
    SHA=$(git rev-parse --short ${{ github.event.pull_request.head.sha || github.sha }})
    # Yank the commit message from the log, using the SHA
    COMMIT_MSG=$(git log -n 1 --format=%s $SHA)
    # Create the deploy message
    DEPLOY_MESSAGE=&amp;quot;$REF@$SHA: $COMMIT_MSG (${{ github.workflow }} workflow)&amp;quot;
    # Set it in env
    echo &amp;quot;::set-env name=DEPLOY_MESSAGE::$DEPLOY_MESSAGE&amp;quot;

# Build the site (omitted for brevity)...

# Deploy either preview or production
- name: Deploy
  uses: nwtgck/actions-netlify@v1.1.0
  with:
    # Pass the message
    deploy-message: ${{ env.DEPLOY_MESSAGE }}
    # more options...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/kylegach/kylegach.com/blob/master/.github/workflows/ci-cd.yml&quot;&gt;full source&lt;/a&gt; of the workflow file is also available, if you find that helpful.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;To maximize clarity, I kept the narrative of this post straightforward, but the reality of developing the code shared here was not straightforward at all. The beta nature of GitHub Actions means that many aspects, like the &lt;code&gt;github&lt;/code&gt; context and the Checkout Action, are still actively changing. That can make it difficult and confusing to try to learn from community resources like blog posts, which can often describe or prescribe outdated details. Even the official support forum suffers from this issue, and I went through &lt;em&gt;many&lt;/em&gt; trial-and-error cycles discovering what still works and what does not. Ultimately, I was best served relying on the official documentation as much as possible, and always double-checking any community-provided content against it.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Building &amp; Deploying with GitHub Actions</title>
    <link href="https://kylegach.com/writing/building-and-deploying-with-github-actions/"/>
    <updated>2020-05-19T16:27:10+00:00</updated>
    <id>https://kylegach.com/writing/building-and-deploying-with-github-actions/</id>
    <content type="html">&lt;p&gt;In &lt;a href=&quot;https://kylegach.com/writing/the-work-before-the-work/&quot;&gt;The Work Before the Work&lt;/a&gt;, I set up automatic deploys with Netlify. But I have &lt;a href=&quot;https://kylegach.com/writing/v2-rebuild-and-redesign/&quot;&gt;plans&lt;/a&gt; to automate much more than deploys.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;One of the useful benefits of a static site (a website that is only static files and doesn’t require a backing server or database) is that it can be built and deployed just about anywhere, and those locations can be &lt;em&gt;different&lt;/em&gt;. &lt;a href=&quot;https://netlify.com/&quot;&gt;Netlify&lt;/a&gt; provides an amazingly simple publishing experience, using &lt;a href=&quot;https://www.digitalocean.com/community/tutorials/an-introduction-to-continuous-integration-delivery-and-deployment&quot;&gt;continuous integration and continuous deployment&lt;/a&gt; (CI/CD): push or merge to master and my site is automatically built (CI) and deployed (CD). But I wanted to extend beyond that simplicity for a few reasons. First, I want my CI pipeline to include more than just building the site. Eventually, I want to continuously audit for accessibility, performance, and other factors in the usability and quality of what I’m publishing. Second, I’ve been itching to play with &lt;a href=&quot;https://github.com/features/actions/&quot;&gt;GitHub Actions&lt;/a&gt;. Third, Netlify’s generous free plan, available for open source projects, has a limit of 300 “build minutes”/month. That’s likely fine for right now (building and deploying only takes ~0.5 build minutes right now), but the additional CI work will start consuming a lot more.&lt;/p&gt;
&lt;p&gt;I drew up a plan for where I want to go:&lt;/p&gt;
&lt;figure&gt;
   &lt;img src=&quot;https://kylegach.com/img/building-and-deploying-with-github-actions-1.svg&quot; alt=&quot;&quot;&gt;
   &lt;figcaption&gt;
      Flow diagram of the planned CI/CD flow for the site. &lt;i&gt;Made with the rather excellent &lt;a href=&quot;https://excalidraw.com/&quot;&gt;Excalidraw&lt;/a&gt;.&lt;/i&gt;
   &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;First, we’re just going to tackle the build and deploy steps:&lt;/p&gt;
&lt;figure&gt;
   &lt;img src=&quot;https://kylegach.com/img/building-and-deploying-with-github-actions-2.svg&quot; alt=&quot;&quot;&gt;
   &lt;figcaption&gt;
      Simplified flow diagram highlighting the steps of the planned CI/CD flow I&#39;ll be implementing in this post.
   &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;That diagram illustrates that upon pushing changes (to a branch with an associated pull request or to master), the site will be built and then either deployed to a preview (if a push to a pull request) or production (if a push to master). If a step fails at any point, the flow stops. Finally, either the successful deploy or failure is communicated via a comment on the pull request or commit.&lt;/p&gt;
&lt;p&gt;Before doing anything else, I need to disable automatic deploys. Going forward, I only want to deploy the site (or a preview) when it’s gone through all of those green checkmarks in the flow diagram. In Netlify, this is as easy as toggling a “stop builds” switch in my site settings.&lt;/p&gt;
&lt;p&gt;Next, I create a GitHub workflow, starting from the &lt;a href=&quot;https://github.com/actions/starter-workflows/blob/master/ci/blank.yml&quot;&gt;blank starter&lt;/a&gt;. First, I add a step to install dependencies and then build the site. Then I search the &lt;a href=&quot;https://github.com/marketplace&quot;&gt;GitHub Actions Marketplace&lt;/a&gt; for “netlify” and find &lt;a href=&quot;https://github.com/marketplace/actions/netlify-actions&quot;&gt;Netlify Actions&lt;/a&gt;, which will make it simple to deploy the site (or a preview). Following the guidance on the README, I configure the action with my options and secrets.&lt;/p&gt;
&lt;p&gt;Finally, I &lt;a href=&quot;https://github.com/kylegach/kylegach.com/pull/10&quot;&gt;create a pull request&lt;/a&gt; to test it. The workflow kicks off as soon as I submit, and 30 seconds later I have a deploy preview available from Netlify:&lt;/p&gt;
&lt;figure&gt;
   &lt;img src=&quot;https://kylegach.com/img/building-and-deploying-with-github-actions-3.jpg&quot; alt=&quot;&quot;&gt;
   &lt;figcaption&gt;
      The bottom deploy was built by Netlify; the top was built by the GitHub workflow. Note how the bottom entry contains useful information like the relevant branch, the SHA of the commit deployed, and the commit message.
   &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;That’s good enough for a starting point, but the information in the prior deploy entries is really useful, and I’d like to include it in my deploy message, to make future troubleshooting easier. To be continued…&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>RSS</title>
    <link href="https://kylegach.com/writing/rss/"/>
    <updated>2020-05-12T21:11:10+00:00</updated>
    <id>https://kylegach.com/writing/rss/</id>
    <content type="html">&lt;p&gt;Embarrassingly, despite being subscribed to hundreds of &lt;a href=&quot;https://en.wikipedia.org/wiki/RSS&quot;&gt;RSS&lt;/a&gt; feeds personally, this site has never published one. Until now!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;There were three tasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Generate the feed (&lt;a href=&quot;https://github.com/kylegach/kylegach.com/commit/e9374f2bdbc1235ff11148d6f38afbeb935bdda2&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;11ty provides an easy-to-use &lt;a href=&quot;https://www.11ty.dev/docs/plugins/rss/&quot;&gt;RSS plugin&lt;/a&gt; that does the bulk of the work for me. I only had to decide which content to include: all of &lt;a href=&quot;https://kylegach.com/writing/&quot;&gt;/writing/&lt;/a&gt;. I made one additional update: I created a new collection from which to generate the feed that is limited to the most recent 20 items in /writing/. I’ve heard stories about people with large static sites having their build times slow to a crawl because their feed generation was crawling hundreds of posts and creating an enormous file. RSS readers generally limit a feed to the most recent 10 posts or those published in the last 30 days. A limit of 20 should be well within those boundaries for the way I plan to use this site.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a page layout (&lt;a href=&quot;https://github.com/kylegach/kylegach.com/commit/8c7e531f1ec60f51412cffb945b830b385b8cbc9&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;In a misguided attempt at content portability, I had included each post’s title in the post content itself, which resulted in the title being displayed twice in a feed reader. For now, the page layout merely extends the base layout and displays the page’s title, but I can imagine many more eventual features, mostly regarding the display of metadata.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add &lt;code&gt;link&lt;/code&gt; tags to the &lt;code&gt;head&lt;/code&gt;, for auto-discovery (&lt;a href=&quot;https://github.com/kylegach/kylegach.com/commit/540e1a6f5a879150d2bcc2f1135923546b379f6e&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Following the &lt;a href=&quot;https://blog.whatwg.org/feed-autodiscovery&quot;&gt;guidance of the WHATWG&lt;/a&gt;, I added the appropriate &lt;code&gt;link&lt;/code&gt;s to the site’s &lt;code&gt;head&lt;/code&gt;, in the base layout. This will help browsers, feed readers, and other services discover my feed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After publishing those updates, I searched for the site’s name in &lt;a href=&quot;https://feedly.com/&quot;&gt;Feedly&lt;/a&gt; (my current feed reader) and subscribed. Seeing something I made displayed in a tool I’ve used every day for over a decade brought a big smile to my face.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The Work Before the Work</title>
    <link href="https://kylegach.com/writing/the-work-before-the-work/"/>
    <updated>2020-05-07T22:58:10+00:00</updated>
    <id>https://kylegach.com/writing/the-work-before-the-work/</id>
    <content type="html">&lt;p&gt;I plan to record just about every bit of work that goes into this site. But first, I had to do a bit of work to make that possible.&lt;/p&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create the &lt;a href=&quot;https://github.com/kylegach/kylegach.com/&quot;&gt;repo&lt;/a&gt; on GitHub, cloned it to my machine, and initialized the project (&lt;code&gt;yarn init&lt;/code&gt;) (&lt;a href=&quot;https://github.com/kylegach/kylegach.com/commit/bf482ed370eca036e12a0dc4fff9c5128e4ffe27&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add &lt;a href=&quot;https://11ty.dev/&quot;&gt;11ty&lt;/a&gt; with minimal content and configuration (&lt;a href=&quot;https://github.com/kylegach/kylegach.com/commit/a7e3d1f8a3f12aec0b77cb50b18045b048806a5e&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;So simple to &lt;a href=&quot;https://www.11ty.dev/docs/getting-started/&quot;&gt;get started&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Migrate (some) old content (&lt;a href=&quot;https://github.com/kylegach/kylegach.com/commit/09999f9ad4bbabcc375253dc20aee646279a2dbb&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The migration itself was as simple as copy/pasting and updating some &lt;a href=&quot;https://www.npmjs.com/package/yaml-front-matter#example&quot;&gt;frontmatter&lt;/a&gt; because all of my content, old and new, is written in &lt;a href=&quot;https://www.markdownguide.org/&quot;&gt;Markdown&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;I could use an intermediate template to translate from the old frontmatter properties to the new ones expected by 11ty, but with only three migrated posts, that seems like overkill.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Now that I have more than just a home page, I need to create a basic template to display content.&lt;/li&gt;
&lt;li&gt;I also need to ensure that media like images display correctly. Keeping all images in a single directory will make any future migrations go more smoothly and enables a more straightforward path to setting up a CMS later.&lt;/li&gt;
&lt;li&gt;Finally, I need to &lt;a href=&quot;https://www.11ty.dev/docs/collections/&quot;&gt;add a collection&lt;/a&gt; to display a list of all posts on the &lt;a href=&quot;https://kylegach.com/writing/&quot;&gt;Writing&lt;/a&gt; page.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add content to the home page, re: redesign (&lt;a href=&quot;https://github.com/kylegach/kylegach.com/commit/09999f9ad4bbabcc375253dc20aee646279a2dbb&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set up &lt;a href=&quot;https://docs.netlify.com/site-deploys/create-deploys/#deploy-with-git&quot;&gt;continuous deployment on Netlify&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Now I can push to my master branch and the site will automatically build and, if successful, deploy.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Archive full previous version of the site at &lt;a href=&quot;http://v1.kylegach.com/&quot;&gt;v1.kylegach.com&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I want to keep the old version around for posterity.&lt;/li&gt;
&lt;li&gt;I chose to not migrate some content; this provides a location to which I can redirect those requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add minimal styles (system font, max-width for content) (&lt;a href=&quot;https://5eb2266c3e3a06d7eb369ef7--kylegach.netlify.app/&quot;&gt;deploy&lt;/a&gt;, &lt;a href=&quot;https://github.com/kylegach/kylegach.com/commit/cae108d120aa565a465b5348a6d2bbdfb346dbea&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There’s a &lt;em&gt;lot&lt;/em&gt; I want to have in place before I touch styles, but a limitless line length is difficult to read and must be addressed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add task list support for Markdown, so that I could, well, use task lists in markdown (&lt;a href=&quot;https://github.com/kylegach/kylegach.com/commit/9b6dce61d576f947b0750c8b99d72fdd9656aca5&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Also enable some handy &lt;a href=&quot;https://github.com/markdown-it/markdown-it#init-with-presets-and-options&quot;&gt;markdown options&lt;/a&gt; to improve typography a bit with automatic &lt;a href=&quot;https://smartquotesforsmartpeople.com/&quot;&gt;smart quotes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Publish &lt;em&gt;&lt;a href=&quot;https://kylegach.com/writing/v2-rebuild-and-redesign/&quot;&gt;V2 Rebuild &amp;amp; Redesign&lt;/a&gt;&lt;/em&gt;, the first post on the new site ✨ (&lt;a href=&quot;https://5eb247712a4ee400060b3105--kylegach.netlify.app/writing/v2-rebuild-and-redesign/&quot;&gt;deploy&lt;/a&gt;, &lt;a href=&quot;https://github.com/kylegach/kylegach.com/commit/b29dec97c49b2f03f72925da2277b09315a427db&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;List V2-related posts on the home page (&lt;a href=&quot;https://5eb247f9e394e5000692ea8c--kylegach.netlify.app/&quot;&gt;deploy&lt;/a&gt;, &lt;a href=&quot;https://github.com/kylegach/kylegach.com/commit/2b519a7680a2fa89e50cdc2c1742a1562e99c414&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Until I have better content, it seems wise to simply list all posts tagged ‘v2’.&lt;/li&gt;
&lt;li&gt;Which means I have to add tags to posts and add another collection to collect the ‘v2’ ones.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Publish &lt;em&gt;&lt;a href=&quot;https://kylegach.com/writing/v2-goals/&quot;&gt;V2 Goals&lt;/a&gt;&lt;/em&gt; (and update &lt;em&gt;V2 Rebuild &amp;amp; Redesign&lt;/em&gt;) (&lt;a href=&quot;https://5eb3790ec451b70006a8a995--kylegach.netlify.app/writing/v2-goals/&quot;&gt;deploy&lt;/a&gt;, &lt;a href=&quot;https://github.com/kylegach/kylegach.com/commit/8721747f72be20c5796961afd73a9cfcd5857453&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Revise the first post only to record work and pull out then expand the rest of what was there into a new one.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add redirects for old content that was not migrated (&lt;a href=&quot;https://github.com/kylegach/kylegach.com/commit/35d510dc18a377de002382fe06f088a43ed8f023&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/Provider/Style/URI&quot;&gt;Cool URIs don’t change.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;I tried to do this through &lt;a href=&quot;https://docs.netlify.com/routing/redirects/&quot;&gt;Netlify’s redirects feature&lt;/a&gt;, because it’s better to redirect on the server than on the client, but ran into a snag due to how I archived the old site (also on Netlify). I’ll revisit this.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add site header with banner and update home page (&lt;a href=&quot;https://5eb38e92f126a30006ffd276--kylegach.netlify.app/&quot;&gt;deploy&lt;/a&gt;, &lt;a href=&quot;https://github.com/kylegach/kylegach.com/commit/22179bf1837a9d509b1ec018ebae689fd03c860c&quot;&gt;commit&lt;/a&gt;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If people land on the site from a page that isn’t home, I’d like them to understand the redesign going on.&lt;/li&gt;
&lt;li&gt;Also, previously, only the home page displayed the site name. Oops.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, now I have a workflow that allows me to publish posts and deploy changes with ease, and a simple foundation on which to build. Going forward, I’ll try not to dump these big lists of work, but I needed to get these essential tasks done as quickly as possible to preserve content and enable future updates.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>V2 Goals</title>
    <link href="https://kylegach.com/writing/v2-goals/"/>
    <updated>2020-05-06T20:55:10+00:00</updated>
    <id>https://kylegach.com/writing/v2-goals/</id>
    <content type="html">&lt;p&gt;Why rebuild and redesign? On an entirely new stack? In the open?&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I had a lot of fun building the &lt;a href=&quot;https://kylegach.com/writing/v2-goals/v1.kylegach.com/&quot;&gt;first version of this site&lt;/a&gt;. In &lt;a href=&quot;https://kylegach.com/writing/of-the-web/&quot;&gt;my first post&lt;/a&gt;, I wrote about some of the goals I set out to achieve. Those still stand true for this version—learn some tools, get better about accessibility (a11y), and share what I learn—but there was one goal I kept to myself: I built the site to get a job. More specifically, I built the site &lt;em&gt;in &lt;a href=&quot;https://reactjs.org/&quot;&gt;React&lt;/a&gt;&lt;/em&gt; to get a job writing React. I’m thrilled to say that it worked, remarkably well. As a UX engineer focused on design systems, I now write React code nearly every day for my career, and it’s been a good career, indeed.&lt;/p&gt;
&lt;p&gt;So why am I tearing it all down and starting over? There are several forces in play.&lt;/p&gt;
&lt;p&gt;I gleefully followed along as many &lt;a href=&quot;https://frankchimero.com/blog/&quot;&gt;designers&lt;/a&gt; &lt;a href=&quot;https://geoffgraham.me/&quot;&gt;and&lt;/a&gt; &lt;a href=&quot;https://destroytoday.com/blog/&quot;&gt;developers&lt;/a&gt; redesigned their sites in the open. And a number of others released &lt;a href=&quot;https://ethanmarcotte.com/&quot;&gt;thoughtful&lt;/a&gt;, &lt;a href=&quot;https://joshwcomeau.com/&quot;&gt;gorgeous&lt;/a&gt; &lt;a href=&quot;https://wesbos.com/new-wesbos-website/&quot;&gt;redesigns&lt;/a&gt; of their own. It looked like fun. It made me remember my own neglected home on the web, which I hadn’t touched in nearly four years. It made me want to tinker. To write. So I fired up my text editor, made some tweaks, and… couldn’t publish. The combination of the &lt;a href=&quot;https://kylegach.com/writing/v2-goals/v1.kylegach.com/colophon&quot;&gt;relatively complex tech stack&lt;/a&gt; I had taken on and years of not touching that stack was too much. I couldn’t get my site to build, and I didn’t want to fix it only to find myself in the same situation down the road. I needed to simplify.&lt;/p&gt;
&lt;p&gt;I’m sure you’ve noticed, the &lt;em&gt;whole web&lt;/em&gt; needs to simplify. My site, little more than a blog and portfolio, didn’t need React; it didn’t even really need JavaScript. I want my home on the web to reflect my values&lt;sup&gt;(citation needed)&lt;/sup&gt;, and a 721kb bundle of JS to serve text and some animated SVGs was not abiding by those values. Specifically, I have a growing appreciation for the &lt;em&gt;access&lt;/em&gt; part of accessibility. The web is for everyone, and we should be tearing down any and all barriers that unnecessarily prevent or impede anyone from accessing what we build. That belief has only been strengthened by stories of people not being able to &lt;a href=&quot;https://themarkup.org/2020/04/21/blind-users-struggle-with-state-coronavirus-websites/&quot;&gt;access the resources&lt;/a&gt; they &lt;a href=&quot;https://itif.org/publications/2020/04/15/most-state-unemployment-websites-fail-mobile-and-accessibility-tests/&quot;&gt;need the most&lt;/a&gt; right now.&lt;/p&gt;
&lt;p&gt;Thankfully, a lot’s changed in the last four years. &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers/&quot;&gt;Service workers&lt;/a&gt;! &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Web_Components/&quot;&gt;Web Components&lt;/a&gt;! &lt;a href=&quot;https://jamstack.org/&quot;&gt;Jamstack&lt;/a&gt;! &lt;a href=&quot;https://indieweb.org/&quot;&gt;Indie Web&lt;/a&gt;! &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout/&quot;&gt;CSS Grid&lt;/a&gt;! There’s a &lt;a href=&quot;https://kylegach.com/writing/v2-rebuild-and-redesign/&quot;&gt;bunch of stuff I plan to learn and integrate&lt;/a&gt;. And, most notably for this effort, there’s &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;11ty&lt;/a&gt;. I plan to write more about why I chose 11ty, but the primary motivation is simple: in the last month or so, they’ve started publishing a &lt;a href=&quot;https://www.11ty.dev/leaderboard/&quot;&gt;leaderboard&lt;/a&gt; focused on performance and a11y. And look at those scores! It was immediately apparent that something about the tool either made those things easy, encouraged caring about them, or both. It was also clear that people who care about those things liked the tool, a lot. It would be fun to appear on that leaderboard one day, but mostly I just want to align myself and my site with the values demonstrated there.&lt;/p&gt;
&lt;p&gt;So, goals for my site this time around:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Focus on accessibility and performance&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Every feature I add, every word I write will be done with an eye toward maintaining an open, fast, inclusive web.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Learn and tinker&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I did great with the “learn” part last time; this time, I want to tinker, too. It’s a much &lt;a href=&quot;https://ethanmarcotte.com/wrote/let-a-website-be-a-worry-stone/&quot;&gt;better outlet&lt;/a&gt; than mindlessly scrolling through Twitter and Instagram for the swings of boredom and nervous energy I’ve been feeling lately.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set a lasting foundation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;My tinkering will be in the direction of continual evolution. I don’t want to have to start from scratch again.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Write more&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I write every day for my job. Code, yes, but also the outline of thoughts, that leads to an email to my peers, that leads to a proposal, that leads to the code. And pull request reviews. So many reviews. A newsletter, more emails, various chat messages. Suffice it to say, it can only help my career to get better at writing. If I can muster the vulnerability to write about non-technical things, it might help in other ways. I also plan to continue sharing what I’m learning, to pay it forward for the innumerable articles, blog posts, podcasts, and conversations from which I’ve benefitted.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These words from when I kicked off this site still ring true today:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s empowering to have a place of your own, viewable to all, where every aspect is exactly as you want it. Or, at least, as close as you can get it within your knowledge and skill set… I’m eager to find more ways to express and practice building my ideal web with design, code, and prose, and I’m delighted to finally have a place to do so.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  <entry>
    <title>V2 Rebuild &amp; Redesign</title>
    <link href="https://kylegach.com/writing/v2-rebuild-and-redesign/"/>
    <updated>2020-05-05T21:54:10+00:00</updated>
    <id>https://kylegach.com/writing/v2-rebuild-and-redesign/</id>
    <content type="html">&lt;p&gt;In an effort to share openly, this post will track and record the work done for the site. &lt;a href=&quot;https://kylegach.com/writing/v2-goals&quot;&gt;Read more about why I’m rebuilding and the goals I have for this project&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Tasks&lt;/h2&gt;
&lt;p&gt;Continuously updated.&lt;/p&gt;
&lt;h3&gt;Content&lt;/h3&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; checked=&quot;&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Archive old version and content at v1 subdomain&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; checked=&quot;&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Temporary home page (&lt;a href=&quot;https://kylegach.com/writing/the-work-before-the-work/&quot;&gt;post&lt;/a&gt;)&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; checked=&quot;&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Migrate old content (&lt;a href=&quot;https://kylegach.com/writing/the-work-before-the-work/&quot;&gt;post&lt;/a&gt;)&lt;/label&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; checked=&quot;&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Work&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; checked=&quot;&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Résumé&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; checked=&quot;&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Colophon&lt;/label&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Contact form?&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Notes?&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Tweets?&lt;/label&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://mxb.dev/blog/syndicating-content-to-twitter-with-netlify-functions/&quot;&gt;https://mxb.dev/blog/syndicating-content-to-twitter-with-netlify-functions/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;https://www.11ty.dev/&quot;&gt;11ty&lt;/a&gt;&lt;/h3&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; checked=&quot;&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Initialize (&lt;a href=&quot;https://kylegach.com/writing/the-work-before-the-work/&quot;&gt;post&lt;/a&gt;)&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; checked=&quot;&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Add task list support to markdown (&lt;a href=&quot;https://kylegach.com/writing/the-work-before-the-work/&quot;&gt;post&lt;/a&gt;)&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; checked=&quot;&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; RSS&lt;/label&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/plugins/rss/&quot;&gt;https://www.11ty.dev/docs/plugins/rss/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Syntax highlighting&lt;/label&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/plugins/syntaxhighlight/&quot;&gt;https://www.11ty.dev/docs/plugins/syntaxhighlight/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Matches color mode?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Tooling&lt;/h3&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; checked=&quot;&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;https://docs.netlify.com/site-deploys/create-deploys/#deploy-with-git&quot;&gt;Netlify automatic deploys&lt;/a&gt;&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; checked=&quot;&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;https://github.com/features/actions&quot;&gt;GitHub Actions&lt;/a&gt;&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;http://commitizen.github.io/cz-cli/&quot;&gt;Commitizen&lt;/a&gt; (or something else?)&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci&quot;&gt;Lighthouse&lt;/a&gt; report&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;https://github.com/atlassian/changesets&quot;&gt;changesets&lt;/a&gt;?&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;https://eslint.org/&quot;&gt;ESLint&lt;/a&gt;&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;https://prettier.io/&quot;&gt;prettier&lt;/a&gt;&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;https://github.com/okonet/lint-staged&quot;&gt;lint-staged&lt;/a&gt; w/ &lt;a href=&quot;https://github.com/typicode/husky&quot;&gt;husky&lt;/a&gt;&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt;?&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;https://github.com/pikapkg/pack&quot;&gt;@pika/pack&lt;/a&gt;? &lt;a href=&quot;https://www.snowpack.dev/&quot;&gt;Snowpack&lt;/a&gt;?&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;https://storybook.js.org/&quot;&gt;Storybook&lt;/a&gt;&lt;/label&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://storybook.js.org/docs/guides/guide-html/&quot;&gt;https://storybook.js.org/docs/guides/guide-html/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;https://www.chromatic.com/&quot;&gt;Chromatic&lt;/a&gt;?&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;https://jestjs.io/&quot;&gt;Jest&lt;/a&gt;&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;https://testing-library.com/&quot;&gt;Testing Library&lt;/a&gt;&lt;/label&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Features&lt;/h3&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Offline support&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; “Embed” code samples/playgrounds&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Dark mode&lt;/label&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; System (default), light, dark&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Able to toggle back to system&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Icon for ‘system’ reflects current mode?&lt;/label&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;https://tinacms.org/&quot;&gt;TinaCMS&lt;/a&gt;? &lt;a href=&quot;https://www.netlifycms.org/&quot;&gt;NetlifyCMS&lt;/a&gt;? Others?&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Indie Web&lt;/label&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Web mentions&lt;/label&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Design&lt;/h3&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; checked=&quot;&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; Basic starting styles (&lt;a href=&quot;https://kylegach.com/writing/the-work-before-the-work/&quot;&gt;post&lt;/a&gt;)&lt;/label&gt;&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;label&gt;&lt;input class=&quot;task-list-item-checkbox&quot; disabled=&quot;&quot; type=&quot;checkbox&quot;&gt; &lt;a href=&quot;https://tailwindcss.com/&quot;&gt;Tailwind&lt;/a&gt;?&lt;/label&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Everything I Did to Make This Site Fast, Part 1</title>
    <link href="https://kylegach.com/writing/everything-i-did-to-make-this-site-fast-part-1/"/>
    <updated>2016-04-30T22:08:10+00:00</updated>
    <id>https://kylegach.com/writing/everything-i-did-to-make-this-site-fast-part-1/</id>
    <content type="html">&lt;p&gt;The web is best when it’s fast. A fast web doesn’t just provide a good experience, though that’s certainly important, it also ensures as many people as possible can access it at all. Many people are on slow, unstable connections. By making a site fast, you make it more likely for them to be able to use it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Some things I already did&lt;/h2&gt;
&lt;p&gt;I purposefully did &lt;em&gt;not&lt;/em&gt; do many of the tasks below until I was able to write this post, because I wanted to measure the impact of each change and be able to explain each step. However, some things that help the performance of this site would’ve been too time-consuming to build “the slow way” first only to completely change them to make them faster later. For example:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;This site is static, meaning that all of the pages are pre-rendered on the server and then served directly. Most websites have many back-and-forth requests with a server before presenting a page; this one does not, which speeds things up considerably. Serving static content typically saves ~500ms of loading time.&lt;/li&gt;
&lt;li&gt;I’m using a webfont for the headings, but the body text uses a font stack that leverages the viewer’s system’s default font, which does not need to be loaded from the server.&lt;/li&gt;
&lt;li&gt;The animations are built with SVG and driven by a ~40 Kb JS library. It would’ve been easier to just include them as gifs or videos, but that would’ve had much larger download costs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Please see the &lt;a href=&quot;https://kylegach.com/colophon/&quot;&gt;Colophon&lt;/a&gt; for more details.&lt;/p&gt;
&lt;h2&gt;Snapshot before any improvements&lt;/h2&gt;
&lt;p&gt;Before I do anything, let‘s get a snapshot of the current state of the site, to serve as a baseline. I‘m going to use the excellent &lt;a href=&quot;http://www.webpagetest.org/&quot;&gt;WebPageTest&lt;/a&gt; and &lt;a href=&quot;https://developers.google.com/speed/pagespeed/insights/&quot;&gt;PageSpeed Insights&lt;/a&gt; for this.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: For all of the WebPageTest snapshots, I‘m testing the homepage of the site, three times, on a Motorola G in Chrome with a ‘3G - slow’ connection. The PageSpeed Insight snapshots are ran once, on the homepage.&lt;/em&gt;&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
		&lt;tr&gt;
			&lt;th scope=&quot;col&quot;&gt;Metric&lt;/th&gt;
			&lt;th scope=&quot;col&quot;&gt;First View&lt;/th&gt;
			&lt;th scope=&quot;col&quot;&gt;Repeat View&lt;/th&gt;
		&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
		&lt;tr&gt;
			&lt;td&gt;PageSpeed (Mobile)&lt;/td&gt;
			&lt;td colspan=&quot;2&quot;&gt;68/100&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;PageSpeed (Desktop)&lt;/td&gt;
			&lt;td colspan=&quot;2&quot;&gt;71/100&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Speed Index (Mobile)&lt;/td&gt;
			&lt;td&gt;2025&lt;/td&gt;
			&lt;td&gt;511&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Load Time (Mobile)&lt;/td&gt;
			&lt;td&gt;8.666s&lt;/td&gt;
			&lt;td&gt;2.864s&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/tbody&gt;
	&lt;caption&gt;Summary of initial snapshot. &lt;a href=&quot;http://www.webpagetest.org/result/160430_KW_176V/&quot;&gt;Full results&lt;/a&gt;.&lt;/caption&gt;
&lt;/table&gt;
&lt;p&gt;While developing on my home’s broadband connection, I thought the site felt fairly zippy, but these baseline results make it clear that there’s plenty of room for improvement. Here’s a breakdown of the content being loaded:&lt;/p&gt;
&lt;figure&gt;
		&lt;svg width=&quot;300&quot; height=&quot;220&quot; aria-label=&quot;A chart.&quot; style=&quot;overflow: hidden;&quot;&gt;
				&lt;rect x=&quot;0&quot; y=&quot;0&quot; width=&quot;300&quot; height=&quot;220&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
				&lt;g transform=&quot;translate(-75,-40)&quot;&gt;
						&lt;rect x=&quot;276&quot; y=&quot;58&quot; width=&quot;88&quot; height=&quot;83&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
						&lt;g&gt;
								&lt;rect x=&quot;276&quot; y=&quot;58&quot; width=&quot;88&quot; height=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
								&lt;g&gt;&lt;text text-anchor=&quot;start&quot; x=&quot;291&quot; y=&quot;67.35&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#222222&quot;&gt;css (1)&lt;/text&gt;&lt;/g&gt;
								&lt;circle cx=&quot;281.5&quot; cy=&quot;63.5&quot; r=&quot;5.5&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#b2ea94&quot;&gt;&lt;/circle&gt;
						&lt;/g&gt;
						&lt;g&gt;
								&lt;rect x=&quot;276&quot; y=&quot;76&quot; width=&quot;88&quot; height=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
								&lt;g&gt;&lt;text text-anchor=&quot;start&quot; x=&quot;291&quot; y=&quot;85.35&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#222222&quot;&gt;font (1)&lt;/text&gt;&lt;/g&gt;
								&lt;circle cx=&quot;281.5&quot; cy=&quot;81.5&quot; r=&quot;5.5&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#ff523e&quot;&gt;&lt;/circle&gt;
						&lt;/g&gt;
						&lt;g&gt;
								&lt;rect x=&quot;276&quot; y=&quot;94&quot; width=&quot;88&quot; height=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
								&lt;g&gt;&lt;text text-anchor=&quot;start&quot; x=&quot;291&quot; y=&quot;103.35&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#222222&quot;&gt;html (1)&lt;/text&gt;&lt;/g&gt;
								&lt;circle cx=&quot;281.5&quot; cy=&quot;99.5&quot; r=&quot;5.5&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#82b5fc&quot;&gt;&lt;/circle&gt;
						&lt;/g&gt;
						&lt;g&gt;
								&lt;rect x=&quot;276&quot; y=&quot;112&quot; width=&quot;88&quot; height=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
								&lt;g&gt;&lt;text text-anchor=&quot;start&quot; x=&quot;291&quot; y=&quot;121.35&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#222222&quot;&gt;image (3)&lt;/text&gt;&lt;/g&gt;
								&lt;circle cx=&quot;281.5&quot; cy=&quot;117.5&quot; r=&quot;5.5&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#c49ae8&quot;&gt;&lt;/circle&gt;
						&lt;/g&gt;
						&lt;g&gt;
								&lt;rect x=&quot;276&quot; y=&quot;130&quot; width=&quot;88&quot; height=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
								&lt;g&gt;&lt;text text-anchor=&quot;start&quot; x=&quot;291&quot; y=&quot;139.35&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#222222&quot;&gt;js (2)&lt;/text&gt;&lt;/g&gt;
								&lt;circle cx=&quot;281.5&quot; cy=&quot;135.5&quot; r=&quot;5.5&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#fec584&quot;&gt;&lt;/circle&gt;
						&lt;/g&gt;
				&lt;/g&gt;
				&lt;g transform=&quot;translate(-80,-40)&quot;&gt;
						&lt;path d=&quot;M172,151L172,65A86,86,0,0,1,232.8111831820431,90.18881681795692L172,151A0,0,0,0,0,172,151&quot; stroke=&quot;#ffffff&quot; stroke-width=&quot;1&quot; fill=&quot;#b2ea94&quot;&gt;&lt;/path&gt;
						&lt;text text-anchor=&quot;start&quot; x=&quot;180.60355104213698&quot; y=&quot;96.6588801727207&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;12.5%&lt;/text&gt;
				&lt;/g&gt;
				&lt;g transform=&quot;translate(-80,-40)&quot;&gt;
						&lt;path d=&quot;M172,151L232.8111831820431,90.18881681795692A86,86,0,0,1,258,151L172,151A0,0,0,0,0,172,151&quot; stroke=&quot;#ffffff&quot; stroke-width=&quot;1&quot; fill=&quot;#ff523e&quot;&gt;&lt;/path&gt;
						&lt;text text-anchor=&quot;start&quot; x=&quot;210.61189089455615&quot; y=&quot;132.43612090582164&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;12.5%&lt;/text&gt;
				&lt;/g&gt;
				&lt;g transform=&quot;translate(-80,-40)&quot;&gt;
						&lt;path d=&quot;M172,151L258,151A86,86,0,0,1,232.8111831820431,211.81118318204307L172,151A0,0,0,0,0,172,151&quot; stroke=&quot;#ffffff&quot; stroke-width=&quot;1&quot; fill=&quot;#82b5fc&quot;&gt;&lt;/path&gt;
						&lt;text text-anchor=&quot;start&quot; x=&quot;210.61189089455618&quot; y=&quot;177.26387909417835&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;12.5%&lt;/text&gt;
				&lt;/g&gt;
				&lt;g transform=&quot;translate(-80,-40)&quot;&gt;
						&lt;path d=&quot;M172,151L86,151A86,86,0,0,1,172,65L172,151A0,0,0,0,0,172,151&quot; stroke=&quot;#ffffff&quot; stroke-width=&quot;1&quot; fill=&quot;#fec584&quot;&gt;&lt;/path&gt;
						&lt;text text-anchor=&quot;start&quot; x=&quot;116.2883393387254&quot; y=&quot;110.13833933872542&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;25%&lt;/text&gt;
				&lt;/g&gt;
				&lt;g transform=&quot;translate(-80,-40)&quot;&gt;
						&lt;path d=&quot;M172,151L232.8111831820431,211.81118318204307A86,86,0,0,1,86,151L172,151A0,0,0,0,0,172,151&quot; stroke=&quot;#ffffff&quot; stroke-width=&quot;1&quot; fill=&quot;#c49ae8&quot;&gt;&lt;/path&gt;
						&lt;text text-anchor=&quot;start&quot; x=&quot;132.396448957863&quot; y=&quot;213.0411198272793&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;37.5%&lt;/text&gt;
				&lt;/g&gt;
		&lt;/svg&gt;
		&lt;div aria-label=&quot;A tabular representation of the data in the chart.&quot; style=&quot;position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden;&quot;&gt;
				&lt;table&gt;
						&lt;thead&gt;
								&lt;tr&gt;
										&lt;th&gt;Content Type&lt;/th&gt;
										&lt;th&gt;Requests&lt;/th&gt;
								&lt;/tr&gt;
						&lt;/thead&gt;
						&lt;tbody&gt;
								&lt;tr&gt;
										&lt;td&gt;css&lt;/td&gt;
										&lt;td&gt;1&lt;/td&gt;
								&lt;/tr&gt;
								&lt;tr&gt;
										&lt;td&gt;flash&lt;/td&gt;
										&lt;td&gt;0&lt;/td&gt;
								&lt;/tr&gt;
								&lt;tr&gt;
										&lt;td&gt;font&lt;/td&gt;
										&lt;td&gt;1&lt;/td&gt;
								&lt;/tr&gt;
								&lt;tr&gt;
										&lt;td&gt;html&lt;/td&gt;
										&lt;td&gt;1&lt;/td&gt;
								&lt;/tr&gt;
								&lt;tr&gt;
										&lt;td&gt;image&lt;/td&gt;
										&lt;td&gt;3&lt;/td&gt;
								&lt;/tr&gt;
								&lt;tr&gt;
										&lt;td&gt;js&lt;/td&gt;
										&lt;td&gt;2&lt;/td&gt;
								&lt;/tr&gt;
								&lt;tr&gt;
										&lt;td&gt;other&lt;/td&gt;
										&lt;td&gt;0&lt;/td&gt;
								&lt;/tr&gt;
						&lt;/tbody&gt;
				&lt;/table&gt;
		&lt;/div&gt;
	&lt;figcaption&gt;First view content breakdown, by requests.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
	&lt;svg width=&quot;300&quot; height=&quot;220&quot; aria-label=&quot;A chart.&quot; style=&quot;overflow: hidden;&quot;&gt;
			&lt;rect x=&quot;0&quot; y=&quot;0&quot; width=&quot;300&quot; height=&quot;220&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
			&lt;g transform=&quot;translate(-80,-40)&quot;&gt;
					&lt;rect x=&quot;276&quot; y=&quot;58&quot; width=&quot;88&quot; height=&quot;83&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
					&lt;g&gt;
							&lt;rect x=&quot;276&quot; y=&quot;58&quot; width=&quot;88&quot; height=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
							&lt;g&gt;&lt;text text-anchor=&quot;start&quot; x=&quot;291&quot; y=&quot;67.35&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#222222&quot;&gt;css (6.5 Kb)&lt;/text&gt;&lt;/g&gt;
							&lt;circle cx=&quot;281.5&quot; cy=&quot;63.5&quot; r=&quot;5.5&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#b2ea94&quot;&gt;&lt;/circle&gt;
					&lt;/g&gt;
					&lt;g&gt;
							&lt;rect x=&quot;276&quot; y=&quot;76&quot; width=&quot;88&quot; height=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
							&lt;g&gt;&lt;text text-anchor=&quot;start&quot; x=&quot;291&quot; y=&quot;85.35&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#222222&quot;&gt;font (19.9 Kb)&lt;/text&gt;&lt;/g&gt;
							&lt;circle cx=&quot;281.5&quot; cy=&quot;81.5&quot; r=&quot;5.5&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#ff523e&quot;&gt;&lt;/circle&gt;
					&lt;/g&gt;
					&lt;g&gt;
							&lt;rect x=&quot;276&quot; y=&quot;94&quot; width=&quot;88&quot; height=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
							&lt;g&gt;&lt;text text-anchor=&quot;start&quot; x=&quot;291&quot; y=&quot;103.35&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#222222&quot;&gt;html (7.92 Kb)&lt;/text&gt;&lt;/g&gt;
							&lt;circle cx=&quot;281.5&quot; cy=&quot;99.5&quot; r=&quot;5.5&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#82b5fc&quot;&gt;&lt;/circle&gt;
					&lt;/g&gt;
					&lt;g&gt;
							&lt;rect x=&quot;276&quot; y=&quot;112&quot; width=&quot;88&quot; height=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
							&lt;g&gt;&lt;text text-anchor=&quot;start&quot; x=&quot;291&quot; y=&quot;121.35&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#222222&quot;&gt;image (402.1 Kb)&lt;/text&gt;&lt;/g&gt;
							&lt;circle cx=&quot;281.5&quot; cy=&quot;117.5&quot; r=&quot;5.5&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#c49ae8&quot;&gt;&lt;/circle&gt;
					&lt;/g&gt;
					&lt;g&gt;
							&lt;rect x=&quot;276&quot; y=&quot;130&quot; width=&quot;88&quot; height=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
							&lt;g&gt;&lt;text text-anchor=&quot;start&quot; x=&quot;291&quot; y=&quot;139.35&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#222222&quot;&gt;js (196 Kb)&lt;/text&gt;&lt;/g&gt;
							&lt;circle cx=&quot;281.5&quot; cy=&quot;135.5&quot; r=&quot;5.5&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#fec584&quot;&gt;&lt;/circle&gt;
					&lt;/g&gt;
			&lt;/g&gt;
			&lt;g transform=&quot;translate(-75,-40)&quot;&gt;
					&lt;path d=&quot;M172,151L172,65A86,86,0,0,1,177.51013461663786,65.17670236755914L172,151A0,0,0,0,0,172,151&quot; stroke=&quot;#ffffff&quot; stroke-width=&quot;1&quot; fill=&quot;#b2ea94&quot;&gt;&lt;/path&gt;
			&lt;/g&gt;
			&lt;g transform=&quot;translate(-75,-40)&quot;&gt;
					&lt;path d=&quot;M172,151L177.51013461663786,65.17670236755914A86,86,0,0,1,194.3200144896735,67.94690280801827L172,151A0,0,0,0,0,172,151&quot; stroke=&quot;#ffffff&quot; stroke-width=&quot;1&quot; fill=&quot;#ff523e&quot;&gt;&lt;/path&gt;
			&lt;/g&gt;
			&lt;g transform=&quot;translate(-75,-40)&quot;&gt;
					&lt;path d=&quot;M172,151L194.3200144896735,67.94690280801827A86,86,0,0,1,200.76344451294048,69.95270356297507L172,151A0,0,0,0,0,172,151&quot; stroke=&quot;#ffffff&quot; stroke-width=&quot;1&quot; fill=&quot;#82b5fc&quot;&gt;&lt;/path&gt;
			&lt;/g&gt;
			&lt;g transform=&quot;translate(-75,-40)&quot;&gt;
					&lt;path d=&quot;M172,151L92.0313275160493,182.63876453268406A86,86,0,0,1,172,65L172,151A0,0,0,0,0,172,151&quot; stroke=&quot;#ffffff&quot; stroke-width=&quot;1&quot; fill=&quot;#fec584&quot;&gt;&lt;/path&gt;
					&lt;text text-anchor=&quot;start&quot; x=&quot;109.06951167305932&quot; y=&quot;119.5486073897865&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;31%&lt;/text&gt;
			&lt;/g&gt;
			&lt;g transform=&quot;translate(-75,-40)&quot;&gt;
					&lt;path d=&quot;M172,151L200.76344451294048,69.95270356297507A86,86,0,1,1,92.0313275160493,182.63876453268406L172,151A0,0,0,1,0,172,151&quot; stroke=&quot;#ffffff&quot; stroke-width=&quot;1&quot; fill=&quot;#c49ae8&quot;&gt;&lt;/path&gt;
					&lt;text text-anchor=&quot;start&quot; x=&quot;199.4738779850747&quot; y=&quot;196.31600465641716&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;63.6%&lt;/text&gt;
			&lt;/g&gt;
			&lt;g&gt;&lt;/g&gt;
	&lt;/svg&gt;
	&lt;div aria-label=&quot;A tabular representation of the data in the chart.&quot; style=&quot;position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden;&quot;&gt;
			&lt;table&gt;
					&lt;thead&gt;
							&lt;tr&gt;
									&lt;th&gt;Content Type&lt;/th&gt;
									&lt;th&gt;Bytes&lt;/th&gt;
							&lt;/tr&gt;
					&lt;/thead&gt;
					&lt;tbody&gt;
							&lt;tr&gt;
									&lt;td&gt;css&lt;/td&gt;
									&lt;td&gt;6454&lt;/td&gt;
							&lt;/tr&gt;
							&lt;tr&gt;
									&lt;td&gt;flash&lt;/td&gt;
									&lt;td&gt;0&lt;/td&gt;
							&lt;/tr&gt;
							&lt;tr&gt;
									&lt;td&gt;font&lt;/td&gt;
									&lt;td&gt;19974&lt;/td&gt;
							&lt;/tr&gt;
							&lt;tr&gt;
									&lt;td&gt;html&lt;/td&gt;
									&lt;td&gt;7901&lt;/td&gt;
							&lt;/tr&gt;
							&lt;tr&gt;
									&lt;td&gt;image&lt;/td&gt;
									&lt;td&gt;402108&lt;/td&gt;
							&lt;/tr&gt;
							&lt;tr&gt;
									&lt;td&gt;js&lt;/td&gt;
									&lt;td&gt;196044&lt;/td&gt;
							&lt;/tr&gt;
							&lt;tr&gt;
									&lt;td&gt;other&lt;/td&gt;
									&lt;td&gt;0&lt;/td&gt;
							&lt;/tr&gt;
					&lt;/tbody&gt;
			&lt;/table&gt;
	&lt;/div&gt;
	&lt;figcaption&gt;First view content breakdown, by bytes.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Typically, the first step in improving web performance is reducing the number of requests. For this relatively simple site, that number is already pretty low. There’s only one image on the page; the other two image requests are tiny and from Google Analytics. The JavaScript is all combined into one bundle except for the Google Analytics package, which is loaded asynchronously. I could embed the font file within the CSS, using base64 encoding, but, as we’ll see later, that would make things worse in other ways.&lt;/p&gt;
&lt;p&gt;The next typical step is reducing the size of requests. That definitely applies here, so let’s dig in.&lt;/p&gt;
&lt;h2&gt;Reducing the size of images&lt;/h2&gt;
&lt;p&gt;Before this exercise, the avatar image on the home page was a 639px × 639px, 392 Kb PNG. It has a fixed-width of 150px in the design, so I resized to 300px × 300px^[The dimensions are doubled to account for retina screens.], and &lt;a href=&quot;https://imageoptim.com/&quot;&gt;optimized&lt;/a&gt; it while converting to JPEG, which brought it down to 70 Kb.&lt;/p&gt;
&lt;p&gt;But I can do more. Not every screen is retina, so I need to serve the smaller, non-retina version by default, then use &lt;a href=&quot;http://blog.cloudfour.com/responsive-images-101-part-3-srcset-display-density/&quot;&gt;&lt;code&gt;srcset&lt;/code&gt;&lt;/a&gt; to serve the retina version to screens that need it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;img src=&amp;quot;/avatar.jpg&amp;quot; srcset=&amp;quot;/avatar@2x.jpg 2x&amp;quot; alt=&amp;quot;Profile picture of Kyle&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the result:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
		&lt;tr&gt;
			&lt;th scope=&quot;col&quot;&gt;Metric&lt;/th&gt;
			&lt;th scope=&quot;col&quot;&gt;First View&lt;/th&gt;
			&lt;th scope=&quot;col&quot;&gt;Repeat View&lt;/th&gt;
		&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
		&lt;tr&gt;
			&lt;td&gt;PageSpeed (Mobile)&lt;/td&gt;
			&lt;td colspan=&quot;2&quot;&gt;90/100 (+22)&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;PageSpeed (Desktop)&lt;/td&gt;
			&lt;td colspan=&quot;2&quot;&gt;96/100 (+25)&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Speed Index (Mobile)&lt;/td&gt;
			&lt;td&gt;2056 (+1.5%)&lt;/td&gt;
			&lt;td&gt;498 (-2.5%)&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;Load Time (Mobile)&lt;/td&gt;
			&lt;td&gt;8.666s (-16.2%)&lt;/td&gt;
			&lt;td&gt;2.864s (+1.01%)&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/tbody&gt;
	&lt;caption&gt;Summary of snapshot after optimizing images. &lt;a href=&quot;http://www.webpagetest.org/result/160501_ND_TS/&quot;&gt;Full results&lt;/a&gt;.&lt;/caption&gt;
&lt;/table&gt;
&lt;p&gt;I’m not sure why the speed index on the first view and load time on the repeat view both went up slightly, but it’s such a small change that I’m not too concerned. Those oddities aside, this simple optimization resulted in big, easy speed wins.&lt;/p&gt;
&lt;p&gt;And here’s the new breakdown:&lt;/p&gt;
&lt;figure&gt;
	&lt;svg width=&quot;300&quot; height=&quot;220&quot; aria-label=&quot;A chart.&quot; style=&quot;overflow: hidden;&quot;&gt;
			&lt;rect x=&quot;0&quot; y=&quot;0&quot; width=&quot;300&quot; height=&quot;220&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
			&lt;g transform=&quot;translate(-80,-40)&quot;&gt;
					&lt;rect x=&quot;276&quot; y=&quot;58&quot; width=&quot;88&quot; height=&quot;83&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
					&lt;g&gt;
							&lt;rect x=&quot;276&quot; y=&quot;58&quot; width=&quot;88&quot; height=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
							&lt;g&gt;&lt;text text-anchor=&quot;start&quot; x=&quot;291&quot; y=&quot;67.35&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#222222&quot;&gt;css (6.5 Kb)&lt;/text&gt;&lt;/g&gt;
							&lt;circle cx=&quot;281.5&quot; cy=&quot;63.5&quot; r=&quot;5.5&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#b2ea94&quot;&gt;&lt;/circle&gt;
					&lt;/g&gt;
					&lt;g&gt;
							&lt;rect x=&quot;276&quot; y=&quot;76&quot; width=&quot;88&quot; height=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
							&lt;g&gt;&lt;text text-anchor=&quot;start&quot; x=&quot;291&quot; y=&quot;85.35&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#222222&quot;&gt;font (19.9 Kb)&lt;/text&gt;&lt;/g&gt;
							&lt;circle cx=&quot;281.5&quot; cy=&quot;81.5&quot; r=&quot;5.5&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#ff523e&quot;&gt;&lt;/circle&gt;
					&lt;/g&gt;
					&lt;g&gt;
							&lt;rect x=&quot;276&quot; y=&quot;94&quot; width=&quot;88&quot; height=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
							&lt;g&gt;&lt;text text-anchor=&quot;start&quot; x=&quot;291&quot; y=&quot;103.35&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#222222&quot;&gt;html (7.92 Kb)&lt;/text&gt;&lt;/g&gt;
							&lt;circle cx=&quot;281.5&quot; cy=&quot;99.5&quot; r=&quot;5.5&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#82b5fc&quot;&gt;&lt;/circle&gt;
					&lt;/g&gt;
					&lt;g&gt;
							&lt;rect x=&quot;276&quot; y=&quot;112&quot; width=&quot;88&quot; height=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
							&lt;g&gt;&lt;text text-anchor=&quot;start&quot; x=&quot;291&quot; y=&quot;121.35&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#222222&quot;&gt;image (70.1 Kb)&lt;/text&gt;&lt;/g&gt;
							&lt;circle cx=&quot;281.5&quot; cy=&quot;117.5&quot; r=&quot;5.5&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#c49ae8&quot;&gt;&lt;/circle&gt;
					&lt;/g&gt;
					&lt;g&gt;
							&lt;rect x=&quot;276&quot; y=&quot;130&quot; width=&quot;88&quot; height=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill-opacity=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;&lt;/rect&gt;
							&lt;g&gt;&lt;text text-anchor=&quot;start&quot; x=&quot;291&quot; y=&quot;139.35&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#222222&quot;&gt;js (196 Kb)&lt;/text&gt;&lt;/g&gt;
							&lt;circle cx=&quot;281.5&quot; cy=&quot;135.5&quot; r=&quot;5.5&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#fec584&quot;&gt;&lt;/circle&gt;
					&lt;/g&gt;
			&lt;/g&gt;
			&lt;g transform=&quot;translate(-80,-40)&quot;&gt;
					&lt;path d=&quot;M172,151L172,65A86,86,0,0,1,183.80813767046166,65.81450895395729L172,151A0,0,0,0,0,172,151&quot; stroke=&quot;#ffffff&quot; stroke-width=&quot;1&quot; fill=&quot;#b2ea94&quot;&gt;&lt;/path&gt;
			&lt;/g&gt;
			&lt;g transform=&quot;translate(-80,-40)&quot;&gt;
					&lt;path d=&quot;M172,151L183.80813767046166,65.81450895395729A86,86,0,0,1,217.36564337247916,77.93866685173997L172,151A0,0,0,0,0,172,151&quot; stroke=&quot;#ffffff&quot; stroke-width=&quot;1&quot; fill=&quot;#ff523e&quot;&gt;&lt;/path&gt;
			&lt;/g&gt;
			&lt;g transform=&quot;translate(-80,-40)&quot;&gt;
					&lt;path d=&quot;M172,151L217.36564337247916,77.93866685173997A86,86,0,0,1,228.79610027103274,86.4228910990683L172,151A0,0,0,0,0,172,151&quot; stroke=&quot;#ffffff&quot; stroke-width=&quot;1&quot; fill=&quot;#82b5fc&quot;&gt;&lt;/path&gt;
			&lt;/g&gt;
			&lt;g transform=&quot;translate(-80,-40)&quot;&gt;
					&lt;path d=&quot;M172,151L228.79610027103274,86.4228910990683A86,86,0,0,1,242.1691060513362,200.72219379669738L172,151A0,0,0,0,0,172,151&quot; stroke=&quot;#ffffff&quot; stroke-width=&quot;1&quot; fill=&quot;#c49ae8&quot;&gt;&lt;/path&gt;
					&lt;text text-anchor=&quot;start&quot; x=&quot;214.97755276961263&quot; y=&quot;148.00813279040895&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;23.3%&lt;/text&gt;
			&lt;/g&gt;
			&lt;g transform=&quot;translate(-80,-40)&quot;&gt;
					&lt;path d=&quot;M172,151L242.1691060513362,200.72219379669738A86,86,0,1,1,172,65L172,151A0,0,0,1,0,172,151&quot; stroke=&quot;#ffffff&quot; stroke-width=&quot;1&quot; fill=&quot;#fec584&quot;&gt;&lt;/path&gt;
					&lt;text text-anchor=&quot;start&quot; x=&quot;104.38135169191824&quot; y=&quot;181.79562221607026&quot; font-family=&quot;Arial&quot; font-size=&quot;11&quot; stroke=&quot;none&quot; stroke-width=&quot;0&quot; fill=&quot;#ffffff&quot;&gt;65.2%&lt;/text&gt;
			&lt;/g&gt;
			&lt;g&gt;&lt;/g&gt;
	&lt;/svg&gt;
	&lt;div aria-label=&quot;A tabular representation of the data in the chart.&quot; style=&quot;position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden;&quot;&gt;
			&lt;table&gt;
					&lt;thead&gt;
							&lt;tr&gt;
									&lt;th&gt;Content Type&lt;/th&gt;
									&lt;th&gt;Bytes&lt;/th&gt;
							&lt;/tr&gt;
					&lt;/thead&gt;
					&lt;tbody&gt;
							&lt;tr&gt;
									&lt;td&gt;css&lt;/td&gt;
									&lt;td&gt;6583&lt;/td&gt;
							&lt;/tr&gt;
							&lt;tr&gt;
									&lt;td&gt;flash&lt;/td&gt;
									&lt;td&gt;0&lt;/td&gt;
							&lt;/tr&gt;
							&lt;tr&gt;
									&lt;td&gt;font&lt;/td&gt;
									&lt;td&gt;19974&lt;/td&gt;
							&lt;/tr&gt;
							&lt;tr&gt;
									&lt;td&gt;html&lt;/td&gt;
									&lt;td&gt;7920&lt;/td&gt;
							&lt;/tr&gt;
							&lt;tr&gt;
									&lt;td&gt;image&lt;/td&gt;
									&lt;td&gt;70060&lt;/td&gt;
							&lt;/tr&gt;
							&lt;tr&gt;
									&lt;td&gt;js&lt;/td&gt;
									&lt;td&gt;195757&lt;/td&gt;
							&lt;/tr&gt;
							&lt;tr&gt;
									&lt;td&gt;other&lt;/td&gt;
									&lt;td&gt;0&lt;/td&gt;
							&lt;/tr&gt;
					&lt;/tbody&gt;
			&lt;/table&gt;
	&lt;/div&gt;
	&lt;figcaption&gt;First view content breakdown after optimizing images, by bytes.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/kylegach/kylegach_com/commit/b911321f418feb78f7f11f6466e23bdaea4c0d9d&quot;&gt;Performance commit #1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: Even though I’m only testing the homepage, I went ahead and did this exercise for all images on the site.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Reducing the size of JavaScript and other resources&lt;/h2&gt;
&lt;p&gt;190 Kb of JavaScript is quite a lot, especially since that size is after gzipping. For now, though, I’m going to leave it be, as I would like to see how fast I can make this site while it still runs React client-side. I suspect that I’ll need to remove React to meet my informal goal of a speed index under 1000, but I’ll save that for last.&lt;/p&gt;
&lt;p&gt;My CSS is only 6.5 Kb (gzipped). At that size, that’s too small to justify the effort to make it any smaller^[You should always endeavor to keep your CSS as small and simple as you reasonably can. The effort I’m avoiding here is because my styles are already &lt;a href=&quot;http://mrmrs.io/writing/2016/03/24/scalable-css/&quot;&gt;architected in a way to keep them very small&lt;/a&gt;. Any further optimization will require either a lot of manual fine-tuning that could break future updates or an automated process using something like &lt;a href=&quot;https://github.com/purifycss/purifycss&quot;&gt;PurifyCSS&lt;/a&gt;. I intend to implement the latter in a future post.]. There are other reasons being the filesize to make CSS as small as possible, which I’ll cover later in this post.&lt;/p&gt;
&lt;h2&gt;Absolute vs. perceived performance&lt;/h2&gt;
&lt;p&gt;So far, I’ve only made changes that affected the page load time/size, which correlates to the &lt;strong&gt;absolute&lt;/strong&gt; page speed. But that’s not all that matters. Arguably, &lt;a href=&quot;http://blog.teamtreehouse.com/perceived-performance&quot;&gt;&lt;strong&gt;perceived&lt;/strong&gt; performance&lt;/a&gt; matters even more, as that affects how fast your site &lt;em&gt;feels&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;For example, check out this filmstrip view of a portion of the experience waiting for the site to load on 3G:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://kylegach.com/img/v1.filmstrip.jpg&quot; alt=&quot;Filmstrip view of this site loading on a mobile device&quot;&gt;&lt;/p&gt;
&lt;p&gt;There’s a full 1.5 seconds between the initial content displaying and the webfont displaying. Worse, because I reference the webfont directly in CSS, via &lt;code&gt;@font-face&lt;/code&gt;, there’s a &lt;abbr title=&quot;Flash of Invisible Text&quot;&gt;FOIT&lt;/abbr&gt; making the headings completely unreadable until the webfont has finished loading. This is unacceptable.&lt;/p&gt;
&lt;h2&gt;Preventing a Flash of Invisible Text (FOIT)&lt;/h2&gt;
&lt;p&gt;I’m going to use &lt;a href=&quot;https://github.com/bramstein/fontfaceobserver&quot;&gt;FontFaceObserver&lt;/a&gt; to instead only apply the webfont to headings after it is loaded. While it is loading, they’ll use the same font stack as the body text, changing the &lt;abbr title=&quot;Flash of Invisible Text&quot;&gt;FOIT&lt;/abbr&gt; into a &lt;abbr title=&quot;Flash of Unstyled Text&quot;&gt;FOUT&lt;/abbr&gt;. In some scenarios, this can provide a poor experience just like a &lt;abbr title=&quot;Flash of Invisible Text&quot;&gt;FOIT&lt;/abbr&gt;, but I have a couple things going for me:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The body text is set in a font that doesn’t have to load at all, meaning it will display correctly immediately. So when the headings also use that font while the web font loads, they’ll match the rest of the site.&lt;/li&gt;
&lt;li&gt;The webfont I’ve chosen for the headings, League Spartan, has a very similar baseline &amp;amp; caps height, so shifts after the webfont loads are minimal.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After making the change, the &lt;a href=&quot;http://www.webpagetest.org/video/compare.php?tests=160501_Q3_SH8-r:2-c:0&quot;&gt;filmstrip&lt;/a&gt; now looks like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://kylegach.com/img/v1.filmstrip2.jpg&quot; alt=&quot;Filmstrip view of this site loading on a mobile device, after applying a font loading strategy&quot;&gt;&lt;/p&gt;
&lt;p&gt;Much better! You can see how the headings now display for a brief moment using the same font as the rest of the text, and then switch to the webfont after it has finished loading.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/kylegach/kylegach_com/commit/6e9d316bff15a86262cd3abad7ed90102796e263&quot;&gt;Performance commit #2&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Clearing the critical path&lt;/h2&gt;
&lt;p&gt;What you can’t see in the filmstrips above is all that time before anything is visible:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://kylegach.com/img/v1.filmstrip3.jpg&quot; alt=&quot;Full filmstrip of site loading&quot;&gt;&lt;/p&gt;
&lt;p&gt;Part of that is because it must download the full CSS file before it displays anything. In other words, the &lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-blocking-css?hl=en&quot;&gt;CSS is blocking the critical path&lt;/a&gt;, which happens regardless of the file’s size. So even though the size is fairly small, it has an outsized effect on the perceived performance of the site.&lt;/p&gt;
&lt;p&gt;I’ll cover my approach for solving that issue (and possibly removing React on the client-side) in a future post.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Everything I Did to Make This Site Accessible</title>
    <link href="https://kylegach.com/writing/everything-i-did-to-make-this-site-accessible/"/>
    <updated>2016-04-16T04:54:54+00:00</updated>
    <id>https://kylegach.com/writing/everything-i-did-to-make-this-site-accessible/</id>
    <content type="html">&lt;p&gt;I believe the web is meant to be open and available to everyone, no matter who they are, what device/software they’re using, or the speed/quality of the network they’re on.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Accessibility (also known as &lt;a href=&quot;https://en.wikipedia.org/wiki/Numeronym&quot;&gt;a11y&lt;/a&gt;) is so much bigger than just making things work for people with no or low vision. But, even if you define it so narrowly, that’s still &lt;a href=&quot;http://www.who.int/mediacentre/factsheets/fs282/en/&quot;&gt;285 million people&lt;/a&gt; or ~5% of the world’s population. What follows is a collection of everything I’ve done to make this site as accessible as I could.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: I‘m using &lt;a href=&quot;http://a11yproject.com/checklist.html&quot;&gt;The A11y Project‘s helpful checklist&lt;/a&gt; as a rough starting point for this post.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Not relying on JavaScript (Progressive Enhancement)&lt;/h2&gt;
&lt;p&gt;This site is built using &lt;a href=&quot;http://facebook.github.io/react/&quot;&gt;React&lt;/a&gt;, a JS library. &lt;em&gt;But&lt;/em&gt;, it renders everything from the server before all that JS does anything. The JS then progressively enhances the site to enable things like super-fast additional page loads and the SVG animations. This means that the site will be accessible even if the JS were to fail for any reason. You may think the numbers for that are small… like, 1%. Keep in mind that it’s not 1% of people who always encounter a broken site, and 99% of people who don’t. It’s 1% of &lt;em&gt;visits&lt;/em&gt;. I stole that line from &lt;a href=&quot;http://kryogenix.org/code/browser/why-availability/&quot;&gt;this wonderful illustration of the phenomenon&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also, progressive enhancement makes supporting older browsers &lt;em&gt;so much easier&lt;/em&gt;. Because the site will always work without JS, you can &lt;a href=&quot;http://responsivenews.co.uk/post/18948466399/cutting-the-mustard&quot;&gt;cut the mustard&lt;/a&gt; so that your JS only runs on your supported browsers. Meaning you don’t ever have to write JS to work in non-modern browsers.&lt;/p&gt;
&lt;h2&gt;Making it responsive&lt;/h2&gt;
&lt;p&gt;The only reasonable way I know of to ensure a website is usable on &lt;em&gt;any&lt;/em&gt; device/software is &lt;a href=&quot;https://bradfrost.github.io/this-is-responsive/&quot;&gt;Responsive Web Design&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Writing semantic HTML&lt;/h2&gt;
&lt;p&gt;The easiest way to make something accessible is when you get it for free. By using &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;footer&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;,  and other elements appropriately, you build accessibility into the very structure of your app. This includes using &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, etc… in a sensible order. I reviewed this site’s code and found some areas I could improve.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/kylegach/kylegach_com/commit/9b7d4b063fef4d1e0a8997a739bdf96598479154&quot;&gt;A11y commit #1&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Supplanting semantic HTML with &lt;code&gt;aria&lt;/code&gt; landmark roles&lt;/h2&gt;
&lt;p&gt;While most browsers automatically associate, say, &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt; with &lt;code&gt;aria-role=&amp;quot;main&amp;quot;&lt;/code&gt;, &lt;a href=&quot;http://alistapart.com/column/wai-finding-with-aria-landmark-roles&quot;&gt;not all do&lt;/a&gt;. So it’s best to go ahead and define those yourself.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/kylegach/kylegach_com/commit/1e24b97eddc4ad5dd853af0e2c6954823de675e5&quot;&gt;A11y commit #2&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Focus states&lt;/h2&gt;
&lt;p&gt;A lot of sites have some CSS like this to remove the default dotted outline when elements are focused in some browsers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;a:focus {
  outline: none;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don‘t do that! If you absolutely must remove it, you also &lt;em&gt;must&lt;/em&gt; define your own focus styles.&lt;/p&gt;
&lt;h2&gt;Use alt text (and the equivalent for SVG)&lt;/h2&gt;
&lt;p&gt;Any image in the content of a site must have an appropriate &lt;code&gt;alt&lt;/code&gt; attribute defined. The only exception is images that are purely decorative.&lt;/p&gt;
&lt;p&gt;For SVGs, you can use the &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;desc&amp;gt;&lt;/code&gt; elements to describe the graphic in combination with &lt;code&gt;aria&lt;/code&gt; attributes. See the commit for examples.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/kylegach/kylegach_com/commit/02f01c7b3eb7df5ceb8d2d1fa4f95c6494e6744d&quot;&gt;A11y commit #3&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Test for sufficient color contrast and color blindness&lt;/h2&gt;
&lt;p&gt;Researchers have determined a minimum threshold for foreground/background color contrast that is readable by most people, which is specified as part of &lt;a href=&quot;https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html&quot;&gt;WCAG&lt;/a&gt;. You can use a tool like &lt;a href=&quot;https://chrome.google.com/webstore/detail/axe/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US&quot;&gt;aXe&lt;/a&gt;, which integrates into Chrome‘s Dev Tools, or &lt;a href=&quot;http://khan.github.io/tota11y/&quot;&gt;tota11y&lt;/a&gt;, which can be integrated into your site or used as a bookmarklet, to check if the text of your site meets this threshold. There are some gotchas, though:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It will only test actual text and backgrounds, not text that is part of or on top of an image.&lt;/li&gt;
&lt;li&gt;It cannot determine the contrast of pseudo-elements (&lt;code&gt;::before&lt;/code&gt; &amp;amp; &lt;code&gt;::after&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After running checks, if I find any colors that need changed, I like to use &lt;a href=&quot;http://jxnblk.com/colorable/demos/text/&quot;&gt;Colorable&lt;/a&gt; to find values with sufficient contrast.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/kylegach/kylegach_com/commit/f90a098774856b657e3c19c75239c5a4ec2baecd&quot;&gt;A11y commit #4&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://github.com/kylegach/kylegach_com/commit/646dec0acd9c51657fcda47caeaed860b9734a49&quot;&gt;A11y commit #5&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Consider a “Skip to content” link&lt;/h2&gt;
&lt;p&gt;Sometimes a site can have a lot of stuff that a person using a screenreader or restricted to a keyboard would have to wade through before they get to the content. Including a &lt;a href=&quot;https://www.bignerdranch.com/blog/web-accessibility-skip-navigation-links/&quot;&gt;link to skip down to the content&lt;/a&gt; in the very beginning of your page that is visually hidden until focused is a nice way to help them out.&lt;/p&gt;
&lt;p&gt;This site has a very minimal header and the primary navigation is at the bottom of the page, so the link I‘m adding will be “Skip to navigation”.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/kylegach/kylegach_com/commit/5c8529bc0cc50fa15cd15f3a8c8bf562e1deed13&quot;&gt;A11y commit #6&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://github.com/kylegach/kylegach_com/commit/bf4617b170a383586ba9454e6f16dedd727cde91&quot;&gt;A11y commit #7&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Make sure to use descriptive links&lt;/h2&gt;
&lt;p&gt;Consider the post teasers on my &lt;a href=&quot;https://kylegach.com/writing/&quot;&gt;Writing&lt;/a&gt; page. They have a title, a brief excerpt of the post, and a Keep Reading… link. Sighted users can see that the “Keep Reading…” belongs to the post above it, but screen readers have no way of relaying that information to their users. That is, not without a little help.&lt;/p&gt;
&lt;p&gt;We can use &lt;code&gt;aria&lt;/code&gt; attributes again to add a more descriptive label to those links:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;article role=&amp;quot;article&amp;quot;&amp;gt;
  &amp;lt;h3 id=&amp;quot;everything-i-did-to-make-this-site-accessible&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/writing/everything-i-did-to-make-this-site-accessible/&amp;quot;&amp;gt;Everything I Did to Make This Site Accessible&amp;lt;/a&amp;gt;&amp;lt;/h3&amp;gt;
  &amp;lt;em&amp;gt;&amp;lt;span title=&amp;quot;April 12, 2016&amp;quot;&amp;gt;3 days ago&amp;lt;/span&amp;gt;&amp;lt;/em&amp;gt;
  &amp;lt;div&amp;gt;I believe the web is meant to be open and available to everyone, no matter who they are, what device/software...&amp;lt;/div&amp;gt;
  &amp;lt;a href=&amp;quot;/writing/everything-i-did-to-make-this-site-accessible/&amp;quot; aria-labelledby=&amp;quot;everything-i-did-to-make-this-site-accessible&amp;quot;&amp;gt;Keep reading…&amp;lt;/a&amp;gt;
&amp;lt;/article&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Thanks to &lt;a href=&quot;http://codepen.io/grayghostvisuals/pen/Gtoua&quot;&gt;this CodePen&lt;/a&gt; by &lt;a href=&quot;http://grayghostvisuals.com/&quot;&gt;Gray Ghost Visuals&lt;/a&gt; for the technique.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You should also generally avoid using generic phrases like “Click here” for your links, because they provide very little context.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/kylegach/kylegach_com/commit/f5e61a774cf339f30988ad9566a017aecee049b2&quot;&gt;A11y commit #8&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Test, test, test&lt;/h2&gt;
&lt;p&gt;After you’ve done everything you can, you should test your site using assistive technology tools. Ideally, you‘d do so with someone who uses such tools on a regular basis, but you can simply use the tools yourself in a pinch. If you‘re on a Mac, you have &lt;a href=&quot;https://www.apple.com/voiceover/info/guide/&quot;&gt;VoiceOver&lt;/a&gt; built in.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Of the Web</title>
    <link href="https://kylegach.com/writing/of-the-web/"/>
    <updated>2016-04-12T14:01:34+00:00</updated>
    <id>https://kylegach.com/writing/of-the-web/</id>
    <content type="html">&lt;p&gt;I’ve been &lt;em&gt;on&lt;/em&gt; the web for most of my life, but, without a site to call home, I haven’t been &lt;a href=&quot;https://adactio.com/journal/9016&quot;&gt;&lt;em&gt;of&lt;/em&gt; the web&lt;/a&gt; for far too long.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I’m proud to announce the launch of this site, by far my most personal website ever. Making this spot on the web mine has taken great effort and care, and I’ve deeply enjoyed all of it^[Well, almost all of it. Those SVG animations were fairly tedious to make.]. Like any successful project, I defined a vision/goals for this site before I started any work:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://kylegach.com/colophon/&quot;&gt;Learn and employ many new tools&lt;/a&gt; to accurately demonstrate my understanding of building for the web, in a manner I believe to be best&lt;/strong&gt;. This site’s primary purpose is to serve as my portfolio, and I wanted to use this site as a way to show off a bit, when doing so isn’t always appropriate or possible for the projects I work on at &lt;a href=&quot;http://civicplus.com/&quot;&gt;CivicPlus&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Make this site as accessible and fast as I can&lt;/strong&gt;. The web is best when it is open to all, and making things accessible and fast (which are often overlapping concerns) helps provide that. I’ll probably be writing much more about this.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Build for learnability&lt;/strong&gt;. I learned everything I know about building for the web from the generosity and kindness of others who shared their knowledge, tools, struggles, and passions. I owe my entire career to the web community, and I want to give back. While viewing source in the age of module bundlers and style processors is of less utility than it used to be, I hope that sharing this &lt;a href=&quot;https://github.com/kylegach/kylegach_com&quot;&gt;site’s source code&lt;/a&gt; can help someone curious enough to dig in.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It’s empowering to have a place of your own, viewable to all, where every aspect is exactly as you want it. Or, at least, as close as you can get it within your knowledge and skill set. For example, I get frustrated when I have to look at a white screen at night, so I made a “night mode” that automatically flips on after sunset. I’m eager to find more ways to express and practice building my ideal web with design, code, and prose, and I’m delighted to finally have a place to do so.&lt;/p&gt;
</content>
  </entry>
</feed>