<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ image optimization  - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ image optimization  - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 16:31:06 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/image-optimization/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ What is AVIF? How to Use AV1 Image Format Images on Your Website ]]>
                </title>
                <description>
                    <![CDATA[ By Erisan Olasheni The AV1 Image format, or AVIF, is the latest image codec on earth. AVIF is an optimized image format which was created to make our images smaller while keeping the same quality (lossless). The file extension for AVIF is .avif. In t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-avif-images-on-your-website/</link>
                <guid isPermaLink="false">66d45e3cb6b7f664236cbdba</guid>
                
                    <category>
                        <![CDATA[ image optimization  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 20 Nov 2020 18:14:06 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/11/how-to-start-using-images-on-your-webistes-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Erisan Olasheni</p>
<p>The AV1 Image format, or AVIF, is the latest image codec on earth. AVIF is an optimized image format which was created to make our images smaller while keeping the same quality (lossless). The file extension for AVIF is <code>.avif</code>.</p>
<p>In this article, I want to talk about its features and benefits, and why you should start using AVIF. I will also show you the safe way to include AVIF images on your website. </p>
<h2 id="heading-what-is-avif-and-how-does-it-work">What is AVIF and How Does it Work?</h2>
<p>AVIF is an extraction from the keyframes of the now popular video format <a target="_blank" href="https://en.wikipedia.org/wiki/AV1">AV1</a> developed by <a target="_blank" href="http://aomedia.org/">Alliance for Open Media (AOM)</a>. </p>
<p>AOM developed AVIF with the goal of providing royalty-free images with better compression efficiency and more feature support compared to the existing image formats. </p>
<p>AVIF now has backers from big companies like Google, Netflix, and Apple. </p>
<h2 id="heading-why-is-avif-better">Why is AVIF Better?</h2>
<p>Following its predecessors (<strong>WebP</strong>, <strong>JPEG-XR</strong>, <strong>JPEG2000</strong>, and <strong>PNG</strong>, <strong>GIF</strong>) AVIF is compatible with high-dynamic-range imaging. It supports <strong>10-</strong> and <strong>12-bit</strong> color at full resolution, resulting in images that are up to 10 times smaller than other known formats. </p>
<p>AVIF is a good choice for web developers because:</p>
<ul>
<li>It is royalty-free, so you can use it for free without worrying about licensing.</li>
<li>It is currently backed by many big players in tech like Google, Amazon, Netflix, Microsoft, and more.</li>
<li>It has the most optimal compression.</li>
<li>It has more modern features packed in like transparency, HDR, wide colour gamut, and more.</li>
</ul>
<h2 id="heading-how-to-start-using-avif-images">How to Start Using AVIF Images</h2>
<p>Now we get to the fun section of this tutorial. There are two major ways you can start using AVIF images:</p>
<ol>
<li>One is by converting your old images to AVIF.</li>
<li>The other is by creating AVIF images using AVIF-supported image editors.</li>
</ol>
<h3 id="heading-how-to-convert-your-old-images-to-avif">How to convert your old images to AVIF</h3>
<p>Because AVIF is still in its infancy, the easiest way to create images in AVIF format is to convert your old formats. </p>
<p>This can be done simply online, as there are many online AVIF image converters. The <a target="_blank" href="https://avif-converter.online/">AVIF online converter</a> is my choice because it is simpler and seems the to be the fastest available online converter. </p>
<p>Just follow these steps to convert your images to AVIF:</p>
<ol>
<li>Visit <a target="_blank" href="https://avif-converter.online/">the website</a>.</li>
<li>Upload your old images (can be <strong>PNG</strong>, <strong>JPEG</strong>, <strong>GIF </strong>and others).</li>
<li>Wait while the website processes the conversion.</li>
<li>Save your new AVIF files.</li>
</ol>
<h3 id="heading-how-to-create-avif-images-using-avif-supported-image-editors">How to create AVIF images using AVIF-supported image editors</h3>
<p>Image editors are adding support for AVIF image creation. These editors now fully support AVIF images:</p>
<ul>
<li>Microsoft Paint – starting from the <a target="_blank" href="https://www.howto-connect.com/windows-10-1903-version-support-avif-file-type/">"19H1" updates</a>, you can now draw images on Microsoft Paint as “save as” AVIF.</li>
<li>GIMP for Windows and Linux now has AVIF support starting <a target="_blank" href="https://www.ghacks.net/2020/10/09/gimp-2-10-22-update-introduces-support-avif-and-heic-support/">from the 2.10.22 update</a>.</li>
<li>Photoshop developers are also <a target="_blank" href="https://feedback.photoshop.com/conversations/photoshop/when-will-avif-support-be-added-to-photoshop/5f5f46314b561a3d4278baf4">talking about how to support AVIF</a>. Hopefully this will soon be supported.</li>
</ul>
<h2 id="heading-how-to-use-avif-on-your-website">How to Use AVIF on Your Website</h2>
<p>AVIF is still a relatively new technology. But most modern browsers now support the format which means you can use it directly in the <code>&lt;img&gt;</code> tag. Just keep in mind that not all browsers fully support the format yet. </p>
<p>The best way to go about using AVIF is with <strong>content negotiation.</strong> We will be using the HTML 5 <code>&lt;picture&gt;</code> and the <code>&lt;source&gt;</code> which supports content negotiation.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/Group-9how-to-use-avif-html--1-.png" alt="Group-9how-to-use-avif-html--1-" width="600" height="400" loading="lazy"></p>
<p>You can play around with <a target="_blank" href="https://lyty.dev/diy/how-to-use-avif-on-website.html">the live example here</a>.</p>
<h3 id="heading-which-browsers-support-avif">Which browsers support AVIF</h3>
<ul>
<li>The first browser to fully support AVIF is <a target="_blank" href="https://developers.google.com/web/updates/2020/08/nic85#more">Chrome 85</a>. </li>
<li>Microsoft <a target="_blank" href="https://www.howto-connect.com/windows-10-1903-version-support-avif-file-type/">Windows 10 </a> also added support in the "19H1" updates.</li>
<li>Mozilla is still working on the support for the image format in Firefox.[155].</li>
</ul>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>AVIF is a game changer that will soon become the world's defacto image format. Because of its potential features, it is likely that it will soon gain full support on all platforms. </p>
<p>Unlike Google's <strong>WebP</strong> image, which took Apple a whole of 10 years to support, AVIF has quickly attracted Apple's interest to the extent that they now contribute to the project. </p>
<p>Are you ready to start using AVIF on your websites? </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use SVG Images in CSS and HTML – A Tutorial for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ By Edidiong Asikpo SVG stands for Scalable Vector Graphics. It is a unique type of image format for vector-based graphics written in Extensible Markup Language (XML). In this tutorial, I will explain why you'd want to use SVG images and how you can u... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/use-svg-images-in-css-html/</link>
                <guid isPermaLink="false">66d45e48052ad259f07e4aa5</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image optimization  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SVG ]]>
                    </category>
                
                    <category>
                        <![CDATA[ xml ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 16 Nov 2020 22:44:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/11/Screen-Shot-2020-11-15-at-3.59.07-PM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Edidiong Asikpo</p>
<p>SVG stands for Scalable Vector Graphics. It is a unique type of image format for vector-based graphics written in Extensible Markup Language (XML).</p>
<p>In this tutorial, I will explain why you'd want to use SVG images and how you can use them in CSS and HTML.</p>
<h2 id="heading-why-should-you-use-svg-images">Why Should You Use SVG Images?</h2>
<p>There are a number of reasons to use SVG images, some of which are:</p>
<ul>
<li><p>SVG images do not lose their quality when zoomed or resized.</p>
</li>
<li><p>They can be created and edited with an IDE or text editor.</p>
</li>
<li><p>They are accessible and animatable.</p>
</li>
<li><p>They have a small file size and are highly scalable.</p>
</li>
<li><p>And they can be searched, indexed, scripted, and compressed.</p>
</li>
</ul>
<p>Now let's see how you can actually work with SVG images.</p>
<h2 id="heading-how-to-download-the-svg-image-used-in-this-tutorial">How to Download the SVG Image Used in This Tutorial</h2>
<p>If you want to work with the SVG image I've used in this tutorial, follow the steps (and diagram) below to download it.</p>
<ul>
<li><p>Go to <a target="_blank" href="https://undraw.co">unDraw</a>.</p>
</li>
<li><p>Change the background color to yellow.</p>
</li>
<li><p>In the search box, search for the word <strong>happy</strong>.</p>
</li>
</ul>
<p><img src="https://i.imgur.com/ncSY7Rn.png" alt="unDraw's Homepage" width="1836" height="888" loading="lazy"></p>
<ul>
<li><p>Click on the image named <strong>Happy news</strong>.</p>
</li>
<li><p>On the pop-up window, click on the <strong>Download SVG to your projects</strong> button.</p>
</li>
</ul>
<p><img src="https://i.imgur.com/qGrT73n.png" alt="Download the SVG file" width="1336" height="581" loading="lazy"></p>
<p>If you followed the steps above correctly, the SVG image should be on your computer now.</p>
<p><img src="https://i.imgur.com/3uCGy6B.png" alt="Image" width="1003" height="183" loading="lazy"></p>
<p>Now, open the SVG image in your favorite IDE or text editor. Rename it to <strong>happy.svg</strong> or whatever name you prefer.</p>
<h2 id="heading-how-to-use-svg-images-in-css-and-html">How to Use SVG Images in CSS and HTML</h2>
<p>There are several different ways to use SVG images in CSS and HTML. We will explore six different methods in this tutorial.</p>
<h3 id="heading-1-how-to-use-an-svg-as-an">1. How to use an SVG as an <code>&lt;img&gt;</code></h3>
<p>This method is the simplest way to add SVG images to a webpage. To use this method, add the <code>&lt;img&gt;</code> element to your HTML document and reference it in the <code>src</code> attribute, like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span> = <span class="hljs-string">"happy.svg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"My Happy SVG"</span>/&gt;</span>
</code></pre>
<p>Assuming you downloaded the SVG image from unDraw and renamed it to <strong>happy.svg</strong>, you can go ahead and add the code snippet above into your HTML document.</p>
<p>If you did everything correctly, your webpage should look exactly like the demo below. 👀</p>
<div class="embed-wrapper"><iframe src="https://codesandbox.io/embed/svg-demo-mppxs?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%;height:500px;border:0;border-radius:4px;overflow:hidden" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" title="Embedded content" loading="lazy"></iframe></div>

<p>When you add an SVG image using the <code>&lt;img&gt;</code> tag without specifying the size, it assumes the size of the original SVG file.</p>
<p>For instance, in the demo above, I didn't modify the size of the SVG image, so it assumed its original size (which was a width of <code>915.11162px</code> and a height of <code>600.53015px</code> ).</p>
<p><strong>Note:</strong> to change the original size, you have to specify the <code>width</code> and <code>height</code> with CSS as you can see in the demo below. You can also update the original <code>width</code> and <code>height</code> directly.</p>
<div class="embed-wrapper"><iframe src="https://codesandbox.io/embed/svg-demo-1-ey5me?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%;height:500px;border:0;border-radius:4px;overflow:hidden" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" title="Embedded content" loading="lazy"></iframe></div>

<p>Even though we can change the size of SVG images added via the <code>&lt;img&gt;</code> tag, there are still some restrictions if you want to make major style changes to the SVG image.</p>
<h3 id="heading-2-how-to-use-svg-as-a-css-background-image">2. How to use SVG as a CSS <code>background-image</code></h3>
<p>This is similar to adding SVG to an HTML document using the <code>&lt;img&gt;</code> tag. But this time we do it with CSS instead of HTML as you can see in the code snippet below.</p>
<pre><code class="lang-bash">body {
  background-image: url(happy.svg);
}
</code></pre>
<p>When you use an SVG as a CSS background image, it has similar limitations to using <code>&lt;img&gt;</code>. Still, it allows a bit more customization.</p>
<p>Check out the demo below and feel free to make modifications to it using CSS.</p>
<div class="embed-wrapper"><iframe src="https://codesandbox.io/embed/svg-demo-2-ftn6n?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%;height:500px;border:0;border-radius:4px;overflow:hidden" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" title="Embedded content" loading="lazy"></iframe></div>

<h3 id="heading-3-how-to-use-inline-svg-images">3. How to use inline SVG images</h3>
<p>SVG images can be written directly into the HTML document using the<code>&lt;svg&gt; &lt;/svg&gt;</code> tag.</p>
<p>To do this, open the SVG image in VS code or your preferred IDE, copy the code, and paste it inside the <code>&lt;body&gt;</code> element in your HTML document.</p>
<pre><code class="lang-bash">&lt;body&gt;
 // Paste the SVG code here.
&lt;/body&gt;
</code></pre>
<p>If you did everything correctly, your webpage should look exactly like the demo below.</p>
<div class="embed-wrapper"><iframe src="https://codesandbox.io/embed/svg-demo-3-zunkd?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%;height:500px;border:0;border-radius:4px;overflow:hidden" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" title="Embedded content" loading="lazy"></iframe></div>

<p>When you use SVG inline in the HTML document, it reduces load time because it serves as an HTTP request.</p>
<p>Using this method lets you perform more customization as opposed to using either the <code>&lt;img&gt;</code> or <code>background-image</code> methods.</p>
<h3 id="heading-4-how-to-use-an-svg-as-an">4. How to use an SVG as an <code>&lt;object&gt;</code></h3>
<p>You can also use an HTML <code>&lt;object&gt;</code> element to add SVG images to a webpage using the code syntax below:</p>
<pre><code class="lang-bash">&lt;object data=<span class="hljs-string">"happy.svg"</span> width=<span class="hljs-string">"300"</span> height=<span class="hljs-string">"300"</span>&gt; &lt;/object&gt;
</code></pre>
<p>You use the <code>data</code> attribute to specify the URL of the resource that you'll use by the object, which is the SVG image in our case.</p>
<p>You use the <code>width</code> and <code>height</code> to specify the size of the SVG image.</p>
<p>Again, below is a demo for you to explore. 😃</p>
<div class="embed-wrapper"><iframe src="https://codesandbox.io/embed/svg-demo-4-3ge0n?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%;height:500px;border:0;border-radius:4px;overflow:hidden" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" title="Embedded content" loading="lazy"></iframe></div>

<p>Using the <code>&lt;object&gt;</code> is supported across all browsers that support SVG.</p>
<h3 id="heading-5-how-to-use-svg-as-an">5. How to use SVG as an <code>&lt;iframe&gt;</code></h3>
<p>Even though this isn't advisable, you can also add an SVG image using an <code>&lt;iframe&gt;</code> as seen in the demo below.</p>
<div class="embed-wrapper"><iframe src="https://codesandbox.io/embed/svg-demo-5-co3hg?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%;height:500px;border:0;border-radius:4px;overflow:hidden" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" title="Embedded content" loading="lazy"></iframe></div>

<p>Just keep in mind, though, that <code>&lt;iframe&gt;</code>s can be difficult to maintain and will be bad for your site's Search Engine Optimization (SEO).</p>
<p>Using <code>&lt;iframe&gt;</code> also defeats the purpose of the <em>Scalable</em> in the name <em>Scalable Vector Graphics</em> because SVG images added with this format are not scalable.</p>
<h3 id="heading-6-how-to-use-svg-as-an">6. How to use SVG as an <code>&lt;embed&gt;</code></h3>
<p>The HTML <code>&lt;embed&gt;</code> element is another way to use an SVG image in HTML and CSS using this syntax: <code>&lt;embed src="happy.svg" /&gt;</code>.</p>
<p>Keep in mind, however, that this method has limitations, too. According to MDN, most modern browsers have deprecated and removed support for browser plug-ins. This means that relying upon <code>&lt;embed&gt;</code> is generally not wise if you want your site to be operable on the average user's browser.</p>
<p>Below is a demo of using the HTML <code>&lt;embed&gt;</code> element to add an SVG image.</p>
<div class="embed-wrapper"><iframe src="https://codesandbox.io/embed/svg-demo-6-iwy0s?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%;height:500px;border:0;border-radius:4px;overflow:hidden" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" title="Embedded content" loading="lazy"></iframe></div>

<h2 id="heading-conclusion">Conclusion</h2>
<p>I hope you were able to learn about the different ways of using SVG images in CSS and HTML. This will hopefully guide you towards choosing the right method when adding SVG images to a website.</p>
<p>If you have any questions, you can send me a <a target="_blank" href="https://twitter.com/Didicodes">message on Twitter</a>, and I'll be happy to answer every single one.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ A Basic Intro to Image Optimization for the Web ]]>
                </title>
                <description>
                    <![CDATA[ By Anton Garcia Diaz Images are an essential ingredient of most websites. The visual quality of pictures has a direct impact on the brand image and the message those images convey. And the weight of images usually accounts for a 40-60% of the data tr... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/image-optimization/</link>
                <guid isPermaLink="false">66d45d9e37bd2215d1e24586</guid>
                
                    <category>
                        <![CDATA[ image optimization  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 30 Apr 2020 07:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/04/image-breakpoints-2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Anton Garcia Diaz</p>
<p>Images are an essential ingredient of most websites. The visual quality of pictures has a direct impact on the brand image and the message those images convey. And the weight of images usually accounts for a 40-60% of the data transferred on the web. </p>
<p>This usually has the largest impact on loading time over other resources like JavaScript. So, whether we're creating or running a website, we should put in place an image transformation and optimization pipeline.</p>
<p>There are many options to do this, from in-house developments based on open source libraries and suites – like ImageMagick – to cloud-based tools and APIs. </p>
<p>Whatever tool we use in our deployment, there are four main tasks that, at the very least, any pipeline should accomplish.</p>
<h3 id="heading-resize-images">Resize images.</h3>
<p>Image resizing is the first and most important step. It brings a big impact on weight with no visual quality penalty, as long as we don't make it smaller than the displaying resolution. </p>
<p>We should always set and enforce a maximum image resolution in our website, for instance 2000 px width. Ideally, we'd make our website responsive by setting different breakpoints and delivering images that fit in our users' displays. </p>
<p>If you need help on choosing your breakpoints, check out this article on the <a target="_blank" href="https://abraia.me/docs/best-image-sizes-for-web/">best image sizes for web</a>.</p>
<h3 id="heading-convert-to-the-right-format">Convert to the right format.</h3>
<p>JPEG is the default format in the web. PNG may work better with graphic designs featuring solid colors, but in these cases it may yield lower weight with better quality. </p>
<p>You may consider offering WEBP for Chrome, Edge, Firefox and Android users, keeping JPEG as fallback for Safari and iOS. It may save 10-30% of image weight with very similar quality, perhaps some more blur and less ringing. </p>
<p>For an up to date revision you may check out this article on <a target="_blank" href="https://abraia.me/docs/best-image-formats-for-web/">image formats for web</a>.</p>
<h3 id="heading-compress-images-properly">Compress images properly.</h3>
<p>We can do this with a powerful open source suite like <a target="_blank" href="https://imagemagick.org/index.php">ImageMagick</a> and simply set a quality factor (typically 75 to 85) for JPEG (and WEBP) images. You can still use a perceptual metric to better protect quality and further squeeze weight – this is an option available in some cloud <a target="_blank" href="https://abraia.me/docs/image-optimization/#automatic-image-optimization-for-web">image optimization tools</a>.</p>
<h3 id="heading-get-rid-of-metadata">Get rid of metadata.</h3>
<p>From shooting to editing, images accumulate metadata, like <a target="_blank" href="https://abraia.me/docs/exif-data-orientation/">exif data</a>. While they may be useful for editing and management purposes, they have no impact on how images show in our web. Their weight can easily get 20 KB or more per image. </p>
<p>We should get rid of metadata before publishing on the web. We only have to make sure that images are coded with the proper orientation and with a sRGB profile, adhering to good <a target="_blank" href="https://abraia.me/docs/color-management-for-web/">color management</a> practices.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to generate product images for Amazon, Instagram, Zalando, and Tmall ]]>
                </title>
                <description>
                    <![CDATA[ By Anton Garcia Diaz Millions of people have already shifted from traditional tv to online content, and from traditional malls to online stores. Because of this, e-commerce and marketing teams need to deploy and maintain strong online presences for t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/generation-of-product-images-for-amazon-zalando-tmall-instagram-asos/</link>
                <guid isPermaLink="false">66d45d9c052ad259f07e4a61</guid>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image optimization  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image processing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ responsive images ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 26 Nov 2019 15:54:54 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/11/123brand.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Anton Garcia Diaz</p>
<p>Millions of people have already shifted from traditional tv to online content, and from traditional malls to online stores. Because of this, e-commerce and marketing teams need to deploy and maintain strong online presences for their businesses. </p>
<p>This usually means running the brand's own online store and having a presence in different marketplaces that cover different regions and population segments. The never-ending list of possible marketplaces in which to showcase, promote, and sell products just gets longer and longer.</p>
<p>To make matters worse, different marketplaces have different requirements and restrictions on images, which can add a burden for the devops and marketing teams. It's also a source of inconsistency in the public image of a brand.</p>
<p>Here, we'll review the main aspects to consider when setting up a clean pipeline for the seamless production of omnichannel images.</p>
<h2 id="heading-a-single-master-image-through-a-single-pipeline">A single master image through a single pipeline</h2>
<p>To simplify workflows and keep them sustainable, a good practice is to apply the principles of omnichannel to images. This basically means to set a single, easy to configure pipeline for the creation of variants, from the same master or pristine images. Under this approach, we can use <strong>the same product image for every channel</strong>. </p>
<p>Our pipeline should receive master images and produce the derivatives needed to feed the marketplaces. At a minimum, it should cope with a workflow like this.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://store.abraia.me/05bf471cbb3f9fa9ed785718e6f60e28/product-images-for-amazon-zalando-tmall-lamoda-ssg/generation-of-variants/index.html">https://store.abraia.me/05bf471cbb3f9fa9ed785718e6f60e28/product-images-for-amazon-zalando-tmall-lamoda-ssg/generation-of-variants/index.html</a></div>
<p>Of course, a front-end and cloud storage are not necessary. The pipeline may just work by watching a hot folder and creating the variants as master images land there. We'll also take a look at this.</p>
<h2 id="heading-image-transformation-and-optimization">Image transformation and optimization</h2>
<p>Each web channel has its own web design and layout. As for images, this means different and specific aspect ratios. Besides, each marketplace usually has an image policy in place, which limits the resolution and the weight of the image and sets the admissible image format. Usually, it also specifies other style guidelines.</p>
<p>Let's look at the main operations we'll want to accomplish with our pipeline.</p>
<h3 id="heading-resizing-cropping-padding">Resizing, cropping, padding</h3>
<p>To change the aspect ratio of an image we may crop it or pad it. To get a squared image from a vertical one we may cut out the upper and bottom parts or we may fill in the left and right sides with white stripes. </p>
<p>There are open source tools – like ImageMagick – that allow you to perform these operations effectively. Resizing an image with ImageMagick to limit its maximum dimensions to 800 px is as simple as this:</p>
<pre><code>convert input.jpg -resize <span class="hljs-number">800</span>x800 resized.jpg
</code></pre><p>This instruction respects the aspect ratio. If the original image is not squared, then the resized image has one dimension lower than 800 px.  Let's say the image is vertical and we want it for Tmall, which requires a squared image of 800x800 px. Then we may pad it like this:</p>
<pre><code>convert resized.jpg  -gravity center -extent <span class="hljs-number">800</span>x800 padded.jpg
</code></pre><p>Also, we may simply crop it to fit the dimensions:</p>
<pre><code>convert input.jpg -gravity Center  -crop <span class="hljs-number">800</span>x800+<span class="hljs-number">0</span>+<span class="hljs-number">0</span> +repage crop.jpg
</code></pre><p>While some marketplaces like Tmall encourage padding images with white stripes and branding them with logos to use them in category pages, others like Amazon or Lamoda forbid this practice. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/crop_pad.png" alt="Image" width="600" height="400" loading="lazy">
<em>Cropping (left), Resizing (center), Resizing and padding (right)</em></p>
<p>When we pad an image to match the aspect ratio, we don’t risk cropping out important parts. In fact, padding is a trick to keep the aspect ratio unchanged. However, the risk is real when we crop the image. </p>
<p>So, it is a good practice to ensure in the studio that we comply with some composition requirements set by each channel. We should produce master images with a view of the product compatible with the different aspect ratios that we'll deliver.</p>
<h3 id="heading-smart-cropping">Smart cropping</h3>
<p>There are algorithms inspired by human attention and aesthetic perception that provide an enhanced protection against bad automatic crops. In the next example, with smart image cropping (white line) we avoid cutting the face unlike a simple center cropping (red line) would do.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/smart-cropping-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Example of smart cropping with a <a target="_blank" href="https://abraia.me/workflows/">cloud service</a> vs center cropping</em></p>
<p>This option is available in some cloud services. If we're going to use it, we should verify that it works properly for us because many solutions only use an attention map and do not consider aesthetic aspects. Usually, choosing a number of representative images, making some tests with them, and finally verifying the results is enough to get a good grasp.</p>
<h3 id="heading-overlaying-logos-and-text">Overlaying logos and text</h3>
<p>We may also need to add our brand logo or to add a message to the image by overlaying a vector graphic or a text. Moreover, in many cases we need some content localization strategy in place – like tailoring discounts and language to a market region. Sticking to our example, with ImageMagick we can overlay text on a padded image.</p>
<pre><code>convert -fill black -pointsize <span class="hljs-number">70</span> -gravity center -draw <span class="hljs-string">"rotate -90 text 0,-330 'MyBrandHere'"</span> padded.jpg padded-<span class="hljs-keyword">with</span>-brand.jpg
</code></pre><p>Once we configure it for one image, we may apply it to any other with the same dimensions. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/brand.png" alt="Image" width="600" height="400" loading="lazy">
<em>Examples of batch image branding using <a target="_blank" href="https://abraia.me/workflows/">Abraia's cloud service</a></em></p>
<p>Otherwise, handling typographies and different settings may end being tricky in workflows with certain complexity. In this regard, a <a target="_blank" href="https://abraia.me/workflows/">cloud service</a> usually provides a front-end to make the configuration intuitive and fast, and more convenient to handle. It also deals with other stuff like typographies or quality preservation in image recompression. </p>
<h2 id="heading-the-workflows">The workflows</h2>
<p>There are many ways to deploy an image processing pipeline. Depending on the flow rate of images, we may need to support different types of workflows.  </p>
<h3 id="heading-batch-processing">Batch processing</h3>
<p>In the most simple case – when the flow rate is low – a batch image processing solution may be enough. With ImageMagick, we can use <em>mogrify</em> (instead of convert) to process all the images inside a folder. </p>
<p>In certain cases, like image versions with a text in different languages, we may need to code a script, but that's not a big deal either. To make it even easier, we may use a cloud batch processing tool in which we drop images and it gives us back all the variants we need, like in the video at the beginning of the post.</p>
<h3 id="heading-hot-folders">Hot folders</h3>
<p>For in-house deployments where we need something more than simple batch image processing, the use of hot folders may be a good option. In this case, we should set a worker that watches a folder. Any time an image lands the folder the watcher triggers the process that creates all the variants we need.</p>
<p>In this regard, Gulp comes very handy to implement a folder watching pipeline. <a target="_blank" href="https://github.com/abraia/workflows">This GitHub repository brings a ready-to-use implementation of hot folder</a> based on Gulp. It allows us to transform images using Abraia's cloud service or optimize them using Imagemin (an open source solution). Once installed, the watcher is easily started with just one command in the terminal.</p>
<pre><code>$ gulp
</code></pre><p>This video shows the process at work.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://store.abraia.me/05bf471cbb3f9fa9ed785718e6f60e28/product-images-for-amazon-zalando-tmall-lamoda-ssg/hot-folder-gulp/index.html">https://store.abraia.me/05bf471cbb3f9fa9ed785718e6f60e28/product-images-for-amazon-zalando-tmall-lamoda-ssg/hot-folder-gulp/index.html</a></div>
<h3 id="heading-full-cloud">Full cloud</h3>
<p>Cloud services usually bring the most flexible and fast-to-deploy solution. Still, there are different ways to go full cloud. In the most simple approach from a user perspective, an image management and optimization service takes charge of the transformation. It also manages the delivery to end users (through a CDN) or other web channels like marketplaces and social networks. The user only needs to upload the master images and to configure the transformations, usually with an intuitive graphic interface.</p>
<p>In medium to large companies that manage their own cloud, services from different providers are usually combined. In this case, we are likely to have to manage private and public buckets. We can have a service accessing a bucket, creating the variants, and delivering the resources or just returning them to a different bucket. </p>
<p>Also, a cloud pipeline may be partially implemented in-house. In this case we have endless possibilities. However, such development effort only makes sense when no service complies with the requirements and there is a justified need for a tailored solution.</p>
<h2 id="heading-summary">Summary</h2>
<p>Studio shooting and photography retouching are time-consuming and costly operations. Being able to use the same master material everywhere is very important to keep times and cost under control.</p>
<p>We have reviewed the main aspects of a complete pipeline in charge of creating image variants. On one hand, we looked at the transformations you need to perform from resizing, cropping, or padding, to the overlay of texts and graphics. On the other, we looked at the workflows to implement from batch processing to hot folders or full cloud solutions. We have reviewed some important open source resources (like ImageMagick or Gulp) that make it possible to implement a pipeline you develop yourself. </p>
<p>In the end, there are two main factors to consider when deciding whether to use an in-house or a cloud service. First, you must evaluate your willingness to take on the development effort. Second, you need to decide what features you require, from an easy to use interface for the configuration of variants to advanced features like smart cropping.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Building the React Image Optimization Component for Tueri.io ]]>
                </title>
                <description>
                    <![CDATA[ By Dane Stevens Let’s face it, image optimization is hard. We want to make it effortless. When we set out to build our React Component there were a few problems we wanted to solve: Automatically decide image width for any device based on the parent... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/building-the-react-image-optimization-component-for-tueri-io/</link>
                <guid isPermaLink="false">66d84e855a0b456f4d321452</guid>
                
                    <category>
                        <![CDATA[ Image Placeholder ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image optimization  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ responsive images ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 11 Jun 2019 18:37:17 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/06/progressive.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Dane Stevens</p>
<p><img src="https://cdn.tueri.io/274877906967/low-quality-image-placeholder-example.png" alt="Low-quality Image Placeholder" width="1428" height="1046" loading="lazy"></p>
<p>Let’s face it, image optimization is hard. We want to make it effortless.</p>
<p>When we set out to build our React Component there were a few problems we wanted to solve:</p>
<ul>
<li><p>Automatically decide image width for any device based on the parent container.</p>
</li>
<li><p>Use the best possible image format the user’s browser supports.</p>
</li>
<li><p>Automatic image lazy loading.</p>
</li>
<li><p>Automatic low-quality image placeholders (LQIP).</p>
</li>
</ul>
<p>Oh, and it had to be effortless for React Developers to use.</p>
<h2 id="heading-this-is-what-we-came-up-with">This is what we came up with:</h2>
<pre><code class="lang-jsx">&lt;Img src={ tueriImageId } alt=<span class="hljs-string">'Alt Text'</span> /&gt;
</code></pre>
<p>Easy right? Let’s dive in.</p>
<h2 id="heading-calculating-the-image-size">Calculating the image size:</h2>
<p>Create a <code>&lt;figure /&gt;</code> element, detect the width and build an image URL:</p>
<pre><code class="lang-jsx"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Img</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{

    <span class="hljs-keyword">constructor</span>(props) {
        <span class="hljs-built_in">super</span>(props)
        <span class="hljs-built_in">this</span>.state = {
            <span class="hljs-attr">width</span>: <span class="hljs-number">0</span>
        }
        <span class="hljs-built_in">this</span>.imgRef = React.createRef()
    }

    componentDidMount() {
        <span class="hljs-keyword">const</span> width = <span class="hljs-built_in">this</span>.imgRef.current.clientWidth
        <span class="hljs-built_in">this</span>.setState({
            width
        })
    }

    render() {

        <span class="hljs-comment">// Destructure props and state</span>
        <span class="hljs-keyword">const</span> { src, alt, options = {}, ext = <span class="hljs-string">'jpg'</span> } = <span class="hljs-built_in">this</span>.props
        <span class="hljs-keyword">const</span> { width } = <span class="hljs-built_in">this</span>.state

        <span class="hljs-comment">// Create an empty query string</span>
        <span class="hljs-keyword">let</span> queryString = <span class="hljs-string">''</span>        

        <span class="hljs-comment">// If width is specified, otherwise use auto-detected width</span>
        options[<span class="hljs-string">'w'</span>] = options[<span class="hljs-string">'w'</span>] || width

        <span class="hljs-comment">// Loop through option object and build queryString</span>
        <span class="hljs-built_in">Object</span>.keys(options).map(<span class="hljs-function">(<span class="hljs-params">option, i</span>) =&gt;</span> {
            <span class="hljs-keyword">return</span> queryString +=  <span class="hljs-string">`<span class="hljs-subst">${i &lt; <span class="hljs-number">1</span> ? <span class="hljs-string">'?'</span> : <span class="hljs-string">'&amp;'</span>}</span><span class="hljs-subst">${option}</span>=<span class="hljs-subst">${options[option]}</span>`</span>
        })

        <span class="hljs-keyword">return</span>(
            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">figure</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{this.imgRef}</span>&gt;</span>
                { 
                    // If the container width has been set, display the image else null
                    width &gt; 0 ? (
                        <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
                            <span class="hljs-attr">src</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">https:</span>//<span class="hljs-attr">cdn.tueri.io</span>/${ <span class="hljs-attr">src</span> }/${ <span class="hljs-attr">kebabCase</span>(<span class="hljs-attr">alt</span>) }<span class="hljs-attr">.</span>${ <span class="hljs-attr">ext</span> }${ <span class="hljs-attr">queryString</span> }`}
                            <span class="hljs-attr">alt</span>=<span class="hljs-string">{</span> <span class="hljs-attr">alt</span> }
                        /&gt;</span>
                    ) : null 
                }
            <span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span></span>
        )

    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Img
</code></pre>
<p>This returns the following HTML:</p>
<pre><code class="lang-jsx">&lt;figure&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
        <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.tueri.io/tueriImageId/alt-text.jpg?w=autoCalculatedWidth"</span> 
        <span class="hljs-attr">alt</span>=<span class="hljs-string">"Alt Text"</span> 
    /&gt;</span></span>
&lt;/figure&gt;
</code></pre>
<h2 id="heading-use-the-best-possible-image-format">Use the best possible image format:</h2>
<p>Next, we needed to add support for detecting WebP images and having the Tueri service return the image in the WebP format:</p>
<pre><code class="lang-jsx"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Img</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{

    <span class="hljs-keyword">constructor</span>(props) {
        <span class="hljs-comment">// ...</span>
        <span class="hljs-built_in">this</span>.window = <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">window</span> !== <span class="hljs-string">'undefined'</span> &amp;&amp; <span class="hljs-built_in">window</span>
        <span class="hljs-built_in">this</span>.isWebpSupported = <span class="hljs-built_in">this</span>.isWebpSupported.bind(<span class="hljs-built_in">this</span>)
    }

    <span class="hljs-comment">// ...</span>

    isWebpSupported() {
        <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.window.createImageBitmap) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

    render() {

        <span class="hljs-comment">// ...</span>

        <span class="hljs-comment">// If a format has not been specified, detect webp support</span>
        <span class="hljs-comment">// Set the fm (format) option in the image URL</span>
        <span class="hljs-keyword">if</span> (!options[<span class="hljs-string">'fm'</span>] &amp;&amp; <span class="hljs-built_in">this</span>.isWebpSupported) {
            options[<span class="hljs-string">'fm'</span>] = <span class="hljs-string">'webp'</span>
        }

        <span class="hljs-comment">// ...</span>

        <span class="hljs-keyword">return</span> (
            <span class="hljs-comment">// ...</span>
        )

    }
}

<span class="hljs-comment">// ...</span>
</code></pre>
<p>This returns the following HTML:</p>
<pre><code class="lang-jsx">&lt;figure&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
        <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.tueri.io/tueriImageId/alt-text.jpg?w=autoCalculatedWidth&amp;fm=webp"</span> 
        <span class="hljs-attr">alt</span>=<span class="hljs-string">"Alt Text"</span> 
    /&gt;</span></span>
&lt;/figure&gt;
</code></pre>
<h2 id="heading-automatic-image-lazy-loading">Automatic image lazy loading:</h2>
<p>Now, we need to find out if the <code>&lt;figure /&gt;</code> element is in the viewport, plus we add a little buffer area so the images load just before being scrolled into view.</p>
<pre><code class="lang-jsx">   <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Img</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{

   <span class="hljs-keyword">constructor</span>(props) {
       <span class="hljs-comment">// ...</span>
       <span class="hljs-built_in">this</span>.state = {
           <span class="hljs-comment">// ...</span>
           <span class="hljs-attr">isInViewport</span>: <span class="hljs-literal">false</span>
           <span class="hljs-attr">lqipLoaded</span>: <span class="hljs-literal">false</span>
       }
       <span class="hljs-comment">// ...</span>
       <span class="hljs-built_in">this</span>.handleViewport = <span class="hljs-built_in">this</span>.handleViewport.bind(<span class="hljs-built_in">this</span>)
   }

   componentDidMount() {
       <span class="hljs-comment">// ...</span>
       <span class="hljs-built_in">this</span>.handleViewport()
       <span class="hljs-built_in">this</span>.window.addEventListener(<span class="hljs-string">'scroll'</span>, <span class="hljs-built_in">this</span>.handleViewport)
   }

   handleViewport() {
       <span class="hljs-comment">// Only run if the image has not already been loaded</span>
       <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.imgRef.current &amp;&amp; !<span class="hljs-built_in">this</span>.state.lqipLoaded) {
           <span class="hljs-comment">// Get the viewport height</span>
           <span class="hljs-keyword">const</span> windowHeight = <span class="hljs-built_in">this</span>.window.innerHeight
           <span class="hljs-comment">// Get the top position of the &lt;figure /&gt; element</span>
           <span class="hljs-keyword">const</span> imageTopPosition = <span class="hljs-built_in">this</span>.imgRef.current.getBoundingClientRect().top
           <span class="hljs-comment">// Multiply the viewport * buffer (default buffer: 1.5)</span>
           <span class="hljs-keyword">const</span> buffer = <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">this</span>.props.buffer === <span class="hljs-string">'number'</span> &amp;&amp; <span class="hljs-built_in">this</span>.props.buffer &gt; <span class="hljs-number">1</span> &amp;&amp; <span class="hljs-built_in">this</span>.props.buffer &lt; <span class="hljs-number">10</span> ? <span class="hljs-built_in">this</span>.props.buffer : <span class="hljs-number">1.5</span>
           <span class="hljs-comment">// If &lt;figure /&gt; is in viewport</span>
           <span class="hljs-keyword">if</span> (windowHeight * buffer &gt; imageTopPosition) {
               <span class="hljs-built_in">this</span>.setState({
                   <span class="hljs-attr">isInViewport</span>: <span class="hljs-literal">true</span>
               })
           }
       }
   }

   <span class="hljs-comment">// ...</span>

   componentWillUnmount() {
       <span class="hljs-built_in">this</span>.window.removeEventListener(<span class="hljs-string">'scroll'</span>, <span class="hljs-built_in">this</span>.handleViewport)
   }

   render() {

       <span class="hljs-comment">// Destructure props and state</span>
       <span class="hljs-comment">// ...</span>
       <span class="hljs-keyword">const</span> { isInViewport, width } = <span class="hljs-built_in">this</span>.state

       <span class="hljs-comment">// ...</span>

       <span class="hljs-keyword">return</span> (
           <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">figure</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{this.imgRef}</span>&gt;</span>
               { 
                   // If the container width has been set, display the image else null
                   isInViewport &amp;&amp; width &gt; 0 ? (
                       <span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
                           <span class="hljs-attr">onLoad</span>=<span class="hljs-string">{</span> () =&gt;</span> { this.setState({ lqipLoaded: true }) } }
                           // ...
                       /&gt;
                   ) : null 
               }
           <span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span></span>
       )

   }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Img
</code></pre>
<h2 id="heading-automatic-low-quality-image-placeholders-lqip">Automatic low-quality image placeholders (LQIP):</h2>
<p>Finally, when an image is in the viewport, we want to load a 1/10 size blurred image, then fade out the placeholder image when the full-size image is loaded:</p>
<pre><code class="lang-jsx"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Img</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{

    <span class="hljs-keyword">constructor</span>(props) {
        <span class="hljs-comment">// ...</span>
        <span class="hljs-built_in">this</span>.state = {
            <span class="hljs-comment">// ...</span>
            <span class="hljs-attr">fullsizeLoaded</span>: <span class="hljs-literal">false</span>
        }

        <span class="hljs-comment">// ...</span>

    }

    <span class="hljs-comment">// ...</span>

    render() {

        <span class="hljs-comment">// Destructure props and state</span>
        <span class="hljs-comment">// ...</span>
        <span class="hljs-keyword">const</span> { isInViewport, width, fullsizeLoaded } = <span class="hljs-built_in">this</span>.state

        <span class="hljs-comment">// ...</span>

        <span class="hljs-comment">// Modify the queryString for the LQIP image: replace the width param with a value 1/10 the fullsize</span>
        <span class="hljs-keyword">const</span> lqipQueryString = queryString.replace(<span class="hljs-string">`w=<span class="hljs-subst">${ width }</span>`</span>, <span class="hljs-string">`w=<span class="hljs-subst">${ <span class="hljs-built_in">Math</span>.round(width * <span class="hljs-number">0.1</span>) }</span>`</span>)

        <span class="hljs-comment">// Set the default styles. The full size image should be absolutely positioned within the &lt;figure /&gt; element</span>
        <span class="hljs-keyword">const</span> styles = {
            <span class="hljs-attr">figure</span>: {
                <span class="hljs-attr">position</span>: <span class="hljs-string">'relative'</span>,
                <span class="hljs-attr">margin</span>: <span class="hljs-number">0</span>
            },
            <span class="hljs-attr">lqip</span>: {
                <span class="hljs-attr">width</span>: <span class="hljs-string">'100%'</span>,
                <span class="hljs-attr">filter</span>: <span class="hljs-string">'blur(5px)'</span>,
                <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span>,
                <span class="hljs-attr">transition</span>: <span class="hljs-string">'all 0.5s ease-in'</span>
            },
            <span class="hljs-attr">fullsize</span>: {
                <span class="hljs-attr">position</span>: <span class="hljs-string">'absolute'</span>,
                <span class="hljs-attr">top</span>: <span class="hljs-string">'0px'</span>,
                <span class="hljs-attr">left</span>: <span class="hljs-string">'0px'</span>,
                <span class="hljs-attr">transition</span>: <span class="hljs-string">'all 0.5s ease-in'</span>
            }
        }

        <span class="hljs-comment">// When the fullsize image is loaded, fade out the LQIP</span>
        <span class="hljs-keyword">if</span> (fullsizeLoaded) {
            styles.lqip.opacity = <span class="hljs-number">0</span>
        }

        <span class="hljs-keyword">return</span>(
            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">figure</span>
                <span class="hljs-attr">style</span>=<span class="hljs-string">{</span> <span class="hljs-attr">styles.figure</span> }
                // <span class="hljs-attr">...</span>
            &gt;</span>
                {
                    isInViewport &amp;&amp; width &gt; 0 ? (
                        <span class="hljs-tag">&lt;<span class="hljs-name">React.Fragment</span>&gt;</span>

                            {/* Load fullsize image in background */}
                            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
                                <span class="hljs-attr">onLoad</span>=<span class="hljs-string">{</span> () =&gt;</span> { this.setState({ fullsizeLoaded: true }) } }
                                style={ styles.fullsize }
                                src={`https://cdn.tueri.io/${ src }/${ kebabCase(alt) }.${ ext }${ queryString }`}
                                alt={ alt }
                            /&gt;

                            {/* Load LQIP in foreground */}
                            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
                                <span class="hljs-attr">onLoad</span>=<span class="hljs-string">{</span> () =&gt;</span> { this.setState({ lqipLoaded: true }) } }
                                style={ styles.lqip }
                                src={`https://cdn.tueri.io/${ src }/${ kebabCase(alt) }.${ ext }${ lqipQueryString }`} 
                                alt={ alt } 
                            /&gt;
                        <span class="hljs-tag">&lt;/<span class="hljs-name">React.Fragment</span>&gt;</span>
                    ) : null
                }            
            <span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span></span>
        )

    }
}

<span class="hljs-comment">// ...</span>
</code></pre>
<h2 id="heading-putting-it-all-together">Putting it all together:</h2>
<p>Image optimization made effortless. Just swap out your regular <code>&lt;img /&gt;</code> elements for the Tueri <code>&lt;Img /&gt;</code> and never worry about optimization again.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> PropTypes <span class="hljs-keyword">from</span> <span class="hljs-string">'prop-types'</span>
<span class="hljs-keyword">import</span> { TueriContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'./Provider'</span>
<span class="hljs-keyword">import</span> kebabCase <span class="hljs-keyword">from</span> <span class="hljs-string">'lodash.kebabcase'</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Img</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{

    <span class="hljs-keyword">constructor</span>(props) {
        <span class="hljs-built_in">super</span>(props)
        <span class="hljs-built_in">this</span>.state = {
            <span class="hljs-attr">isInViewport</span>: <span class="hljs-literal">false</span>,
            <span class="hljs-attr">width</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">height</span>: <span class="hljs-number">0</span>,
            <span class="hljs-attr">lqipLoaded</span>: <span class="hljs-literal">false</span>,
            <span class="hljs-attr">fullsizeLoaded</span>: <span class="hljs-literal">false</span>
        }

        <span class="hljs-built_in">this</span>.imgRef = React.createRef()
        <span class="hljs-built_in">this</span>.window = <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">window</span> !== <span class="hljs-string">'undefined'</span> &amp;&amp; <span class="hljs-built_in">window</span> 
        <span class="hljs-built_in">this</span>.handleViewport = <span class="hljs-built_in">this</span>.handleViewport.bind(<span class="hljs-built_in">this</span>)       
        <span class="hljs-built_in">this</span>.isWebpSupported = <span class="hljs-built_in">this</span>.isWebpSupported.bind(<span class="hljs-built_in">this</span>)

    }

    componentDidMount() {

        <span class="hljs-keyword">const</span> width = <span class="hljs-built_in">this</span>.imgRef.current.clientWidth

        <span class="hljs-built_in">this</span>.setState({
            width
        })

        <span class="hljs-built_in">this</span>.handleViewport()

        <span class="hljs-built_in">this</span>.window.addEventListener(<span class="hljs-string">'scroll'</span>, <span class="hljs-built_in">this</span>.handleViewport)

    }

    handleViewport() {
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.imgRef.current &amp;&amp; !<span class="hljs-built_in">this</span>.state.lqipLoaded) {
            <span class="hljs-keyword">const</span> windowHeight = <span class="hljs-built_in">this</span>.window.innerHeight
            <span class="hljs-keyword">const</span> imageTopPosition = <span class="hljs-built_in">this</span>.imgRef.current.getBoundingClientRect().top
            <span class="hljs-keyword">const</span> buffer = <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">this</span>.props.buffer === <span class="hljs-string">'number'</span> &amp;&amp; <span class="hljs-built_in">this</span>.props.buffer &gt; <span class="hljs-number">1</span> &amp;&amp; <span class="hljs-built_in">this</span>.props.buffer &lt; <span class="hljs-number">10</span> ? <span class="hljs-built_in">this</span>.props.buffer : <span class="hljs-number">1.5</span>
            <span class="hljs-keyword">if</span> (windowHeight * buffer &gt; imageTopPosition) {
                <span class="hljs-built_in">this</span>.setState({
                    <span class="hljs-attr">isInViewport</span>: <span class="hljs-literal">true</span>
                })
            }

        }
    }

    isWebpSupported() {
        <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.window.createImageBitmap) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

    componentWillUnmount() {
        <span class="hljs-built_in">this</span>.window.removeEventListener(<span class="hljs-string">'scroll'</span>, <span class="hljs-built_in">this</span>.handleViewport)
    }

    render() {

        <span class="hljs-comment">// Destructure props and state</span>
        <span class="hljs-keyword">const</span> { src, alt, options = {}, ext = <span class="hljs-string">'jpg'</span> } = <span class="hljs-built_in">this</span>.props
        <span class="hljs-keyword">const</span> { isInViewport, width, fullsizeLoaded } = <span class="hljs-built_in">this</span>.state

        <span class="hljs-comment">// Create an empty query string</span>
        <span class="hljs-keyword">let</span> queryString = <span class="hljs-string">''</span>

        <span class="hljs-comment">// If width is specified, otherwise use auto-detected width</span>
        options[<span class="hljs-string">'w'</span>] = options[<span class="hljs-string">'w'</span>] || width

        <span class="hljs-comment">// If a format has not been specified, detect webp support</span>
        <span class="hljs-keyword">if</span> (!options[<span class="hljs-string">'fm'</span>] &amp;&amp; <span class="hljs-built_in">this</span>.isWebpSupported) {
            options[<span class="hljs-string">'fm'</span>] = <span class="hljs-string">'webp'</span>
        }

        <span class="hljs-comment">// Loop through option prop and build queryString</span>
        <span class="hljs-built_in">Object</span>.keys(options).map(<span class="hljs-function">(<span class="hljs-params">option, i</span>) =&gt;</span> {
            <span class="hljs-keyword">return</span> queryString +=  <span class="hljs-string">`<span class="hljs-subst">${i &lt; <span class="hljs-number">1</span> ? <span class="hljs-string">'?'</span> : <span class="hljs-string">'&amp;'</span>}</span><span class="hljs-subst">${option}</span>=<span class="hljs-subst">${options[option]}</span>`</span>
        })

        <span class="hljs-comment">// Modify the queryString for the LQIP image: replace the width param with a value 1/10 the fullsize</span>
        <span class="hljs-keyword">const</span> lqipQueryString = queryString.replace(<span class="hljs-string">`w=<span class="hljs-subst">${ width }</span>`</span>, <span class="hljs-string">`w=<span class="hljs-subst">${ <span class="hljs-built_in">Math</span>.round(width * <span class="hljs-number">0.1</span>) }</span>`</span>)

        <span class="hljs-keyword">const</span> styles = {
            <span class="hljs-attr">figure</span>: {
                <span class="hljs-attr">position</span>: <span class="hljs-string">'relative'</span>,
                <span class="hljs-attr">margin</span>: <span class="hljs-number">0</span>
            },
            <span class="hljs-attr">lqip</span>: {
                <span class="hljs-attr">width</span>: <span class="hljs-string">'100%'</span>,
                <span class="hljs-attr">filter</span>: <span class="hljs-string">'blur(5px)'</span>,
                <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span>,
                <span class="hljs-attr">transition</span>: <span class="hljs-string">'all 0.5s ease-in'</span>
            },
            <span class="hljs-attr">fullsize</span>: {
                <span class="hljs-attr">position</span>: <span class="hljs-string">'absolute'</span>,
                <span class="hljs-attr">top</span>: <span class="hljs-string">'0px'</span>,
                <span class="hljs-attr">left</span>: <span class="hljs-string">'0px'</span>,
                <span class="hljs-attr">transition</span>: <span class="hljs-string">'all 0.5s ease-in'</span>
            }
        }

        <span class="hljs-comment">// When the fullsize image is loaded, fade out the LQIP</span>
        <span class="hljs-keyword">if</span> (fullsizeLoaded) {
            styles.lqip.opacity = <span class="hljs-number">0</span>
        }

        <span class="hljs-keyword">const</span> missingALt = <span class="hljs-string">'ALT TEXT IS REQUIRED'</span>

        <span class="hljs-keyword">return</span>(
            <span class="hljs-comment">// Return the CDN domain from the TueriProvider</span>
            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TueriContext.Consumer</span>&gt;</span>
                {({ domain }) =&gt; (
                    <span class="hljs-tag">&lt;<span class="hljs-name">figure</span>
                        <span class="hljs-attr">style</span>=<span class="hljs-string">{</span> <span class="hljs-attr">styles.figure</span> }
                        <span class="hljs-attr">ref</span>=<span class="hljs-string">{this.imgRef}</span>
                    &gt;</span>
                        {
                            // 
                            isInViewport &amp;&amp; width &gt; 0 ? (
                                <span class="hljs-tag">&lt;<span class="hljs-name">React.Fragment</span>&gt;</span>

                                    {/* Load fullsize image in background */}
                                    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
                                        <span class="hljs-attr">onLoad</span>=<span class="hljs-string">{</span> () =&gt;</span> { this.setState({ fullsizeLoaded: true }) } }
                                        style={ styles.fullsize }
                                        src={`${ domain }/${ src }/${ kebabCase(alt || missingALt) }.${ ext }${ queryString }`}
                                        alt={ alt || missingALt }
                                    /&gt;

                                    {/* Load LQIP in foreground */}
                                    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
                                        <span class="hljs-attr">onLoad</span>=<span class="hljs-string">{</span> () =&gt;</span> { this.setState({ lqipLoaded: true }) } }
                                        style={ styles.lqip }
                                        src={`${ domain }/${ src }/${ kebabCase(alt || missingALt) }.${ ext }${ lqipQueryString }`} 
                                        alt={ alt || missingALt } 
                                    /&gt;
                                <span class="hljs-tag">&lt;/<span class="hljs-name">React.Fragment</span>&gt;</span>
                            ) : null
                        }            
                    <span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span>
                )}

            <span class="hljs-tag">&lt;/<span class="hljs-name">TueriContext.Consumer</span>&gt;</span></span>
        )

    }
}

Img.propTypes = {
    <span class="hljs-attr">src</span>: PropTypes.string.isRequired,
    <span class="hljs-attr">alt</span>: PropTypes.string.isRequired,
    <span class="hljs-attr">options</span>: PropTypes.object,
    <span class="hljs-attr">ext</span>: PropTypes.string,
    <span class="hljs-attr">buffer</span>: PropTypes.number
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Img
</code></pre>
<h2 id="heading-see-it-in-action">See it in action:</h2>
<p>Try out a live demo on CodeSandbox:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codesandbox.io/embed/qjzqw7w3q?fontsize=14" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodeSandbox embed" allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin" loading="lazy"></iframe></div>
<hr>
<p>_Originally published at <a target="_blank" href="https://tueri.io/blog/2019-03-21-building-the-react-image-optimization-component/?utm_source=Freecodecamp&amp;utm_medium=Post&amp;utm_campaign=">Tueri.io</a>_</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Your complete guide to truly responsive images ]]>
                </title>
                <description>
                    <![CDATA[ By Dane Stevens There is a lot that goes into making a website responsive, and images are a major factor and can make or break your site. With that out of the way, let's dig in: <img src="giraffe.jpg" /> Whoa! That's not quite right, let's fix tha... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/your-complete-guide-to-truly-responsive-images/</link>
                <guid isPermaLink="false">66d84e8d39c4dccc43d4d47e</guid>
                
                    <category>
                        <![CDATA[ Progressive Images ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image optimization  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Image Placeholder ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Responsive Image ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 11 Jun 2019 18:30:57 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/06/giraffe-NOT-responsive-image-medium.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Dane Stevens</p>
<p><img src="https://cdn.tueri.io/274877906986/giraffe-family.jpg" alt="Responsive Images" width="4294" height="2859" loading="lazy"></p>
<p>There is a lot that goes into making a website responsive, and images are a major factor and can make or break your site. With that out of the way, let's dig in:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"giraffe.jpg"</span> /&gt;</span>
</code></pre>
<p><img src="https://cdn.tueri.io/274877906980/giraffe-NOT-responsive-image.jpg?w=700&amp;crop.width=700&amp;h=467&amp;crop.height=467&amp;crop.x=1100&amp;crop.y=700" alt="Non-responsive Girafee" width="700" height="467" loading="lazy"></p>
<p>Whoa! That's not quite right, let's fix that.</p>
<h2 id="heading-percentage-width-images-using-css">Percentage width images using CSS</h2>
<p>By definition, a responsive site has no fixed width. We can account for this by setting our image width using percentages. A percentage width can be set on the image directly using inline CSS or set globally using a CSS style sheet.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Inline CSS --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"giraffe.jpg"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"max-width: 100%;"</span> /&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-comment">/* Global CSS style sheet */</span>
<span class="hljs-selector-tag">img</span> {
    <span class="hljs-attribute">max-width</span>: <span class="hljs-number">100%</span>;
}
</code></pre>
<p>Our image set to 100% maximum width now looks like this. Feel free to resize your browser window and see the image width change automatically.</p>
<p><img src="https://cdn.tueri.io/274877906980/giraffe-NOT-responsive-image.jpg?w=700&amp;h=467" alt="Fully-responsive Giraffe" width="700" height="467" loading="lazy"></p>
<p>Awesome! Our images are now responsive, but let's not get too excited. CSS percentage widths have a major downside: This reading pane has a maximum width of 700 pixels and our image is 3742 pixels wide or 532% larger than what we need. It's also consuming 1.55 MB of bandwidth.</p>
<h3 id="heading-so-the-image-is-huge-whats-the-big-deal">So the image is huge, what's the big deal?</h3>
<p>On a standard ADSL internet connection it is going to take 2 seconds to download that single image.</p>
<p>I'm going to assume you have more than one image on your website. If every image takes 2 seconds to download, your site will be very slow and your search ranking will take a big hit.</p>
<h3 id="heading-how-can-we-fix-this-problem">How can we fix this problem?</h3>
<p>Since we only need an image that is 700 pixels wide, let's pop open Photoshop and resize it.</p>
<p><img src="https://cdn.tueri.io/274877906980/giraffe-NOT-responsive-image.jpg?w=700&amp;h=467" alt="Giraffe Eating" width="700" height="467" loading="lazy"></p>
<p>That's better! Our image is now 700 pixels wide and weighs in at 264 KB with no loss of quality.</p>
<h3 id="heading-what-about-mobile-devices">What about mobile devices?</h3>
<p>Great question! On mobile devices, 700 pixels can be more than double what you need and 264 KB on is still slow on a mobile internet connection.</p>
<p>What if we could display different size images for different size devices?</p>
<p>Now you're thinking!</p>
<h2 id="heading-different-image-sizes-using-the-srcset-attribute">Different image sizes using the srcset attribute</h2>
<p>Let's downsize our original image and save it as three versions of 700 pixels, 480 pixels and 360 pixels. We'll name them as follows:</p>
<ul>
<li>giraffe-small.jpg - 360px @ 101 KB</li>
<li>giraffe-medium.jpg - 480px @ 151 KB</li>
<li>giraffe-large.jpg - 700px @ 264 KB</li>
</ul>
<p><img src="https://cdn.tueri.io/274877906987/giraffe-family.jpg" alt="Small Medium and Large Giraffe" width="933" height="467" loading="lazy"></p>
<p>We'll use the srcset attribute to tell the browser about our different image sizes. This tells the browser that we have three versions of this image in the sizes 360w, 480w and 700w. The "w" in this case is the same as "px".</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
    <span class="hljs-attr">style</span>=<span class="hljs-string">"max-width: 100%;"</span>
    <span class="hljs-attr">srcset</span>=<span class="hljs-string">"giraffe-small.jpg 360w, giraffe-medium.jpg 480w, giraffe-large.jpg 700w"</span>
/&gt;</span>
</code></pre>
<p>Some older browsers will ignore the srcset attribute. We can use the src attribute as a fallback for these browsers.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
    <span class="hljs-attr">style</span>=<span class="hljs-string">"max-width: 100%;"</span>
    <span class="hljs-attr">srcset</span>=<span class="hljs-string">"giraffe-small.jpg 360w, giraffe-medium.jpg 480w, giraffe-large.jpg 700w"</span>
    <span class="hljs-attr">src</span>=<span class="hljs-string">"giraffe-large.jpg"</span>
/&gt;</span>
</code></pre>
<p><img src="https://cdn.tueri.io/274877906980/giraffe-NOT-responsive-image.jpg?w=700&amp;h=467" alt="Giraffe Eating" width="700" height="467" loading="lazy"></p>
<p>Great! Now we are saving bandwidth by delivering different images to different devices.</p>
<p>This goes without saying, but you know what this means right? You'll need to create a minimum of three versions of every image on your site. If you want to support hi-dpi or retina displays, you'll need even more variations. That is an incredible amount of time that none of us have. In addition, if you re-design your site at different breakpoints, you'll need to do this all over again.</p>
<p>At Tueri, we're developers too and recognize that your time is valuable. In the next section I'll show you how we solved this problem for you.</p>
<h2 id="heading-real-time-image-processing-with-tueriiohttpstueriio">Real-time image processing with <a target="_blank" href="https://tueri.io">Tueri.io</a></h2>
<p><a target="_blank" href="https://tueri.io">Tueri.io</a> is a real-time image processing platform. We store, process, and deliver your image perfectly sized to every device.</p>
<h3 id="heading-heres-what-you-do">Here's what you do</h3>
<ol>
<li>Upload your image to <a target="_blank" href="https://tueri.io">Tueri.io</a></li>
<li>Change the image <code>src</code> to <code>tueri-src</code></li>
<li>Include <a target="_blank" href="https://github.com/tueriapp/vanilla-tueri">tueri.js</a> in your code</li>
</ol>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">tueri-src</span>=<span class="hljs-string">"https://cdn.tueri.io/274877906982/giraffe-family.jpg"</span>/&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"tueri.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.tueri.io/274877906982/giraffe-family.jpg" alt="Giraffe Family" width="4562" height="3650" loading="lazy"></p>
<h3 id="heading-its-like-magic">It's like magic!</h3>
<p>Oh, and we also do:</p>
<ul>
<li>Low-quality image placeholders</li>
<li>Image lazy-loading</li>
<li>Image compression</li>
<li>Image conversion</li>
</ul>
<hr>
<p>_Originally published at <a target="_blank" href="https://tueri.io/blog/2019-03-27-your-complete-guide-to-truly-responsive-images/?utm_source=Freecodecamp&amp;utm_medium=Post&amp;utm_campaign=">Tueri.io</a>_</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
