Assets
Assets are static files like CSS, JavaScript, images, and fonts used in your theme. This guide covers asset management, optimization, and best practices.
Asset Overview
Assets are stored in the assets/ directory:
assets/
theme.css # Main theme styles
theme.js # Main theme JavaScript
components.css # Component styles
custom.js # Custom JavaScript
logo.png # Images
fonts/
custom-font.woff2 # Font files
Asset Types
CSS Files
Stylesheets for your theme:
/* assets/theme.css */
:root {
--primary-color: #000000;
--secondary-color: #ffffff;
}
body {
font-family: 'Arial', sans-serif;
color: var(--primary-color);
}
JavaScript Files
Client-side functionality:
// assets/theme.js
document.addEventListener('DOMContentLoaded', function() {
// Theme initialization
initCart();
initSearch();
});
Images
Images used in the theme:
- Logos
- Icons
- Background images
- Product placeholders
Fonts
Custom fonts:
assets/fonts/
custom-font.woff2
custom-font.woff
Loading Assets
CSS Assets
Load stylesheets in the layout:
{{ 'theme.css' | asset_url | stylesheet_tag }}
{{ 'components.css' | asset_url | stylesheet_tag }}
JavaScript Assets
Load scripts before closing </body>:
{{ 'theme.js' | asset_url | script_tag }}
{{ 'custom.js' | asset_url | script_tag }}
Image Assets
Reference images using asset_url:
<img src="{{ 'logo.png' | asset_url }}" alt="{{ shop.name }}">
Or use the img_url filter for product/collection images:
<img src="{{ product.image | img_url: 'large' }}" alt="{{ product.name }}">
Asset URL Filter
The asset_url filter generates URLs for assets:
{{ 'theme.css' | asset_url }}
<!-- Output: /assets/theme.css?v=1234567890 -->
The version parameter (?v=...) ensures browsers load the latest version after updates.
Asset Optimization
CSS Optimization
- Minify CSS: Remove whitespace and comments
- Combine Files: Merge multiple CSS files when possible
- Remove Unused Styles: Clean up unused CSS
- Use CSS Variables: For maintainability
/* Use CSS variables */
:root {
--spacing-small: 0.5rem;
--spacing-medium: 1rem;
--spacing-large: 2rem;
}
.container {
padding: var(--spacing-medium);
}
JavaScript Optimization
- Minify JavaScript: Compress code
- Defer Loading: Load non-critical scripts asynchronously
- Code Splitting: Split large files
- Remove Unused Code: Tree-shake unused functions
{{ 'theme.js' | asset_url | script_tag }}
<!-- Add defer for non-critical scripts -->
<script src="{{ 'analytics.js' | asset_url }}" defer></script>
Image Optimization
-
Use Appropriate Formats:
- WebP for photos
- SVG for icons/logos
- PNG for transparency
- JPEG for photos (fallback)
-
Responsive Images: Use different sizes for different screens
<picture>
<source srcset="{{ product.image | img_url: 'large' }}" media="(min-width: 768px)">
<source srcset="{{ product.image | img_url: 'medium' }}" media="(min-width: 480px)">
<img src="{{ product.image | img_url: 'small' }}" alt="{{ product.name }}">
</picture>
- Lazy Loading: Load images as needed
<img
src="{{ product.image | img_url: 'medium' }}"
alt="{{ product.name }}"
loading="lazy"
>
Asset Organization
Organize assets logically:
assets/
css/
theme.css
components.css
utilities.css
js/
theme.js
cart.js
product.js
images/
logo.png
icons/
cart.svg
search.svg
fonts/
primary-font.woff2
secondary-font.woff2
Asset Versioning
Assets are automatically versioned to prevent caching issues:
{{ 'theme.css' | asset_url }}
<!-- /assets/theme.css?v=1234567890 -->
The version changes when the file is updated, forcing browsers to load the new version.
Conditional Asset Loading
Load assets conditionally:
{% if template.name == 'product' %}
{{ 'product.js' | asset_url | script_tag }}
{% endif %}
{% if settings.enable_custom_fonts %}
{{ 'custom-fonts.css' | asset_url | stylesheet_tag }}
{% endif %}
External Assets
Link to external assets when needed:
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap">
<script src="https://cdn.example.com/library.js"></script>
Asset Preloading
Preload critical assets:
<link rel="preload" href="{{ 'theme.css' | asset_url }}" as="style">
<link rel="preload" href="{{ 'theme.js' | asset_url }}" as="script">
Font Management
Loading Custom Fonts
- Add font files to
assets/fonts/:
assets/fonts/
custom-font.woff2
custom-font.woff
- Define font-face in CSS:
@font-face {
font-family: 'Custom Font';
src: url('{{ "fonts/custom-font.woff2" | asset_url }}') format('woff2'),
url('{{ "fonts/custom-font.woff" | asset_url }}') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}
- Use the font:
body {
font-family: 'Custom Font', sans-serif;
}
JavaScript Best Practices
DOM Ready
Always wait for DOM to be ready:
document.addEventListener('DOMContentLoaded', function() {
// Your code here
});
Event Delegation
Use event delegation for dynamic content:
document.addEventListener('click', function(e) {
if (e.target.matches('.add-to-cart')) {
// Handle add to cart
}
});
Module Pattern
Organize JavaScript in modules:
// assets/cart.js
const Cart = {
init: function() {
this.bindEvents();
},
bindEvents: function() {
// Event handlers
},
update: function() {
// Update cart
}
};
Cart.init();
CSS Best Practices
Use BEM Methodology
.product-card { }
.product-card__image { }
.product-card__title { }
.product-card__price { }
.product-card--featured { }
Mobile-First Approach
/* Mobile styles (default) */
.container {
padding: 1rem;
}
/* Tablet and up */
@media (min-width: 768px) {
.container {
padding: 2rem;
}
}
/* Desktop */
@media (min-width: 1024px) {
.container {
padding: 3rem;
}
}
CSS Variables
Use CSS variables for theming:
:root {
--primary-color: #000000;
--secondary-color: #ffffff;
--font-size-base: 16px;
--spacing-unit: 8px;
}
.button {
background-color: var(--primary-color);
color: var(--secondary-color);
font-size: var(--font-size-base);
padding: calc(var(--spacing-unit) * 2);
}
Asset Management in Editor
Assets can be managed through the O2VEND Theme Editor:
- Browse assets in file explorer
- Edit CSS/JS files directly
- Upload new images
- Delete unused assets
Asset Optimization Guide
CSS Optimization
- Minify CSS:
/* Before: 2KB */
.button { background-color: #000; color: #fff; padding: 10px; }
/* After minified: 1KB */
.button{background:#000;color:#fff;padding:10px}
-
Remove Unused CSS: Use tools like PurgeCSS to remove unused styles
-
Combine CSS Files:
<!-- Instead of multiple files -->
{{ 'theme.css' | asset_url | stylesheet_tag }}
{{ 'components.css' | asset_url | stylesheet_tag }}
{{ 'utilities.css' | asset_url | stylesheet_tag }}
<!-- Combine into one -->
{{ 'theme.min.css' | asset_url | stylesheet_tag }}
JavaScript Optimization
- Minify JavaScript:
// Before
function addToCart(productId) {
console.log('Adding product to cart:', productId);
// ... code
}
// After minified
function addToCart(a){console.log('Adding product to cart:',a);...}
- Code Splitting:
// Load critical JS immediately
{{ 'theme.js' | asset_url | script_tag }}
// Load non-critical JS asynchronously
<script defer src="{{ 'analytics.js' | asset_url }}"></script>
- Remove Console Logs in Production:
// Development
console.log('Debug info');
// Production - remove or use conditional
if (process.env.NODE_ENV === 'development') {
console.log('Debug info');
}
Image Optimization
- Use Appropriate Formats:
- WebP: Modern browsers, best compression
- JPEG: Photos, complex images
- PNG: Graphics with transparency
- SVG: Icons, simple graphics
- Responsive Images:
<picture>
<source media="(min-width: 1200px)"
srcset="{{ image | img_url: '1920x' }}.webp"
type="image/webp">
<source media="(min-width: 1200px)"
srcset="{{ image | img_url: '1920x' }}.jpg">
<source media="(min-width: 768px)"
srcset="{{ image | img_url: '1200x' }}.webp"
type="image/webp">
<img src="{{ image | img_url: '768x' }}"
alt="{{ product.name }}"
loading="lazy">
</picture>
- Image Compression:
- Use tools like ImageOptim, TinyPNG
- Target: 70-80% quality for JPEG
- Use lossless compression for PNG
Asset Loading Strategies
Critical CSS Inline
<head>
<style>
/* Critical CSS inline */
body { margin: 0; font-family: system-ui; }
.header { position: fixed; top: 0; }
</style>
{{ 'theme.css' | asset_url | stylesheet_tag }}
</head>
Preload Critical Assets
<head>
<link rel="preload" href="{{ 'theme.css' | asset_url }}" as="style">
<link rel="preload" href="{{ 'logo.png' | asset_url }}" as="image">
<link rel="preload" href="{{ 'theme.js' | asset_url }}" as="script">
</head>
Defer Non-Critical JavaScript
<body>
<!-- Page content -->
<!-- Defer non-critical scripts -->
<script defer src="{{ 'analytics.js' | asset_url }}"></script>
<script defer src="{{ 'chat-widget.js' | asset_url }}"></script>
</body>
Lazy Load Images
<img src="{{ image | img_url: 'small' }}"
data-src="{{ image | img_url: 'large' }}"
loading="lazy"
alt="{{ product.name }}"
class="lazy-image">
Asset Versioning Examples
Query String Versioning
{{ 'theme.css?v=1.0.0' | asset_url | stylesheet_tag }}
{{ 'theme.js?v=1.0.0' | asset_url | script_tag }}
Filename Versioning
{{ 'theme-1.0.0.css' | asset_url | stylesheet_tag }}
{{ 'theme-1.0.0.js' | asset_url | script_tag }}
Hash-Based Versioning
{% assign css_hash = 'theme.css' | asset_url | split: '/' | last | split: '?' | first | md5 %}
{{ 'theme.css' | asset_url | append: '?v=' | append: css_hash | stylesheet_tag }}
Theme Settings Versioning
{% assign theme_version = settings.theme_version | default: '1.0.0' %}
{{ 'theme.css' | asset_url | append: '?v=' | append: theme_version | stylesheet_tag }}
CDN Integration Guide
Using CDN for Assets
{% assign cdn_url = 'https://cdn.example.com/themes' %}
{% assign theme_name = tenant.theme %}
<link rel="stylesheet"
href="{{ cdn_url }}/{{ theme_name }}/theme.css">
<script src="{{ cdn_url }}/{{ theme_name }}/theme.js"></script>
Fallback to Local Assets
<script>
// Try CDN first, fallback to local
const cdnUrl = 'https://cdn.example.com';
const localUrl = '{{ 'theme.js' | asset_url }}';
const script = document.createElement('script');
script.src = cdnUrl + '/theme.js';
script.onerror = function() {
// Fallback to local
script.src = localUrl;
};
document.head.appendChild(script);
</script>
CDN with Cache Busting
{% assign cache_buster = 'now' | date: '%s' %}
<link rel="stylesheet"
href="{{ cdn_url }}/theme.css?v={{ cache_buster }}">
Asset Performance Metrics
Target Metrics
- First Contentful Paint (FCP): < 1.8s
- Largest Contentful Paint (LCP): < 2.5s
- Time to Interactive (TTI): < 3.8s
- Total Blocking Time (TBT): < 200ms
- Cumulative Layout Shift (CLS): < 0.1
Measuring Asset Performance
// Measure asset load time
performance.getEntriesByType('resource').forEach(entry => {
if (entry.name.includes('theme.css') || entry.name.includes('theme.js')) {
console.log(`${entry.name}: ${entry.duration}ms`);
}
});
Asset Size Targets
- CSS: < 50KB (gzipped)
- JavaScript: < 100KB (gzipped)
- Images:
- Hero images: < 200KB
- Product images: < 100KB
- Icons: < 10KB
- Fonts: < 50KB per font file
Performance Tips
- Minify Assets: Compress CSS and JavaScript
- Combine Files: Reduce HTTP requests
- Optimize Images: Compress and use appropriate formats
- Lazy Load: Load non-critical assets asynchronously
- Cache Assets: Use proper cache headers
- CDN: Use CDN for static assets if available
- Preload Critical Assets: Use
<link rel="preload"> - Inline Critical CSS: Reduce render-blocking
- Defer JavaScript: Load scripts after page render
- Use Modern Formats: WebP for images, ES6+ for JS
Asset Checklist
- All CSS files minified
- JavaScript files optimized
- Images compressed and optimized
- Fonts properly loaded
- Assets organized logically
- Unused assets removed
- Asset URLs use
asset_urlfilter - Critical assets preloaded
- Non-critical assets lazy-loaded
- CDN configured (if applicable)
- Asset versioning implemented
- Performance metrics within targets
Next Steps
- Liquid Templates - Learn template structure
- Snippets - Create reusable components
- Sections - Build page sections
- Performance Optimization - Advanced performance tips