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-loadingfetchpriority="high"
: Signals browser to prioritize this imagedecoding="sync"
: Forces synchronous image decoding
Style-Related Attributes:
class
: Remove any classes like"lazyload"
,"lazyloading"
,"lqip-blur"
that might trigger effectsstyle
: 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 effectsdata-no-transition="true"
: Custom attribute to signal no transitionsdata-critical="true"
: Marks image as critical for load prioritization
Data Attributes to Remove or Modify:
- If using
data-src
, make suresrc
matches it exactly - If using
data-srcset
, make suresrcset
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:
- It prevents Cumulative Layout Shift (CLS)
- It allows the browser to allocate space before the image loads
- 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:
- Changed class from “lazyload” to “loaded”
- Set lazyload=‘false’ instead of ‘lazyload+lqip’
- Changed decoding=‘async’ to decoding=‘sync’
- 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:
- Keep lazyload=‘lazyload’ but remove ‘+lqip’ (this avoids the low-quality placeholder)
- Keep loading=‘lazy’ to use browser native lazy loading
- Remove ‘high’ from fetchpriority
- Still include data-no-blur=‘true’ and data-no-transition=‘true’
- 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.