<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/css" href="https://www.aaron-gustafson.com/c/feed.min.css" ?><feed xmlns="http://www.w3.org/2005/Atom"
      xmlns:amg="https://www.aaron-gustafson.com.com/amg-dtd/"><title>Aaron Gustafson: Content tagged performance</title><subtitle>The latest 20 posts and links tagged performance.</subtitle><id>https://www.aaron-gustafson.com</id><link href="https://www.aaron-gustafson.com/feeds/performance.xml" rel="self"/><link href="https://www.aaron-gustafson.com"/><author><name>Aaron Gustafson</name><uri>https://www.aaron-gustafson.com</uri></author><updated>2025-12-10T17:15:54Z</updated><entry><id>https://www.aaron-gustafson.com/notebook/lazy-loading-images-based-on-screen-size/</id><title type="html"><![CDATA[✍🏻 Lazy Loading Images Based on Screen Size]]></title><link href="https://www.aaron-gustafson.com/notebook/lazy-loading-images-based-on-screen-size/" rel="alternate" type="text/html" /><published>2025-12-10T17:15:54Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>Native lazy loading and <code>srcset</code> are great, but they have a limitation: they always load <em>some</em> variant of the image. The <code>lazy-img</code> web component takes a different approach—it can completely skip loading images when they don’t meet your criteria, whether that’s screen size, container size, or visibility in the viewport.</p><p>This is particularly valuable for mobile users on slow connections or limited data plans. If an image is only meaningful on larger screens, why waste their bandwidth loading it at all?</p><h2 id="the-performance-benefit" tabindex="-1"><a class="header-anchor" href="#the-performance-benefit" aria-hidden="true">#</a> The performance benefit</h2><p>Unlike <code>picture</code> or <code>srcset</code>, which always load some image variant, <code>lazy-img</code> can <strong>completely skip loading images</strong> on screens or containers below your specified threshold. Set <code>min-inline-size=&quot;768px&quot;</code> and mobile users will never download that image at all—saving data and speeding up page loads.</p><p>Once an image is loaded, however, it remains loaded even if the viewport or container is resized below the threshold. This is intentional—the component prevents unnecessary downloads but doesn’t unload images already in memory. You can control visibility with CSS if needed using the <code>loaded</code> and <code>qualifies</code> attributes (which we’ll get to shortly).</p><h2 id="basic-usage" tabindex="-1"><a class="header-anchor" href="#basic-usage" aria-hidden="true">#</a> Basic usage</h2><p>The <code>lazy-img</code> works pretty much identically to a regular <code>img</code> element, with all the attributes you know and love:</p><pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>lazy-img</span><span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>image.jpg<span class="token punctuation">”</span></span><span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>A beautiful image<span class="token punctuation">”</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>lazy-img</span><span class="token punctuation">&gt;</span></span></code></pre><p>But that’s not very interesting. The real power comes from conditional loading.</p><h2 id="container-queries-(default)" tabindex="-1"><a class="header-anchor" href="#container-queries-(default)" aria-hidden="true">#</a> Container queries (default)</h2><p>Load an image only when its container reaches a minimum width:</p><pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>lazy-img</span><span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>large-image.jpg<span class="token punctuation">”</span></span><span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>Large image<span class="token punctuation">”</span></span><span class="token attr-name">min-inline-size</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>500px<span class="token punctuation">”</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>lazy-img</span><span class="token punctuation">&gt;</span></span></code></pre><p>The image loads when the <code>lazy-img</code> element’s container reaches 500px wide. This is the default query mode—it uses <code>ResizeObserver</code> to watch the container size.</p><h2 id="media-queries" tabindex="-1"><a class="header-anchor" href="#media-queries" aria-hidden="true">#</a> Media queries</h2><p>You can lazy load images based on viewport width instead by switching to media query mode:</p><pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>lazy-img</span><span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>desktop-image.jpg<span class="token punctuation">”</span></span><span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>Desktop image<span class="token punctuation">”</span></span><span class="token attr-name">min-inline-size</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>768px<span class="token punctuation">”</span></span><span class="token attr-name">query</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>media<span class="token punctuation">”</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>lazy-img</span><span class="token punctuation">&gt;</span></span></code></pre><p>With this configuration, the image loads when the browser window is at least 768px wide.</p><h2 id="view-mode-(scroll-based-loading)" tabindex="-1"><a class="header-anchor" href="#view-mode-(scroll-based-loading)" aria-hidden="true">#</a> View mode (scroll-based loading)</h2><p>Load images when they scroll into view using <code>IntersectionObserver</code> by switching to the “view” query type:</p><pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>lazy-img</span><span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>image.jpg<span class="token punctuation">”</span></span><span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>Loads when scrolled into view<span class="token punctuation">”</span></span><span class="token attr-name">query</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>view<span class="token punctuation">”</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>lazy-img</span><span class="token punctuation">&gt;</span></span></code></pre><p>The default behavior (<code>view-range-start=&quot;entry 0%&quot;</code>) loads as soon as any part of the image enters the viewport.</p><p>Control when images load with the <code>view-range-start</code> attribute:</p><p><strong>Load when 50% visible:</strong></p><pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>lazy-img</span><span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>image.jpg<span class="token punctuation">”</span></span><span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>Loads when half visible<span class="token punctuation">”</span></span><span class="token attr-name">query</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>view<span class="token punctuation">”</span></span><span class="token attr-name">view-range-start</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>entry 50%<span class="token punctuation">”</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>lazy-img</span><span class="token punctuation">&gt;</span></span></code></pre><p><strong>Preload before entering viewport:</strong></p><pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>lazy-img</span><span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>image.jpg<span class="token punctuation">”</span></span><span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>Preloads 200px before visible<span class="token punctuation">”</span></span><span class="token attr-name">query</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>view<span class="token punctuation">”</span></span><span class="token attr-name">view-range-start</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>entry -200px<span class="token punctuation">”</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>lazy-img</span><span class="token punctuation">&gt;</span></span></code></pre><p>This creates a smooth user experience—images are already loaded by the time users scroll to them.</p><h2 id="responsive-images" tabindex="-1"><a class="header-anchor" href="#responsive-images" aria-hidden="true">#</a> Responsive images</h2><p>As with regular images, you can use <code>srcset</code> and <code>sizes</code> for responsive images:</p><pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>lazy-img</span><span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>image-800.jpg<span class="token punctuation">”</span></span><span class="token attr-name">srcset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>image-400.jpg 400w,image-800.jpg 800w,image-1200.jpg 1200w<span class="token punctuation">”</span></span><span class="token attr-name">sizes</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>(max-width: 600px) 400px,(max-width: 1000px) 800px,1200px<span class="token punctuation">”</span></span><span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>Responsive image<span class="token punctuation">”</span></span><span class="token attr-name">min-inline-size</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>400px<span class="token punctuation">”</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>lazy-img</span><span class="token punctuation">&gt;</span></span></code></pre><p>The component waits until the conditions are met before loading a real image and the browser takes over from there.</p><h2 id="named-breakpoints" tabindex="-1"><a class="header-anchor" href="#named-breakpoints" aria-hidden="true">#</a> Named breakpoints</h2><p>You can also define named breakpoints using CSS custom properties:</p><pre class="language-css" tabindex="0"><code class="language-css"><span class="token selector">:root</span><span class="token punctuation">{</span><span class="token property">–lazy-img-mq</span><span class="token punctuation">:</span> small<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token atrule"><span class="token rule">@media</span><span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 768px<span class="token punctuation">)</span></span><span class="token punctuation">{</span><span class="token selector">:root</span><span class="token punctuation">{</span><span class="token property">–lazy-img-mq</span><span class="token punctuation">:</span> medium<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token atrule"><span class="token rule">@media</span><span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 1024px<span class="token punctuation">)</span></span><span class="token punctuation">{</span><span class="token selector">:root</span><span class="token punctuation">{</span><span class="token property">–lazy-img-mq</span><span class="token punctuation">:</span> large<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>Then reference them in your markup:</p><pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>lazy-img</span><span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>image.jpg<span class="token punctuation">”</span></span><span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>Image with named breakpoints<span class="token punctuation">”</span></span><span class="token attr-name">named-breakpoints</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>medium, large<span class="token punctuation">”</span></span><span class="token attr-name">query</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>media<span class="token punctuation">”</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>lazy-img</span><span class="token punctuation">&gt;</span></span></code></pre><p>The image loads when <code>–lazy-img-mq</code> matches “medium” or “large”.</p><h2 id="preventing-layout-shift" tabindex="-1"><a class="header-anchor" href="#preventing-layout-shift" aria-hidden="true">#</a> Preventing layout shift</h2><p>As with regular images, don’t forget to use <code>width</code> and <code>height</code> attributes to prevent Cumulative Layout Shift (CLS):</p><pre class="language-html" tabindex="0"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>lazy-img</span><span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>image.jpg<span class="token punctuation">”</span></span><span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>A beautiful image<span class="token punctuation">”</span></span><span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>800<span class="token punctuation">”</span></span><span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>600<span class="token punctuation">”</span></span><span class="token attr-name">min-inline-size</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">“</span>768px<span class="token punctuation">”</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>lazy-img</span><span class="token punctuation">&gt;</span></span></code></pre><p>The browser reserves the correct space while the image loads, preventing content from jumping around.</p><h2 id="state-attributes-for-styling" tabindex="-1"><a class="header-anchor" href="#state-attributes-for-styling" aria-hidden="true">#</a> State attributes for styling</h2><p>The component provides <code>loaded</code> and <code>qualifies</code> attributes you can use in CSS:</p><pre class="language-css" tabindex="0"><code class="language-css"><span class="token comment">/* Hide images that loaded but no longer meet conditions <em>/</span><span class="token selector">lazy-img[loaded]:not([qualifies])</span><span class="token punctuation">{</span><span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">/</em> Show a placeholder for images that qualify but haven’t loaded */</span><span class="token selector">lazy-img[qualifies]:not([loaded])::before</span><span class="token punctuation">{</span><span class="token property">content</span><span class="token punctuation">:</span><span class="token string">“Loading…”</span><span class="token punctuation">;</span><span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span><span class="token property">padding</span><span class="token punctuation">:</span> 2em<span class="token punctuation">;</span><span class="token property">background</span><span class="token punctuation">:</span> #f0f0f0<span class="token punctuation">;</span><span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h2 id="events" tabindex="-1"><a class="header-anchor" href="#events" aria-hidden="true">#</a> Events</h2><p>If you crave control, you can add your own functionality by listening for when images load:</p><pre class="language-javascript" tabindex="0"><code class="language-javascript"><span class="token keyword">const</span> lazyImg <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">“lazy-img”</span><span class="token punctuation">)</span><span class="token punctuation">;</span>lazyImg<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">“lazy-img:loaded”</span><span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">“Image loaded:”</span><span class="token punctuation">,</span> event<span class="token punctuation">.</span>detail<span class="token punctuation">.</span>src<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h2 id="performance" tabindex="-1"><a class="header-anchor" href="#performance" aria-hidden="true">#</a> Performance</h2><p>The component is highly optimized:</p><ul><li><strong>Throttled resize</strong>: Resize events are throttled to prevent excessive checks</li><li><strong>Shared <code>ResizeObserver</code></strong>: Multiple images observing the same container share a single ResizeObserver</li><li><strong>Shared window resize listener</strong>: Media query mode shares a single window resize listener</li><li><strong>Shared <code>IntersectionObserver</code></strong>: View mode with the same <code>view-range-start</code> shares an <code>IntersectionObserver</code></li><li><strong>Clean disconnection</strong>: Properly cleans up observers when elements are removed</li></ul><p>Even with hundreds of <code>lazy-img</code> elements on a page, performance remains excellent.</p><h2 id="progressive-enhancement" tabindex="-1"><a class="header-anchor" href="#progressive-enhancement" aria-hidden="true">#</a> Progressive enhancement</h2><p>If JavaScript fails to load, images simply don’t appear (unless using immediate loading mode). This might sound problematic, but for non-critical images—decorative graphics, supplementary screenshots, marketing imagery—it’s often exactly what you want. Your content remains accessible; you just lose the enhancements.</p><p>For critical images that are part of your content, use standard <code>img</code> tags. Use <code>lazy-img</code> for conditional enhancements.</p><h2 id="demo" tabindex="-1"><a class="header-anchor" href="#demo" aria-hidden="true">#</a> Demo</h2><p>Explore <a href="https://aarongustafson.github.io/lazy-img/demo/">the demo</a> to see container queries, media queries, scroll-based loading, and more in action:</p><figure id="fig-2025-12-06-04" class="media-container"><fullscreen-control class="talk__slides__embed video-embed__video"><iframe src="https://aarongustafson.github.io/lazy-img/demo/" class="talk__slides__embed video-embed__video" frameborder="0"></iframe></fullscreen-control></figure><h2 id="grab-it" tabindex="-1"><a class="header-anchor" href="#grab-it" aria-hidden="true">#</a> Grab it</h2><p>Check out the project on <a href="https://github.com/aarongustafson/lazy-img">GitHub</a>. Install via npm:</p><pre class="language-bash" tabindex="0"><code class="language-bash"><span class="token function">npm</span><span class="token function">install</span> @aarongustafson/lazy-img</code></pre><p>Import and use:</p><pre class="language-javascript" tabindex="0"><code class="language-javascript"><span class="token keyword">import</span><span class="token string">“@aarongustafson/lazy-img”</span><span class="token punctuation">;</span></code></pre><p>Based on my original <a href="https://github.com/easy-designs/easy-lazy-images.js">Easy Lazy Images</a> concept, reimagined as a modern custom element.</p>]]></content><amg:twitter><![CDATA[Want to skip loading images entirely on mobile? Here’s a web component that does just that.]]></amg:twitter><amg:summary><![CDATA[<p>Native lazy loading and <code>srcset</code> are great, but they have a limitation: they always load <em>some</em> variant of the image. The <code>lazy-img</code> web component takes a different approach—it can completely skip loading images when they don’t meet your criteria, whether that’s screen size, container size, or visibility in the viewport.</p><p>This is particularly valuable for mobile users on slow connections or limited data plans. If an image is only meaningful on larger screens, why waste their bandwidth loading it at all?</p>]]></amg:summary><summary type="html"><![CDATA[<p>Native lazy loading and <code>srcset</code> are great, but they have a limitation: they always load <em>some</em> variant of the image. The <code>lazy-img</code> web component takes a different approach—it can completely skip loading images when they don’t meet your criteria, whether that’s screen size, container size, or visibility in the viewport.</p><p>This is particularly valuable for mobile users on slow connections or limited data plans. If an image is only meaningful on larger screens, why waste their bandwidth loading it at all?</p>]]></summary><category term="web components" /><category term="progressive enhancement" /><category term="HTML" /><category term="performance" /><category term="images" /><category term="responsive design" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/why-i-care-deeply-about-web-accessibility-and-you-should-too/</id><title type="html"><![CDATA[🔗 Why I Care Deeply About Web Accessibility And You Should Too]]></title><link href="https://www.aaron-gustafson.com/notebook/links/why-i-care-deeply-about-web-accessibility-and-you-should-too/" rel="alternate" type="text/html" /><link href="https://dev.to/schalkneethling/why-i-care-deeply-about-web-accessibility-and-you-should-too-274a" rel="related" type="text/html" /><published>2024-05-09T17:36:18Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>I agree with so much of this piece… especially <a href="https://www.aaron-gustafson.com/speaking-engagements/delivering-critical-information-services/">the expansive view of accessibility that is inclusive of both the disability divide and the digital divide</a>.</p><p>Great summary here:</p><blockquote><p>[M]y passion for accessibility stems from experiencing accessibility barriers personally, observing their impact on others, and holding the conviction that technology should tear down divides - not erect new ones. I want to fulfill, and help you fulfill, the web’s promise of equal access and opportunity for everyone, regardless of circumstances. Digital accessibility should not be an accommodation but a fundamental right and prerequisite for technology to truly better humanity.</p></blockquote>]]></content><amg:twitter><![CDATA[I agree with so much of this piece, especially the expansive view of accessibility that is inclusive of both the disability divide and the digital divide.]]></amg:twitter><category term="accessibility" /><category term="inclusive design" /><category term="performance" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/save-our-world/</id><title type="html"><![CDATA[🔗 Save Our World]]></title><link href="https://www.aaron-gustafson.com/notebook/links/save-our-world/" rel="alternate" type="text/html" /><link href="https://github.com/jenstrickland/CSUN2023/tree/main" rel="related" type="text/html" /><published>2023-04-05T22:03:37Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>I wish I could have been at CSUN to see Jen Strickland deliver this talk. It’s about the potential and actual harms inherent in web design and how to address them in our work.</p><p>Lots of juicy stats to share in your team discussions!</p>]]></content><amg:twitter><![CDATA[I wish I could have been at #CSUN to see @jenstrickland deliver this talk: “Save Our World.”
It’s about the potential and actual harms inherent in web design and how to address them in our work.]]></amg:twitter><category term="accessibility" /><category term="progressive enhancement" /><category term="performance" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://opengraph.githubassets.com/1859bbad57466a3830d682be630a63f22fa117502e1d3ef98561b36400c14615/jenstrickland/CSUN2023" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/building-a-resilient-frontend-using-progressive-enhancement/</id><title type="html"><![CDATA[🔗 Building a resilient frontend using progressive enhancement]]></title><link href="https://www.aaron-gustafson.com/notebook/links/building-a-resilient-frontend-using-progressive-enhancement/" rel="alternate" type="text/html" /><link href="https://www.gov.uk/service-manual/technology/using-progressive-enhancement" rel="related" type="text/html" /><published>2022-11-03T16:58:46Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>How did I miss this? The <a href="http://gov.uk">gov.uk</a> Service Manual recommends progressive enhancement for all their websites.</p><blockquote><p>Using progressive enhancement means your users will be able to do what they need to do if any part of the stack fails. Building your service using progressive enhancement will:</p><ul><li>make your service more resilient</li><li>mean your service’s most basic functionality will work and meet the core needs of the user</li><li>improve accessibility by encouraging best practices like writing semantic markup</li><li>help users with device or connectivity limitations to use your service</li></ul></blockquote><p>🥰</p>]]></content><amg:twitter><![CDATA[How did I miss that gov.uk was requiring progressive enhancement‽]]></amg:twitter><amg:summary><![CDATA[<p>How did I miss this? The <a href="http://gov.uk">gov.uk</a> Service Manual recommends progressive enhancement for all their websites.</p>]]></amg:summary><summary type="html"><![CDATA[<p>How did I miss this? The <a href="http://gov.uk">gov.uk</a> Service Manual recommends progressive enhancement for all their websites.</p>]]></summary><category term="accessibility" /><category term="performance" /><category term="progressive enhancement" /><category term="web design" /><category term="web development" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.gov.uk/assets/static/govuk-opengraph-image-dade2dad5775023b0568381c4c074b86318194edb36d3d68df721eea7deeac4b.png" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/real-world-performance-budgets-perfnow-2022/</id><title type="html"><![CDATA[🔗 Real-World Performance Budgets [PerfNow 2022]]]></title><link href="https://www.aaron-gustafson.com/notebook/links/real-world-performance-budgets-perfnow-2022/" rel="alternate" type="text/html" /><link href="https://www.slideshare.net/tammyeverts/realworld-performance-budgets-perfnow-2022" rel="related" type="text/html" /><published>2022-11-03T16:45:16Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>A clear and focused walkthrough of how to get started with performance budgets and then how to ramp up.</p>]]></content><amg:twitter><![CDATA[An awesome overview of the whys and hows of performance budgets, from @tameverts]]></amg:twitter><amg:summary><![CDATA[<p>A clear and focused walkthrough of how to get started with performance budgets and then how to ramp up.</p>]]></amg:summary><summary type="html"><![CDATA[<p>A clear and focused walkthrough of how to get started with performance budgets and then how to ramp up.</p>]]></summary><category term="performance" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://cdn.slidesharecdn.com/ss_thumbnails/2022-perfnow-performance-budgets-221027130426-9aa85c3a-thumbnail.jpg?width=640&amp;height=640&amp;fit=bounds" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/will-serving-real-html-content-make-a-website-faster-lets-experiment/</id><title type="html"><![CDATA[🔗 Will Serving Real HTML Content Make A Website Faster? Let's Experiment!]]></title><link href="https://www.aaron-gustafson.com/notebook/links/will-serving-real-html-content-make-a-website-faster-lets-experiment/" rel="alternate" type="text/html" /><link href="https://blog.webpagetest.org/posts/will-html-content-make-site-faster/" rel="related" type="text/html" /><published>2022-10-07T17:31:05Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>When you’ve worked on the web for as long as I have, you see trends come and go. I’ve witnessed at least three different eras where folks began to put all their eggs in the JavaScript basket, only to realize the massive hits they were taking to performance.</p><p>In this piece for WebPageTest, Scott Jehl uses a new “experiments” feature to demonstrate how serving HTML would make a ton of popular websites much, much faster. Some of these companies learned this lesson previously (and even <a href="https://medium.com/airbnb-engineering/isomorphic-javascript-the-future-of-web-apps-10882b7a2ebc">wrote about it</a>) only to have thrown their own advice out the window, which is disappointing.</p><p>Serving HTML will always result in faster page loads. There is no way around that. Sending your JavaScript framework to the client and having it render the HTML adds a ton of extra steps:</p><ol><li>Download skeleton markup</li><li>Download high priority JavaScript file(s) and CSS</li><li>Load JavaScript program into memory</li><li>Execute JavaScript</li><li>Generate actual markup (and replace skeleton)</li><li>Request assets referenced in markup (e.g., images, videos)</li><li><strong>Render page</strong></li><li>Load deferred assets</li></ol><p>Compare that to the HTML-first route:</p><ol><li>Download markup</li><li>Download high priority JavaScript file(s) and CSS</li><li>Request assets referenced in markup (e.g., images, videos)</li><li><strong>Render page</strong></li><li>Load deferred assets</li></ol><p>Sure, on subsequent navigations having JavaScript request only the bits and pieces you need is a performance win, but that first render is a beast. And you can totally load that JavaScript later, after the page is rendered.</p>]]></content><amg:twitter><![CDATA[Loving @scottjehl’s in-depth performance comparison between serving HTML and JavaScript that builds HTML. No surprise: HTML wins every time.]]></amg:twitter><category term="JavaScript" /><category term="performance" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.webpagetest.org/cloudinary/webpagetest/image/upload/f_auto,q_auto,c_fill,g_xy_center,h_630,w_1200,x_0/Mimic_Post_Cover_sedsq6.png" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/making-the-world-s-fastest-website-and-other-mistakes-series-/</id><title type="html"><![CDATA[🔗 Making the world’s fastest website, and other mistakes (Series)]]></title><link href="https://www.aaron-gustafson.com/notebook/links/making-the-world-s-fastest-website-and-other-mistakes-series-/" rel="alternate" type="text/html" /><link href="https://dev.to/tigt/making-the-worlds-fastest-website-and-other-mistakes-56na" rel="related" type="text/html" /><published>2022-04-28T16:37:38Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>This 4 part series walks through the various levels of Hell you must traverse to actually achieve solid web performance on a large e-commerce platform. What is most amazing to me is how things continue to align pretty directly with the philosophy of progressive enhancement.</p>]]></content><amg:twitter><![CDATA[This series on web performance from @tigt_ is really dense but full of so many excellent real-world learnings.]]></amg:twitter><category term="performance" /><category term="web development" /><category term="progressive enhancement" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://res.cloudinary.com/practicaldev/image/fetch/s--SeomjpZ---/c_imagga_scale,f_auto,fl_progressive,h_500,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rix9oblwajfxxrtwc9xk.jpg" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/benchmarking-javascript-memory-usage/</id><title type="html"><![CDATA[🔗 Benchmarking JavaScript Memory Usage]]></title><link href="https://www.aaron-gustafson.com/notebook/links/benchmarking-javascript-memory-usage/" rel="alternate" type="text/html" /><link href="https://blog.webpagetest.org/posts/benchmarking-javascript-memory-usage/" rel="related" type="text/html" /><published>2021-07-23T21:41:30Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>Testing JavaScript memory usage is not done often enough, but it’s incredibly important. This is an awesome guide from Tim Kadlec.</p>]]></content><amg:twitter><![CDATA[Testing JavaScript memory usage is not done often enough, but it’s incredibly important. This is an awesome guide from @tkadlec.]]></amg:twitter><category term="JavaScript" /><category term="performance" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.webpagetest.org/cloudinary/webpagetest/image/upload/f_auto,q_auto,c_limit,w_1200,h_630/MemoryBlogImage_uflo0b.psd" /></entry><entry><id>https://www.aaron-gustafson.com/speaking-engagements/delivering-critical-information-services/</id><title type="html"><![CDATA[📢 Delivering Critical Information &amp; Services]]></title><link href="" rel="alternate" type="text/html" /><published>2020-08-17T05:09:00Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>Early on, Internet access was considered a luxury. Those times have passed and the Internet, especially the Web, has become a necessity. Whether your users are trying to access their money, gather health information, attend class, apply for assistance, or any of the other hundreds (if not thousands) of critical tasks people do on the web, your site needs to be prepared to meet their needs. And it needs to work, no matter what.</p><p>In this session, Aaron discusses the many challenges to delivering critical information and services as well as the steps you can take to overcome those challenges. He’ll explore ways to make sure you can meet users on a variety of devices—and not the just the latest and greatest high end ones folks are talking about; how to make it accessible to people with disabilities; and how to load—and load quickly—on limited-bandwidth connections.</p>]]></content><amg:twitter><![CDATA[In this session, Aaron discusses the many challenges to delivering critical information and services as well as the steps you can take to overcome those challenges.]]></amg:twitter><amg:summary><![CDATA[<p>In this session, Aaron discusses the many challenges to delivering critical information and services as well as the steps you can take to overcome those challenges.</p>]]></amg:summary><summary type="html"><![CDATA[<p>In this session, Aaron discusses the many challenges to delivering critical information and services as well as the steps you can take to overcome those challenges.</p>]]></summary><category term="accessibility" /><category term="inclusive design" /><category term="performance" /><category term="web design" /><category term="web development" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.aaron-gustafson.com/undefined" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/2020-04-21-the-cost-of-javascript-frameworks/</id><title type="html"><![CDATA[🔗 The Cost of Javascript Frameworks]]></title><link href="https://www.aaron-gustafson.com/notebook/links/2020-04-21-the-cost-of-javascript-frameworks/" rel="alternate" type="text/html" /><link href="https://timkadlec.com/remembers/2020-04-21-the-cost-of-javascript-frameworks/" rel="related" type="text/html" /><published>2020-04-27T19:39:10Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>Excellent analysis by Tim here:</p><blockquote><p>Good frameworks should provide a better starting point on the essentials (security, accessibility, performance) or have built-in constraints that make it harder to ship something that violates those.</p><p>That doesn’t appear to be happening with performance (nor with accessibility, apparently).</p><p>…</p><p>What is clear: right now, if you’re using a framework to build your site, you’re making a trade-off in terms of initial performance—even in the best of scenarios.</p><p>Some trade-off may be acceptable in the right situations, but it’s important that we make that exchange consciously.</p></blockquote><p>Do yourself a favor and tuck into the numbers here. He presents a substantial amount of very useful information.</p>]]></content><amg:twitter><![CDATA[The Cost of Javascript Frameworks]]></amg:twitter><category term="performance" /><category term="JavaScript" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://timkadlec.com/images/cost-of-frameworks-bytes-mobile-sm.png" /></entry><entry><id>https://www.aaron-gustafson.com/publications/articles/request-with-intent-caching-strategies-in-the-age-of-pwas/</id><title type="html"><![CDATA[📄 Request with Intent: Caching Strategies in the Age of PWAs]]></title><link href="https://alistapart.com/article/request-with-intent-caching-strategies-in-the-age-of-pwas/" rel="alternate" type="text/html" /><published>2019-11-21T00:00:00Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>Caching media files, especially images, seems like an obvious way to improve performance, but should we? To provide a more performant UX without abusing users’ network connections or hard drives, I put a spin on classic best practices, experiment with media caching strategies, and share smart Cache API tricks.</p>]]></content><category term="progressive web apps" /><category term="responsive web design" /><category term="performance" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/5g-will-definitely-make-the-web-slower-maybe/</id><title type="html"><![CDATA[🔗 5G Will Definitely Make the Web Slower, Maybe]]></title><link href="https://www.aaron-gustafson.com/notebook/links/5g-will-definitely-make-the-web-slower-maybe/" rel="alternate" type="text/html" /><link href="https://www.filamentgroup.com/lab/5g/" rel="related" type="text/html" /><published>2019-09-25T21:56:56Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>The bigger the pipe, the more we’ll shove into it. This is an important piece from Scott Jehl. You should give it a read.</p><blockquote><p>This problem is on us. Yes, we need to better prioritize our asset delivery, but most importantly, we need to stop delivering so much JavaScript. We need to audit our script inventory, and scrutinize our 3rd party integrations regularly, as many of these packages are abandoned or meant to be short-lived. … We should do whatever we can to keep our team members aware of their own impact, across all roles.</p></blockquote>]]></content><amg:twitter><![CDATA[The bigger the pipe, the more we’ll shove into it.]]></amg:twitter><category term="performance" /><category term="JavaScript" /><category term="web development" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.filamentgroup.com/images/icons/twittercard.png" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/the-weight-of-the-wwworld-is-up-to-us-by-patty-toland/</id><title type="html"><![CDATA[🔗 The Weight of the WWWorld is Up to Us by Patty Toland]]></title><link href="https://www.aaron-gustafson.com/notebook/links/the-weight-of-the-wwworld-is-up-to-us-by-patty-toland/" rel="alternate" type="text/html" /><link href="https://adactio.com/journal/15740" rel="related" type="text/html" /><published>2019-08-29T23:29:54Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>So much awesome content in Patty’s talk. In particular…</p><blockquote><p>There was a common assertion that slow networks were a third-world challenge. Remember Facebook’s network challenges? They always talked about new markets in India and Africa. The implication is that this isn’t our problem in, say, Omaha or New York.</p><p>Pew Research provided a lot of data back then that showed that this thinking was wrong. Use of cell phones, especially smartphones and tablets, escalated dramatically in the United States. There was a trend towards mobile-only usage. This was in low-income households—about one third of the population. Among 5,400 panelists, 15% did not have a JavaScript-enabled device.</p></blockquote>]]></content><amg:twitter><![CDATA[The brilliant @pattytoland’s “The Weight of the WWWorld is Up to Us” talk as captured by @adactio’s furiously-typing fingers. #AEACHI]]></amg:twitter><category term="performance" /><category term="progressive enhancement" /><category term="web development" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://adactio.com/images/photo-300.jpg" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/-how-web-content-can-affect-power-usage/</id><title type="html"><![CDATA[🔗   How Web Content Can Affect Power Usage]]></title><link href="https://www.aaron-gustafson.com/notebook/links/-how-web-content-can-affect-power-usage/" rel="alternate" type="text/html" /><link href="https://webkit.org/blog/8970/how-web-content-can-affect-power-usage/" rel="related" type="text/html" /><published>2019-08-29T22:29:17Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>This is a great overview of the many ways in which our designs (and code) affect power usage and battery life.</p>]]></content><category term="performance" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://webkit.org/wp-content/uploads/Web-Inspector-CPU-Timeline-Overview-Light.png" /></entry><entry><id>https://www.aaron-gustafson.com/speaking-engagements/media-in-the-age-of-pwas/</id><title type="html"><![CDATA[📢 Media in the Age of PWAs]]></title><link href="" rel="alternate" type="text/html" /><published>2019-05-01T00:09:00Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>Our industry is abuzz with talk about Progressive Web Apps (PWAs) and with good reason: they are a great way to improve the experiences our users have on our sites, especially when it comes to performance. Using Service Workers—a key component of PWAs—we can manage network requests and the cache to an incredibly granular degree. We can also totally abuse the privilege Service Workers grant us when it comes to writing files to disk.</p><p>In this session, I discuss some of the potential pitfalls in implementing Service Workers, especially when it comes to managing heavy files like images and video. He’ll provide guidance on current best practices in cache management. And he’ll offer a few simple recipes you can put to use right away to deliver amazing experiences for your users that respect their data usage and disk space.</p>]]></content><amg:twitter><![CDATA[In this session I discuss some of the potential pitfalls in implementing Service Workers, especially when it comes to managing heavy files like images and video.]]></amg:twitter><amg:summary><![CDATA[<p>In this session I discuss some of the potential pitfalls in implementing Service Workers, especially when it comes to managing heavy files like images and video.</p>]]></amg:summary><summary type="html"><![CDATA[<p>In this session I discuss some of the potential pitfalls in implementing Service Workers, especially when it comes to managing heavy files like images and video.</p>]]></summary><category term="performance" /><category term="progressive web apps" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.aaron-gustafson.com/undefined" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/native-image-lazy-loading-for-the-web-/</id><title type="html"><![CDATA[🔗 Native image lazy-loading for the web!]]></title><link href="https://www.aaron-gustafson.com/notebook/links/native-image-lazy-loading-for-the-web-/" rel="alternate" type="text/html" /><link href="https://addyosmani.com/blog/lazy-loading/" rel="related" type="text/html" /><published>2019-04-08T18:30:23Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>I’m incredibly excited that this feature is shipping in Chromium. It was one of my favorite IE features.</p><p><em>Note: I no longer use “native” in this context, but it remains in quoted material.</em></p>]]></content><category term="HTML" /><category term="performance" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://addyosmani.com/assets/images/loading-attribute.png" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/hard-costs-of-third-party-scripts/</id><title type="html"><![CDATA[🔗 Hard Costs of Third-Party Scripts]]></title><link href="https://www.aaron-gustafson.com/notebook/links/hard-costs-of-third-party-scripts/" rel="alternate" type="text/html" /><link href="https://daverupert.com/2018/10/hard-costs-of-third-party-scripts/" rel="related" type="text/html" /><published>2018-10-29T23:31:47Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>Dave has an excellent round-up of considerations when looking at your reliance on 3rd party scripts (or any 3rd party resources, for that matter). Most are hidden and all have a serious effect on download performance, UI responsiveness, and, ultimately, user experience.</p><blockquote><p>The Web is an undependable place, so this shouldn’t be very surprising.</p></blockquote>]]></content><amg:twitter><![CDATA[All 3rd party resources have hidden costs that cause serious problems for users in terms of download performance, UI responsiveness, and, ultimately, user experience]]></amg:twitter><category term="performance" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://daverupert.com/images/global/newshammericon.png" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/performance-budgets/</id><title type="html"><![CDATA[🔗 Start Performance Budgeting]]></title><link href="https://www.aaron-gustafson.com/notebook/links/performance-budgets/" rel="alternate" type="text/html" /><link href="https://addyosmani.com/blog/performance-budgets/" rel="related" type="text/html" /><published>2018-10-19T22:16:29Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>More thoughtful (and actionable) advice about performance budgets. Would that more companies would do this!</p>]]></content><category term="performance" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://addyosmani.com/assets/images/perf-budget-metrics.png" /></entry><entry><id>https://www.aaron-gustafson.com/speaking-engagements/better-performance-greater-accessibility/</id><title type="html"><![CDATA[📢 Better Performance == Greater Accessibility]]></title><link href="" rel="alternate" type="text/html" /><published>2018-10-11T00:09:00Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>Design is problem solving. Each and every day, we are tasked with finding ways to reduce the friction our users experience on the Web. That means streamlining flows, reducing cognitive load, writing more appropriate copy, and (of course) building accessible experience. But experience is about more than just interface. Our users’ experiences begin with their first request to our servers.</p><p>In this intensely practical session, Aaron will explore the ins and outs of page load performance by showing how he made the web site of the 10K Apart meet its own contest rules, by having a site that was functional and attractive even without JavaScript, and was less than ten kilobytes at initial load. You’ll walk away with a better understanding of the page load process as well as numerous ways you can improve the projects you are working on right now.</p>]]></content><amg:twitter><![CDATA[In this intensely practical session, Aaron will explore the ins and outs of page load performance by showing how he made the web site of the 10K Apart meet its own contest rules, by having a site that was functional and attractive even without JavaScript, and was less than ten kilobytes at initial load.]]></amg:twitter><amg:summary><![CDATA[<p>In this intensely practical session, Aaron will explore the ins and outs of page load performance by showing how he made the web site of the 10K Apart meet its own contest rules, by having a site that was functional and attractive even without JavaScript, and was less than ten kilobytes at initial load.</p>]]></amg:summary><summary type="html"><![CDATA[<p>In this intensely practical session, Aaron will explore the ins and outs of page load performance by showing how he made the web site of the 10K Apart meet its own contest rules, by having a site that was functional and attractive even without JavaScript, and was less than ten kilobytes at initial load.</p>]]></summary><category term="performance" /><category term="accessibility" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.aaron-gustafson.com/undefined" /></entry><entry><id>https://www.aaron-gustafson.com/notebook/links/how-to-build-a-lowtech-website/</id><title type="html"><![CDATA[🔗 How to Build a Low-tech Website?]]></title><link href="https://www.aaron-gustafson.com/notebook/links/how-to-build-a-lowtech-website/" rel="alternate" type="text/html" /><link href="https://solar.lowtechmagazine.com/2018/09/how-to-build-a-lowtech-website/" rel="related" type="text/html" /><published>2018-10-03T22:38:05Z</published><content type="html" xml:base="https://www.aaron-gustafson.com"><![CDATA[<p>I <em>love</em> this project. It ticks so many boxes for me as it’s all about doing more with less. I love the ways they’ve found to reduce consumption on the server side and throughput to their users as well. So much to unpack!</p>]]></content><amg:twitter><![CDATA[Building a Low Tech Website… I *love* this project. It ticks so many boxes for me as it’s all about doing more with less.]]></amg:twitter><category term="web design" /><category term="web development" /><category term="performance" /><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://solar.lowtechmagazine.com/dithers/sps_close.png" /></entry></feed>