Skip to content

Stencil Responsive Images

Here’s a comprehensive list of HTML attributes to ensure are set correctly on each image to prevent blur and white overlay issues:

Essential Attributes:

  • src: Use high-quality image source directly (remove any “lqip” or low-quality parameters)
  • loading="eager": Forces immediate loading without lazy-loading
  • fetchpriority="high": Signals browser to prioritize this image
  • decoding="sync": Forces synchronous image decoding

Style-Related Attributes:

  • class: Remove any classes like "lazyload", "lazyloading", "lqip-blur" that might trigger effects
  • style: Add inline styles: opacity: 1 !important; filter: none !important; -webkit-filter: none !important;

Data Attributes to Add:

  • data-no-blur="true": Custom attribute to signal no blur effects
  • data-no-transition="true": Custom attribute to signal no transitions
  • data-critical="true": Marks image as critical for load prioritization

Data Attributes to Remove or Modify:

  • If using data-src, make sure src matches it exactly
  • If using data-srcset, make sure srcset matches it exactly
  • Remove data-sizes if possible, or ensure it’s set to actual sizes

Responsive Image Attributes:

  • sizes: Set explicitly (e.g., sizes=“(min-width: 800px) 50vw, 100vw”)
  • srcset: Use without any blur or low-quality parameters

Example of Correctly Tagged Image:

<img
class="loaded"
src="image.jpg"
alt="Description of image"
loading="eager"
decoding="sync"
data-critical="true"
data-no-blur="true"
data-no-transition="true"
fetchpriority="high"
style="opacity: 1 !important; filter: none !important; -webkit-filter: none !important; transition: none !important;" />

This approach completely bypasses lazy loading and forces immediate, full-quality image display without any transitions or effects that could cause blur or white overlays.

Should I still include width, height, and sizes?

● Yes, absolutely! Including width, height, and sizes is very important to prevent layout shifts and ensure proper image rendering. Here’s the updated guidance:

Dimensions (Critical for Performance):

  • width: Always include the actual width in pixels
  • height: Always include the actual height in pixels
  • sizes: Specify how image size relates to viewport (e.g., sizes=“(min-width: 800px) 50vw, 100vw”)

Including width and height is especially critical because:

  1. It prevents Cumulative Layout Shift (CLS)
  2. It allows the browser to allocate space before the image loads
  3. It helps with proper aspect ratio calculation

Complete Example with All Attributes:

<img
class="loaded"
src="image.jpg"
alt="Description of image"
width="800"
height="600"
loading="eager"
decoding="sync"
data-critical="true"
data-no-blur="true"
data-no-transition="true"
fetchpriority="high"
sizes="(min-width: 800px) 50vw, 100vw"
style="opacity: 1 !important; filter: none !important; -webkit-filter: none !important; transition: none !important;" />

Including these dimension attributes is one of the most effective ways to improve both performance and visual stability while ensuring images render properly without blur effects.


● Here’s how you should structure the Handlebars responsive-img component to prevent blur and white overlay issues:

{{> components/common/responsive-img
image=post.thumbnail
class="h-auto max-w-full nerden-blogPageImage aspect-w-[957px] aspect-w-957 aspect-h-[539px] aspect-h-539 object-cover object-center w-full rounded-3 shadow-lg
lazyload"
loaded"
width='957'
height='539'
fallback_size='957w'
lazyload='lazyload'
lazyload='false'
loading='eager'
fetchpriority='low'
fetchpriority='high'
decoding='async'
decoding='sync'
sizes='(min-width: 1480px) 1013px, (min-width: 1040px) calc(87.62vw - 293px), calc(100.14vw - 81px)'
named_transformation='blog_page_image'
data-critical='true'
data-no-blur='true'
data-no-transition='true'
}}
```hbs
{{> components/common/responsive-img
image=post.thumbnail
class="h-auto max-w-full nerden-blogPageImage aspect-w-[957px] aspect-w-957 aspect-h-[539px] aspect-h-539 object-cover object-center w-full rounded-3 shadow-lg loaded"
width='957'
height='539'
fallback_size='957w'
lazyload='false'
loading='eager'
fetchpriority='high'
decoding='sync'
sizes='(min-width: 1480px) 1013px, (min-width: 1040px) calc(87.62vw - 293px), calc(100.14vw - 81px)'
named_transformation='blog_page_image'
data-critical='true'
data-no-blur='true'
data-no-transition='true'
}}

Key changes:

  1. Changed class from “lazyload” to “loaded”
  2. Set lazyload=‘false’ instead of ‘lazyload+lqip’
  3. Changed decoding=‘async’ to decoding=‘sync’
  4. Added data-critical=‘true’, data-no-blur=‘true’, and data-no-transition=‘true’

These changes will ensure the image loads immediately without blur effects or transitions while maintaining the proper dimensions, aspect ratio, and responsive behavior.

If your responsive-img component doesn’t accept all these attributes, you might need to modify the component itself in /templates/components/common/responsive-img.html to ensure it passes these attributes to the underlying img element.


● If you want to maintain lazy loading while avoiding blur/white overlay issues, you’ll need a more balanced approach. Here’s how to set up lazy loading correctly:

{{> components/common/responsive-img
image=post.thumbnail
class="h-auto max-w-full nerden-blogPageImage aspect-w-[957px] aspect-w-957 aspect-h-[539px] aspect-h-539 object-cover object-center w-full rounded-3 shadow-lg
lazyload"
width='957'
height='539'
fallback_size='957w'
lazyload='lazyload'
loading='eager'
loading='lazy'
fetchpriority='low'
fetchpriority='auto'
decoding='async'
sizes='(min-width: 1480px) 1013px, (min-width: 1040px) calc(87.62vw - 293px), calc(100.14vw - 81px)'
named_transformation='blog_page_image'
data-no-blur='true'
data-no-transition='true'
}}
```hbs
{{> components/common/responsive-img
image=post.thumbnail
class="h-auto max-w-full nerden-blogPageImage aspect-w-[957px] aspect-w-957 aspect-h-[539px] aspect-h-539 object-cover object-center w-full rounded-3 shadow-lg lazyload"
width='957'
height='539'
fallback_size='957w'
lazyload='lazyload'
loading='lazy'
fetchpriority='auto'
decoding='async'
sizes='(min-width: 1480px) 1013px, (min-width: 1040px) calc(87.62vw - 293px), calc(100.14vw - 81px)'
named_transformation='blog_page_image'
data-no-blur='true'
data-no-transition='true'
}}

Key differences for lazy loading without blur:

  1. Keep lazyload=‘lazyload’ but remove ‘+lqip’ (this avoids the low-quality placeholder)
  2. Keep loading=‘lazy’ to use browser native lazy loading
  3. Remove ‘high’ from fetchpriority
  4. Still include data-no-blur=‘true’ and data-no-transition=‘true’
  5. Keep width, height, and sizes to prevent layout shifts

This approach:

  • Still delays loading until the image approaches the viewport
  • Doesn’t show a blurry placeholder while loading
  • Avoids white overlay issues by disabling transitions/filters
  • Shows nothing until the full-quality image is ready
  • Prevents layout shifts with proper dimensions

For below-the-fold images, this is a good balance between performance and visual quality.