Theme Development Best Practices
Recommended practices for developing O2VEND themes.
Code Organization
File Structure
Organize files logically:
theme/
layout/
theme.liquid
templates/
index.liquid
product.liquid
sections/
header.liquid
footer.liquid
snippets/
product-card.liquid
assets/
theme.css
theme.js
config/
settings_schema.json
Naming Conventions
- Use lowercase with hyphens for file names:
product-card.liquid - Use descriptive names:
hero-banner.liquidnothb.liquid - Group related files:
product-*.liquidfor product-related snippets
Template Best Practices
1. Use Layouts
Always use the layout system:
{% layout 'theme' %}
<!-- Template content -->
2. Error Handling
Always handle missing data:
{% if product %}
{{ product.name }}
{% else %}
<p>Product not found</p>
{% endif %}
3. Escape User Input
Always escape user-generated content:
{{ user_content | escape }}
{{ product.name | escape }}
4. Use Default Values
Provide fallbacks:
{{ product.name | default: 'Untitled Product' }}
{{ settings.color | default: '#000000' }}
Performance Best Practices
1. Minimize Loops
Avoid deep nesting:
{% for collection in collections limit: 5 %}
{% render 'collection-grid', collection: collection %}
{% endfor %}
2. Cache Values
Cache expensive operations:
{% assign product_count = collection.products.size %}
{% assign has_discount = product.compare_at_price > product.price %}
3. Lazy Load Images
<img src="{{ image | img_url: 'small' }}"
data-src="{{ image | img_url: 'large' }}"
loading="lazy">
4. Optimize Assets
- Minify CSS and JavaScript
- Combine files when possible
- Use appropriate image formats
- Compress images
Widget Best Practices
1. Provide Fallbacks
{% if widgets.content.size > 0 %}
{% for widget in widgets.content %}
{{ widget | render_widget }}
{% endfor %}
{% else %}
<!-- Fallback content -->
{% endif %}
2. Validate Settings
{% if widget.settings.show_title %}
<h2>{{ widget.settings.title | default: 'Default Title' }}</h2>
{% endif %}
3. Limit Widget Count
{% assign limited_widgets = widgets.content | limit: 10 %}
Snippet Best Practices
1. Make Snippets Reusable
{% comment %}
Snippet: button
Parameters: text, url, style
{% endcomment %}
<a href="{{ url }}" class="btn btn-{{ style | default: 'primary' }}">
{{ text }}
</a>
2. Document Parameters
Always document snippet parameters in comments.
3. Keep Snippets Focused
Each snippet should do one thing well.
Section Best Practices
1. Use Settings
Make sections configurable:
<section style="background-color: {{ section.settings.bg_color }}">
<h2>{{ section.settings.title }}</h2>
</section>
2. Support Widgets
Allow widgets in sections:
{% for widget in widgets.content %}
{{ widget | render_widget }}
{% endfor %}
Security Best Practices
1. Escape Output
{{ user_input | escape }}
{{ product.name | escape }}
2. Validate Input
{% if product and product.id %}
<!-- Use product -->
{% endif %}
3. Use Secure Asset Loading
{{ 'script.js' | asset_url | script_tag }}
Accessibility Best Practices
1. Semantic HTML
<header>
<nav>
<ul>
<li><a href="/">Home</a></li>
</ul>
</nav>
</header>
2. Alt Text for Images
<img src="{{ image | img_url: 'large' }}"
alt="{{ product.name | escape }}">
3. ARIA Labels
<button aria-label="Add to cart">
Add to Cart
</button>
CSS Variables Best Practices (Updated - January 2025)
Use CSS Variables Instead of Hardcoded Values
Always use CSS custom properties (CSS variables) from the root :root selector instead of hardcoded values:
Avoid:
.widget {
padding: 16px;
border-radius: 8px;
color: #333333;
background: #ffffff;
}
Use:
.widget {
padding: var(--space-4);
border-radius: var(--border-radius-medium);
color: var(--color-text);
background: var(--color-background);
}
Available CSS Variables
Color Variables
--color-primary,--color-secondary,--color-accent--color-background,--color-surface,--color-text--color-border,--color-error,--color-success
Spacing Variables
--space-1,--space-2,--space-4,--space-6,--space-8, etc.--theme-spacing-sm,--theme-spacing-md,--theme-spacing-lg
Typography Variables
--font-primary,--font-display--text-base,--text-sm,--text-lg,--text-xl, etc.--leading-tight,--leading-normal,--leading-relaxed
Border Radius Variables
--border-radius-small,--border-radius-medium,--border-radius-large
Shadow Variables
--shadow-sm,--shadow-md,--shadow-lg,--shadow-xl
Transition Variables
--transition-fast,--transition,--transition-slow--duration-*and--ease-*variables
Benefits of CSS Variables
- Centralized Theming: All values defined in root CSS
- Runtime Customization: Values can be changed via theme configuration
- Consistency: Ensures consistent styling across themes
- Maintainability: Easier to update theme-wide values
Using Theme Settings
Values from settings_data.json are automatically mapped to CSS variables:
:root {
--color-primary: {{ settings.color_primary | default: '#000000' }};
--color-accent: {{ settings.color_accent | default: '#007bff' }};
}
Use these in your CSS:
.button {
background-color: var(--color-primary);
border-color: var(--color-accent);
}
Fallback Values
Always provide fallback values when using CSS variables:
.widget {
/* With fallback */
padding: var(--space-4, 16px);
color: var(--color-text, #333333);
}
Related Topics
- Performance Optimization
- Security Hardening
- Theme Development Guide
- Editor Publishing - Learn about theme validation