{"id":3972,"date":"2024-09-23T17:17:49","date_gmt":"2024-09-23T22:17:49","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=3972"},"modified":"2024-09-23T17:17:50","modified_gmt":"2024-09-23T22:17:50","slug":"keeping-pixely-images-pixely-and-performant","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/keeping-pixely-images-pixely-and-performant\/","title":{"rendered":"Keeping Pixely Images Pixely (and Performant!)"},"content":{"rendered":"\n<p><a href=\"https:\/\/frontendmasters.com\/blog\/gradient-text-with-a-drop-shadow\/\">After Marc chimed in<\/a> with technique he needed to pull off as part of this years big promotion last week, it reminded me of another thing that ended up being relevant to the design aesthetic at play. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"841\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-23-at-2.31.56%E2%80%AFPM.png?resize=1024%2C841&#038;ssl=1\" alt=\"\" class=\"wp-image-3974\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-23-at-2.31.56%E2%80%AFPM.png?resize=1024%2C841&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-23-at-2.31.56%E2%80%AFPM.png?resize=300%2C246&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-23-at-2.31.56%E2%80%AFPM.png?resize=768%2C631&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-23-at-2.31.56%E2%80%AFPM.png?resize=1536%2C1261&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/Screenshot-2024-09-23-at-2.31.56%E2%80%AFPM.png?w=1985&amp;ssl=1 1985w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><figcaption class=\"wp-element-caption\">A horizontal slice of that background image was used here on this blog and the image size was quite tolerably small thanks to this CSS property.<\/figcaption><\/figure>\n\n\n\n<p>See how everything has that 8-bit-ish pixely look to it? There is a CSS property that you can apply to images (<code>&lt;img><\/code> elements) that will affect how they look when they scale. Like if you&#8217;ve got an image like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"512\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/landscape.png?resize=1024%2C512&#038;ssl=1\" alt=\"\" class=\"wp-image-3975\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/landscape.png?resize=1024%2C512&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/landscape.png?resize=300%2C150&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/landscape.png?resize=768%2C384&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/landscape.png?resize=1536%2C768&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/landscape.png?resize=2048%2C1024&amp;ssl=1 2048w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/landscape.png?w=3000&amp;ssl=1 3000w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>You&#8217;re probably going to want to do this no matter what:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.castle-landscape-image<\/span> {\n  <span class=\"hljs-attribute\">image-rendering<\/span>: pixelated;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>If there is any resizing at all any direction, it&#8217;s just going to look better. There is also <code>image-rendering: crisp-edges;<\/code> which is apparently specifically for pixel art, but I don&#8217;t see much of a difference. <\/p>\n\n\n\n<p>Another cool thing we can do here is ensure the original art is as small as it can reasonably be (probably whatever size it was <em>originally created at) <\/em>and served like that, so any scaling beyond that doesn&#8217;t cause any anti-aliasing stuff (blurred edges) <em>at all.<\/em> In the case of the example above where I didn&#8217;t really have the original just a high-res version, I can scale it down and down trying to find the best place where it still looks fine but I&#8217;m saving lots of image space:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_jOgOYOL\" src=\"\/\/codepen.io\/anon\/embed\/jOgOYOL?height=1000&amp;theme-id=47434&amp;slug-hash=jOgOYOL&amp;default-tab=result\" height=\"1000\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed jOgOYOL\" title=\"CodePen Embed jOgOYOL\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Another use-case here is something like a QR code. This QR code is 393 <em>bytes<\/em> (super small!). I&#8217;ll render it huge here and see how perfect it looks:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_dyxydMv\" src=\"\/\/codepen.io\/anon\/embed\/dyxydMv?height=650&amp;theme-id=47434&amp;slug-hash=dyxydMv&amp;default-tab=result\" height=\"650\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed dyxydMv\" title=\"CodePen Embed dyxydMv\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>I have an SVG version of this same QR code that is 33 KB. This is a (very rare) case where a simple vector-looking graphic is actually better served from a binary image that the natively vector SVG.<\/p>\n\n\n\n<p>Even a bit more extreme, here&#8217;s a 78 byte GIF (I hand-pixeled drew in Photoshop, and exported without metadata to get that small). It can scale up huge. Here&#8217;s the tiny natural one on top and the big one below:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_NWQWyrO\" src=\"\/\/codepen.io\/anon\/embed\/NWQWyrO?height=450&amp;theme-id=47434&amp;slug-hash=NWQWyrO&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed NWQWyrO\" title=\"CodePen Embed NWQWyrO\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Note that if you try the <code>crisp-edges<\/code> value on the above, it seems to bail out, so I guess there must be some kind of difference between the values.<\/p>\n\n\n\n<p>Point of the story: if you&#8217;ve got a pixely <code>&lt;img><\/code>, chuck <code>image-rendering: pixelated;<\/code> and go as small as you can to save on size. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>With CSS&#8217; `image-rendering: pixelated;` we can keep HTML images that have pixelated look anyway quite sharp looking, and possibly more performant to boot.<\/p>\n","protected":false},"author":1,"featured_media":3975,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[7,24,133],"class_list":["post-3972","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-css","tag-design","tag-images"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/landscape.png?fit=4000%2C2000&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/3972","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=3972"}],"version-history":[{"count":3,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/3972\/revisions"}],"predecessor-version":[{"id":3977,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/3972\/revisions\/3977"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/3975"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=3972"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=3972"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=3972"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}