Assets & CDN Filters
Nimbu provides powerful CDN integration for assets, with automatic image processing, optimization, and responsive image generation.
Asset URLs
asset_url
Generate URL for theme assets:
liquid
{{ 'style.css' | asset_url }}
<!-- Output: /assets/themes/theme-slug/style.css -->
<link rel="stylesheet" href="{{ 'main.css' | asset_url }}">
<script src="{{ 'app.js' | asset_url }}"></script>theme_image_url
Get theme image URL:
liquid
{{ 'logo.png' | theme_image_url }}
<img src="{{ 'banner.jpg' | theme_image_url }}" alt="Banner">global_asset_url
Access global site assets:
liquid
{{ 'shared-logo.png' | global_asset_url }}
<img src="{{ 'favicon.ico' | global_asset_url }}">Image Processing with CDN
filter
Apply comprehensive image transformations:
liquid
{{ image.url | filter, width: '800px', height: '600px' }}
{{ product.image.url | filter, width: '400px', cropping: 'fill' }}
{{ photo.url | filter, width: '1200px', height: '800px', gravity: 'face', quality: 85 }}Parameters:
| Parameter | Description | Values |
|---|---|---|
width | Target width | '300px', '1200px' |
height | Target height | '400px', '800px' |
cropping | Crop mode | 'fill', 'fit', 'limit', 'pad', 'scale' |
gravity | Crop focus | 'center', 'face', 'north', 'south', 'east', 'west' |
effect | Visual effect | 'grayscale', 'sepia', 'blur', 'sharpen' |
quality | JPEG quality | 1-100 (default: 80) |
format | Output format | 'jpg', 'png', 'webp', 'avif' |
alpha | Transparency | 0-100 |
Cropping Modes:
fill- Resize and crop to exact dimensionsfit- Fit within dimensions, maintain aspect ratiolimit- Only downscale, never upscalepad- Fit and add padding to match dimensionsscale- Resize to dimensions, ignore aspect ratio
Gravity Options:
center- Center of imageface- Detected facesnorth,south,east,west- Directionalnorth_east,north_west,south_east,south_west- Corners
grayscale
Convert image to grayscale:
liquid
{{ image.url | grayscale }}
<img src="{{ product.image.url | grayscale }}" alt="B&W {{ product.name }}">Image Tag Helpers
image_tag
Generate complete image tag:
liquid
{{ 'logo.png' | theme_image_url | image_tag }}
<!-- Output: <img src="/assets/.../logo.png" alt="Logo"> -->
{{ image.url | image_tag, alt: product.name, class: 'product-image' }}
{{ photo | image_tag, alt: "Team photo", width: 800, height: 600 }}With Lazy Loading:
liquid
{{ image.url | image_tag, loading: 'lazy', class: 'lazy-image' }}Responsive Images
Srcset Generation
Create responsive image sets:
liquid
{% assign image_400 = product.image.url | filter, width: '400px' %}
{% assign image_800 = product.image.url | filter, width: '800px' %}
{% assign image_1200 = product.image.url | filter, width: '1200px' %}
<img
src="{{ image_800 }}"
srcset="{{ image_400 }} 400w,
{{ image_800 }} 800w,
{{ image_1200 }} 1200w"
sizes="(max-width: 600px) 400px,
(max-width: 1200px) 800px,
1200px"
alt="{{ product.name }}"
loading="lazy">Picture Element
Art direction with different crops:
liquid
<picture>
<source
media="(max-width: 600px)"
srcset="{{ image.url | filter, width: '600px', height: '400px', cropping: 'fill', gravity: 'face' }}">
<source
media="(max-width: 1200px)"
srcset="{{ image.url | filter, width: '1200px', height: '600px', cropping: 'fill' }}">
<img
src="{{ image.url | filter, width: '1920px', height: '800px', cropping: 'fill' }}"
alt="{{ image.title }}">
</picture>Stylesheet and Script Tags
stylesheet_tag
Generate stylesheet link:
liquid
{{ 'theme.css' | asset_url | stylesheet_tag }}
<!-- Output: <link href="/assets/.../theme.css" rel="stylesheet"> -->
{{ 'custom.css' | asset_url | stylesheet_tag, media: 'print' }}script_tag
Generate script tag:
liquid
{{ 'app.js' | asset_url | script_tag }}
<!-- Output: <script src="/assets/.../app.js"></script> -->
{{ 'analytics.js' | asset_url | script_tag, defer: true }}
{{ 'polyfill.js' | asset_url | script_tag, async: true }}Practical Examples
Product Images with Variants
liquid
<div class="product-gallery">
<!-- Main image -->
<div class="main-image">
{% if product.images.first %}
{% assign main_image = product.images.first.url %}
<img
src="{{ main_image | filter, width: '800px', height: '800px', cropping: 'fill' }}"
srcset="{{ main_image | filter, width: '400px', height: '400px', cropping: 'fill' }} 400w,
{{ main_image | filter, width: '800px', height: '800px', cropping: 'fill' }} 800w,
{{ main_image | filter, width: '1200px', height: '1200px', cropping: 'fill' }} 1200w"
sizes="(max-width: 768px) 400px, 800px"
alt="{{ product.name }}"
loading="eager">
{% endif %}
</div>
<!-- Thumbnails -->
<div class="thumbnails">
{% for image in product.images %}
<button class="thumbnail" data-index="{{ forloop.index0 }}">
<img
src="{{ image.url | filter, width: '100px', height: '100px', cropping: 'fill' }}"
alt="{{ product.name }} - Image {{ forloop.index }}"
loading="lazy">
</button>
{% endfor %}
</div>
</div>Hero Banner with Optimizations
liquid
<section class="hero">
{% if page.hero_image %}
<picture>
<!-- Mobile: Portrait crop -->
<source
media="(max-width: 768px)"
srcset="{{ page.hero_image.url | filter, width: '768px', height: '1024px', cropping: 'fill', gravity: 'center', format: 'webp' }} 768w"
type="image/webp">
<!-- Tablet: Landscape -->
<source
media="(max-width: 1200px)"
srcset="{{ page.hero_image.url | filter, width: '1200px', height: '600px', cropping: 'fill', format: 'webp' }} 1200w"
type="image/webp">
<!-- Desktop: Full width -->
<source
srcset="{{ page.hero_image.url | filter, width: '1920px', height: '800px', cropping: 'fill', format: 'webp', quality: 85 }} 1920w"
type="image/webp">
<!-- Fallback JPG -->
<img
src="{{ page.hero_image.url | filter, width: '1920px', height: '800px', cropping: 'fill', quality: 85 }}"
alt="{{ page.hero_title }}"
loading="eager">
</picture>
{% endif %}
<div class="hero-content">
<h1>{{ page.hero_title }}</h1>
<p>{{ page.hero_subtitle }}</p>
</div>
</section>Team Member Cards
liquid
<div class="team-grid">
{% for member in channels.team.all %}
<div class="team-card">
{% if member.photo %}
<div class="photo">
<img
src="{{ member.photo.url | filter, width: '300px', height: '300px', cropping: 'fill', gravity: 'face' }}"
alt="{{ member.name }}"
loading="lazy">
</div>
{% else %}
<div class="photo placeholder">
<img src="{{ 'team-placeholder.png' | theme_image_url }}" alt="{{ member.name }}">
</div>
{% endif %}
<h3>{{ member.name }}</h3>
<p class="role">{{ member.role }}</p>
</div>
{% endfor %}
</div>Background Images
liquid
<section
class="cta-section"
style="background-image: url('{{ page.background.url | filter, width: '1920px', quality: 75, effect: 'blur' }}')">
<div class="cta-content">
<h2>{{ page.cta_title }}</h2>
<a href="{{ page.cta_link }}" class="btn">{{ page.cta_text }}</a>
</div>
</section>Asset Preloading
liquid
<head>
<!-- Preload critical images -->
<link
rel="preload"
as="image"
href="{{ page.hero_image.url | filter, width: '1920px', format: 'webp' }}"
type="image/webp">
<!-- Preload fonts -->
<link
rel="preload"
as="font"
href="{{ 'Inter-Regular.woff2' | asset_url }}"
type="font/woff2"
crossorigin>
<!-- Stylesheets -->
{{ 'theme.css' | asset_url | stylesheet_tag }}
<!-- Critical JS -->
{{ 'critical.js' | asset_url | script_tag }}
</head>Image Gallery with Lightbox
liquid
<div class="image-gallery">
{% for image in page.gallery %}
<a
href="{{ image.url | filter, width: '1920px', quality: 90 }}"
class="gallery-item"
data-lightbox="gallery">
<img
src="{{ image.url | filter, width: '400px', height: '300px', cropping: 'fill' }}"
alt="{{ image.title }}"
loading="lazy">
</a>
{% endfor %}
</div>Performance Best Practices
1. Use Appropriate Image Formats
liquid
<!-- ✅ Good: Modern formats with fallback -->
<picture>
<source srcset="{{ image.url | filter, width: '800px', format: 'webp' }}" type="image/webp">
<source srcset="{{ image.url | filter, width: '800px', format: 'jpg' }}" type="image/jpeg">
<img src="{{ image.url | filter, width: '800px' }}" alt="...">
</picture>
<!-- ⚠️ Acceptable for simple cases -->
<img src="{{ image.url | filter, width: '800px' }}" alt="...">2. Optimize Quality Settings
liquid
<!-- ✅ Good: Optimized quality -->
{{ image.url | filter, width: '1200px', quality: 80 }}
<!-- ❌ Bad: Unnecessarily high quality -->
{{ image.url | filter, width: '1200px', quality: 100 }}3. Lazy Load Below the Fold
liquid
<!-- Above the fold: Eager loading -->
<img src="{{ hero.url | filter, width: '1920px' }}" loading="eager" alt="Hero">
<!-- Below the fold: Lazy loading -->
<img src="{{ image.url | filter, width: '800px' }}" loading="lazy" alt="...">4. Use Face Detection for People Photos
liquid
<!-- ✅ Good: Face-aware cropping -->
{{ member.photo.url | filter, width: '300px', height: '300px', cropping: 'fill', gravity: 'face' }}
<!-- ❌ Bad: Might crop out faces -->
{{ member.photo.url | filter, width: '300px', height: '300px', cropping: 'fill' }}Next Steps
- Commerce - Shopping cart and product helpers
- Special Purpose - QR codes, analytics, utilities
- Pages - Working with page images
- Performance - Optimization strategies
Optimize and deliver assets effectively with Nimbu's CDN filters!