<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jim Thoburn</title>
    <description>The latest articles on DEV Community by Jim Thoburn (@jimthoburn).</description>
    <link>https://dev.to/jimthoburn</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F282560%2F705ed80e-52ce-4580-8381-ef307c2a0022.png</url>
      <title>DEV Community: Jim Thoburn</title>
      <link>https://dev.to/jimthoburn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jimthoburn"/>
    <language>en</language>
    <item>
      <title>Serving a high quality user experience, without being a server-side expert</title>
      <dc:creator>Jim Thoburn</dc:creator>
      <pubDate>Tue, 14 Jan 2020 22:45:43 +0000</pubDate>
      <link>https://dev.to/jimthoburn/serving-a-high-quality-user-experience-without-being-a-server-side-expert-4gif</link>
      <guid>https://dev.to/jimthoburn/serving-a-high-quality-user-experience-without-being-a-server-side-expert-4gif</guid>
      <description>&lt;p&gt;Recently an organization asked if I would help them create a web application for a voting contest. The contest would involve a showcase of organizations working to improve Los Angeles that can be voted for by anyone who lives in the city. The winners would collectively receive one million dollars in support. They wanted to host everything on the web and were expecting tens of thousands of voters to visit the web site.&lt;/p&gt;

&lt;p&gt;It felt like a huge undertaking with a lot at stake–and that deserved a team of expert designers and engineers. A part of me wanted to tell them, “I’m not qualified to do all of this for you”, but I really wanted to work on the project–so the words that actually came out were, “Yes, of course!”&lt;/p&gt;

&lt;p&gt;I had been part of teams working on projects like this one in the past, filling the role of user experience engineer. I knew that I could write high quality HTML, CSS and JavaScript to make a user interface for them. And I had been in the room with experienced server side engineers who were setting up things like servers and databases. Thinking about the qualities of a web application that I had observed those engineers putting effort into, I felt that I should focus on &lt;em&gt;security&lt;/em&gt;, &lt;em&gt;scalability&lt;/em&gt; and &lt;em&gt;robustness&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I had recently learned about using GitHub pages and Jekyll to make a static web site or application that, by its very nature, would have these attributes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: A folder of static HTML files served directly on the web is going to be almost unhackable. And the source code will be safely stored in a version control system, behind GitHub’s two-factor authentication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: HTML files on a CDN are going to be lighting fast for lots of simultaneous visitors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robustness&lt;/strong&gt;: HTML files don’t have moving parts and browsers are super-forgiving when it comes to interpreting HTML, so there’s almost nothing that can break and make the site unavailable.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I had also learned that it’s possible to extend a static web site with third-party services, to add features that may be missing–such as having the ability to accept and save data from visitors–for things like comments on a post and in my case, voting forms.&lt;/p&gt;

&lt;p&gt;The basic pieces that I felt the voting application needed were:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Form that users can use to vote for their favorite organizations&lt;/li&gt;
&lt;li&gt;The ability to save voting forms in a database, so they can be retrieved and counted&lt;/li&gt;
&lt;li&gt;A way to for users to authenticate themselves, to keep the voting fair&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The static user interface would be core of the application, showcasing the organizations and providing a voting form.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.netlify.com/products/forms/" rel="noopener noreferrer"&gt;Netlify’s forms&lt;/a&gt; feature provided a way to save the voting data. It worked really well and was super easy to set up!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"vote"&lt;/span&gt; &lt;span class="na"&gt;data-netlify=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;…&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://auth0.com/passwordless" rel="noopener noreferrer"&gt;Auth0’s passwordless sign in&lt;/a&gt; service provided a way to authenticate the voters. They have an API that can be accessed with JavaScript, so it worked great with a static site.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;webAuth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;auth0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WebAuth&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="err"&gt;…&lt;/span&gt;
  &lt;span class="na"&gt;redirectUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/vote/authenticated/`&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;form[name="vote"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;webAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;passwordlessStart&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Auth0 provides easy integration with other services like Twilio and SendGrid for sending text messages and emails that visitors can use to &lt;a href="https://auth0.com/passwordless" rel="noopener noreferrer"&gt;authenticate themselves, without needing to create a password&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://beta-challenge.la2050.org/vote/form/" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftobbi.co%2Fimages%2Fla2050%2F2048-wide%2F6.png" alt="Voting form"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cloudflare.com/" rel="noopener noreferrer"&gt;Cloudflare&lt;/a&gt; provided a CDN to keep the web site fast for everyone and essentially reduced bandwidth costs for the project to just $20 per month. Their service was also useful for, things like true 301 and 302 redirects, which aren’t generally available for a static web site. And their service provides free HTTPS, which keeps the web site secure and private for visitors. Cloudflare also provides protection from DoS and bad robots with things like &lt;a href="https://www.cloudflare.com/learning/bots/how-captchas-work/" rel="noopener noreferrer"&gt;automatic CAPTCHAs&lt;/a&gt;. This turned out to be useful in terms of keeping the voting fair and protected from automatic form submissions.&lt;/p&gt;

&lt;p&gt;The combination of GitHub and Netlify also made it possible to set up multiple staging web sites for each phase of the project, automatically deployed from a few core Git branches.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build command
    jekyll build --config _config.yml,_config/staging.yml
Publish directory
    _site/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Flfrsnbf7rcvcpggjzwie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Flfrsnbf7rcvcpggjzwie.png" alt="Deploy settings on Netlify"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Discovering these services and putting them to use for each aspect of the project felt really empowering. And it left me feeling like it’s never been a better time to be designing and building on the web, with so many high quality tools and materials to work with. If there’s anything that you take away from this article, I hope that it will be–when you’re faced with a seemingly impossible project, you’ll tell yourself “I can do it!” 🙂&lt;/p&gt;

&lt;p&gt;You can learn more about using static site generators to make scalable web products, from &lt;a href="https://thewebahead.net/54" rel="noopener noreferrer"&gt;episode 54 of the “The Web Ahead” podcast&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’d like to see more example code, here’s the &lt;a href="https://github.com/la2050/challenge" rel="noopener noreferrer"&gt;LA2050 project on GitHub&lt;/a&gt;, and a &lt;a href="https://tobbi.co/la2050/" rel="noopener noreferrer"&gt;case study&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>jamstack</category>
      <category>ux</category>
    </item>
    <item>
      <title>Improving UX for images while they’re loading on the web</title>
      <dc:creator>Jim Thoburn</dc:creator>
      <pubDate>Fri, 06 Dec 2019 23:44:17 +0000</pubDate>
      <link>https://dev.to/jimthoburn/how-to-improve-ux-for-images-while-they-re-loading-on-the-web-3b12</link>
      <guid>https://dev.to/jimthoburn/how-to-improve-ux-for-images-while-they-re-loading-on-the-web-3b12</guid>
      <description>&lt;p&gt;This post is about a few different ways that you can improve the experience someone has while they’re waiting for the images to load on your web site or application.&lt;/p&gt;

&lt;p&gt;You can see a demo of these techniques by switching on &lt;a href="https://developer.mozilla.org/en-US/docs/Tools/Network_Monitor/Throttling"&gt;network throttling&lt;/a&gt; in the developer tools for Firefox or Chrome, and then visiting this wildflower picture gallery:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pictures.tobbi.co/wildflowers/"&gt;Wildflowers of Joshua Tree (demo)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pictures.tobbi.co/wildflowers/51-mastodon-peak/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S6h4LjTH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tobbi.co/images/writing/2019-12-06-improving-ux-for-images-while-loading-on-the-web/2048-wide/network-throttle.png" alt="Network throttling in the developer tools for Firefox" width="880" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are five ideas suggested here, but don’t feel like you have to use all of them! Some will be way more useful in certain contexts (especially &lt;em&gt;lazy loading&lt;/em&gt;), and implementing even just one can make a big difference. In general, these techniques are useful for large images, long lists of images, and images that affect the layout of a web page.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Loading images lazily&lt;/li&gt;
&lt;li&gt;Giving images an intrinsic size&lt;/li&gt;
&lt;li&gt;Making a variety of image sizes available for differently sized screens&lt;/li&gt;
&lt;li&gt;Showing a preview of each image&lt;/li&gt;
&lt;li&gt;Making image descriptions available&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id="lazy-loading"&gt;Loading images lazily&lt;/h2&gt;

&lt;p&gt;This technique involves only loading images if they’re within the viewport or likely to be within the viewport the next time the user scrolls up or down. It’s super useful when applied to a list of images, where only a few are visible at a time.&lt;/p&gt;

&lt;p&gt;This should make the first few images a user is looking at load more quickly–particularly on a slow connection. It may also save bandwidth and some dollars for users of your web product.&lt;/p&gt;

&lt;p&gt;You can easily begin using the lazy loading technique, now that it’s built into the web platform:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://css-tricks.com/native-lazy-loading/"&gt;Native Lazy Loading on CSS Tricks&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if it’s not yet implemented in a browser that you feel is important to your audience, you can manually apply the technique by following a guide like this one, from Google:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video/"&gt;Lazy Loading Images and Video, Web Fundamentals by Google&lt;/a&gt;&lt;/p&gt;

&lt;h2 id="intrinsic-sizing"&gt;Giving images an &lt;a href="https://twitter.com/jensimmons/status/980980521848127488"&gt;intrinsic&lt;/a&gt; size&lt;/h2&gt;

&lt;p&gt;This will help browsers to lay out the page completely while the images are still loading, since it will know how wide and tall each image should be. Basically all you have to do is add a &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attribute to each image and the browser will take care of the rest. You can learn more about it with this guide from Mozilla:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Media/images/aspect_ratio_mapping"&gt;Media container elements and aspect-ratio, by Mozilla&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"1500"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"1000"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c"&gt;/* Browsers like Firefox now have a default rule like this one
    (so you don’t have to write this line, but it looks neat!) */&lt;/span&gt;
  &lt;span class="py"&gt;aspect-ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have a lot of images, you can use a tool like &lt;a href="https://www.npmjs.com/package/exif"&gt;node-exif&lt;/a&gt; to automatically make the image sizes available to you as data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"exif"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ExifImageWidth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ExifImageHeight"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2 id="responsive-images"&gt;Making a variety of image sizes available for differently sized screens&lt;/h2&gt;

&lt;p&gt;Similar to lazy loading, this will make images load noticeably faster on slow connections and saves bandwidth for users and servers–and potentially some dollars for your audience and yourself.&lt;/p&gt;

&lt;p&gt;You can get started by adding a &lt;code&gt;srcset&lt;/code&gt; attribute to your image element and giving it a few image sizes at different widths. If you want to go further, adding a &lt;code&gt;sizes&lt;/code&gt; attribute can make a big difference in download size too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"
    /images/500-wide/wildflowers.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"
    /images/500-wide/wildflowers.jpg 500w,
    /images/1000-wide/wildflowers.jpg 1000w,
    /images/1500-wide/wildflowers.jpg 1500w"&lt;/span&gt;
  &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"
    (min-width: 35em) 50vw,
    100vw"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;srcset&lt;/code&gt; attribute above is basically saying to the browser, “Hey! I have three different images for you to choose from, ranging from 500 pixels wide to 1,500 pixels wide. Please choose whichever one is best for your viewport size and device pixel ratio.”&lt;/p&gt;

&lt;p&gt;And the &lt;code&gt;sizes&lt;/code&gt; attribute is saying, “I’ve included a CSS layout for this page that makes images either 50 or 100 percent of the viewport width, depending on how wide the viewport is. Please consider this information too when you choose one of the &lt;code&gt;srcset&lt;/code&gt; images. I’m telling you this information now–since you’re awesome and you have a &lt;a href="https://cloudfour.com/thinks/the-real-conflict-behind-picture-and-srcset/"&gt;lookahead preparser&lt;/a&gt; that needs this information to be stored somewhere in the HTML.”&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;35em&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50vw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be sure to keep the &lt;code&gt;src&lt;/code&gt; attribute that you already have on the &lt;code&gt;img&lt;/code&gt; element. This will provide a default image for browsers that don’t understand the &lt;code&gt;srcset&lt;/code&gt; syntax. Any size image will be a good choice–even a big one. (Modern browsers will skip the &lt;code&gt;src&lt;/code&gt;image and download a potentially smaller image from the &lt;code&gt;srcset&lt;/code&gt; instead.)&lt;/p&gt;

&lt;p&gt;If you have a lot of images, you can use a tool like &lt;a href="https://github.com/topics/graphicsmagick"&gt;GraphicsMagick&lt;/a&gt; to automatically generate differently sized images. Or you can use a service like &lt;a href="https://www.netlify.com/products/large-media/"&gt;Netlify Large Media&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can learn more in the &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images"&gt;Responsive Images&lt;/a&gt; guide from Mozilla or by listening to this &lt;a href="https://thewebahead.net/99"&gt;Implementing Responsive Images&lt;/a&gt; podcast with Jen Simmons and Jason Grigsby.&lt;/p&gt;

&lt;h2 id="image-preview"&gt;Showing a preview of each image&lt;/h2&gt;

&lt;p&gt;This practice is about making images &lt;em&gt;appear&lt;/em&gt; to load faster, by showing a colorful preview of each image while it’s loading.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://css-tricks.com/the-blur-up-technique-for-loading-background-images/"&gt;The “Blur Up” Technique for Loading Background Images on CSS Tricks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re already creating differently sized images for use in the &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images"&gt;responsive images&lt;/a&gt; technique, you can easily generate one more tiny sized image for use as a preview. I found that a 16 pixel wide image works well–especially after it’s optimized with a tool like &lt;a href="https://imageoptim.com"&gt;ImageOptim&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have your tiny images, you can embed them directly in the HTML for your page using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs"&gt;data URLs&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"preview"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;" data:image/jpeg;base64,/9j…EKyONpWJGxwSAuDj5qPEXQxv/9k="&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/wildflowers.jpg"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;img&lt;/span&gt;&lt;span class="nc"&gt;.preview&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WrXUiYGK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tobbi.co/images/writing/2019-12-06-improving-ux-for-images-while-loading-on-the-web/2048-wide/image-preview.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WrXUiYGK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tobbi.co/images/writing/2019-12-06-improving-ux-for-images-while-loading-on-the-web/2048-wide/image-preview.png" alt="A blurry preview image with a variety of colors" width="880" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l2jzcO1Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tobbi.co/images/writing/2019-12-06-improving-ux-for-images-while-loading-on-the-web/2048-wide/image-loaded.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l2jzcO1Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tobbi.co/images/writing/2019-12-06-improving-ux-for-images-while-loading-on-the-web/2048-wide/image-loaded.png" alt="The original image" width="880" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id="image-description"&gt;Making image descriptions available&lt;/h2&gt;

&lt;p&gt;Most browsers display the description stored in the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Img"&gt;&lt;em&gt;alt&lt;/em&gt; attribute&lt;/a&gt; while the image is loading.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"A lush group of plants with purple flowers, growing in the sunshine"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O5Jmtu9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tobbi.co/images/writing/2019-12-06-improving-ux-for-images-while-loading-on-the-web/2048-wide/description.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O5Jmtu9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://tobbi.co/images/writing/2019-12-06-improving-ux-for-images-while-loading-on-the-web/2048-wide/description.png" alt="Alternate text displayed on top of an image, loading on a web page" width="880" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Descriptions are also super important and helpful for people who experience your web product using tools like &lt;a href="http://www.apple.com/accessibility/voiceover/"&gt;Voice Over&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have a lot of images, you may be able to get a head start writing descriptions by using something like &lt;a href="https://stackoverflow.com/questions/44929055/generate-meaningful-image-description-based-on-image-labels"&gt;machine learning&lt;/a&gt;. (I haven’t done this before myself, but would really like to try it!)&lt;/p&gt;

&lt;h2&gt;
  
  
  An example project
&lt;/h2&gt;

&lt;p&gt;Here’s a project on GitHub that makes use of each of these techniques, that you can use a reference or starting point:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jimthoburn/picture-gallery"&gt;Picture Gallery 🖼 ✨ on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project also contains example code for automatically &lt;a href="https://github.com/jimthoburn/picture-gallery/blob/master/create/images.js"&gt;generating images&lt;/a&gt; and &lt;a href="https://github.com/jimthoburn/picture-gallery/blob/master/create/albums.js"&gt;&lt;em&gt;width&lt;/em&gt; and &lt;em&gt;height&lt;/em&gt;&lt;/a&gt; data.&lt;/p&gt;

&lt;h2&gt;
  
  
  More tips
&lt;/h2&gt;

&lt;p&gt;There are, no doubt, many more ways to improve the user experience while loading images on the web. If you have a tip I didn’t mention or an easier way of accomplishing any of the ideas above, please &lt;a href="https://dev.to/jimthoburn/how-to-improve-ux-for-images-while-they-re-loading-on-the-web-3b12#comments"&gt;feel free to comment&lt;/a&gt;. 🙂&lt;/p&gt;

</description>
      <category>ux</category>
      <category>html</category>
      <category>css</category>
    </item>
  </channel>
</rss>
