product-comparison
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseProduct Comparison
产品对比
Overview
概述
Build a side-by-side product comparison feature where shoppers select 2–4 products and see their attributes in a sticky-header table. Attribute rows that are identical across all selected products can be hidden to reduce noise. The comparison state is stored in the URL so it can be shared or bookmarked.
构建一款并排产品对比功能,购物者可选择2–4款产品,在固定表头的表格中查看它们的属性。所有选中产品属性相同的行可被隐藏,以减少冗余信息。对比状态会存储在URL中,方便分享或添加书签。
When to Use This Skill
何时使用此功能
- When selling products with many technical specifications (electronics, appliances, cameras)
- When conversion research shows shoppers are considering multiple products before purchasing
- When the product catalog has well-structured attribute data that lends itself to comparison
- When building a B2B store where buyers need to justify purchase decisions to stakeholders
- When implementing a "Compare" checkbox on product listing pages
- 销售带有大量技术规格的产品时(电子产品、家电、相机等)
- 转化研究显示购物者在购买前会考虑多款产品时
- 产品目录拥有结构清晰、适合对比的属性数据时
- 搭建B2B店铺,采购者需要向利益相关者证明购买决策合理性时
- 在产品列表页实现「对比」复选框时
Core Instructions
核心操作步骤
Step 1: Determine the merchant's platform and choose the right approach
步骤1:确定商家平台并选择合适方案
| Platform | Recommended Approach | Why |
|---|---|---|
| Shopify | Install Comparify or Product Compare app (both free tiers available) | Shopify doesn't have built-in comparison; these apps add Compare buttons to product cards, a floating comparison tray, and a full comparison table page; they pull product metafields for spec data |
| WooCommerce | Install YITH WooCommerce Compare (free) or WooCommerce Products Compare | YITH Compare is the most popular free option — adds Compare checkboxes to product cards, a comparison table page using WooCommerce product attributes, and a "show differences only" toggle |
| BigCommerce | Enable the built-in Compare feature in Storefront → My Themes → Customize (Cornerstone theme) | BigCommerce and Cornerstone include native product comparison — enable it in the Theme Editor; it uses product custom fields as comparison attributes |
| Custom / Headless | Build a URL-state comparison tray + comparison table page with your product attribute data | Full control over attribute display, difference highlighting, and table layout; see implementation below |
| 平台 | 推荐方案 | 原因 |
|---|---|---|
| Shopify | 安装Comparify或Product Compare应用(均提供免费版) | Shopify无内置对比功能;这些应用会在产品卡片上添加对比按钮、悬浮对比托盘和完整的对比表格页面;它们会提取产品元字段作为规格数据 |
| WooCommerce | 安装YITH WooCommerce Compare(免费)或WooCommerce Products Compare | YITH Compare是最受欢迎的免费选项——会在产品卡片上添加对比复选框,利用WooCommerce产品属性生成对比表格页面,并提供「仅显示差异」开关 |
| BigCommerce | 在Storefront → My Themes → Customize(Cornerstone主题)中启用内置的Compare功能 | BigCommerce和Cornerstone包含原生产品对比功能——在主题编辑器中启用即可;它使用产品自定义字段作为对比属性 |
| 自定义/无头电商 | 利用产品属性数据构建基于URL状态的对比托盘 + 对比表格页面 | 可完全控制属性展示、差异高亮和表格布局;实现方式见下文 |
Step 2: Enable and configure comparison on your platform
步骤2:在平台上启用并配置对比功能
Shopify
Shopify
Using Comparify app:
- Install Comparify – Product Comparison from the Shopify App Store (free tier available)
- In the app settings, select which product metafields to display as comparison rows (e.g., material, weight, dimensions, warranty)
- If you haven't set up metafields yet: go to Settings → Custom data → Products and create metafields for your specs
- The app automatically adds a "Compare" checkbox to product cards in your collection pages
- Shoppers select up to 4 products, click "Compare" in the floating tray, and land on a full comparison table
- Configure which attributes appear as rows and in what order in the app's Table Settings
Preparing your product data:
- Add spec data as product metafields (recommended) or in the product description with consistent formatting
- For variant specs, add them as variant metafields (e.g., weight per size)
使用Comparify应用:
- 从Shopify应用商店安装Comparify – Product Comparison(提供免费版)
- 在应用设置中,选择要作为对比行展示的产品元字段(例如材质、重量、尺寸、保修)
- 若尚未设置元字段:前往Settings → Custom data → Products,为产品规格创建元字段
- 应用会自动在商品集合页的产品卡片上添加「对比」复选框
- 购物者最多选择4款产品,点击悬浮托盘中的「对比」按钮,即可进入完整对比表格页面
- 在应用的Table Settings中配置显示的属性行及其顺序
准备产品数据:
- 将规格数据添加为产品元字段(推荐),或在产品描述中使用统一格式填写
- 对于变体规格,添加为变体元字段(例如不同尺寸对应的重量)
WooCommerce
WooCommerce
Using YITH WooCommerce Compare (free):
- Install and activate from WordPress.org
- Go to YITH → Compare → Settings
- Under Fields to compare, select which WooCommerce product attributes and custom fields to show as rows (e.g., Color, Material, Dimensions, Weight)
- Set Maximum products to 4
- Enable Highlight differences to visually call out rows where products differ
- The plugin adds a "Compare" button to product cards on your shop page and archives
- A floating comparison bar appears at the bottom of the page as shoppers add products
Preparing your product data:
- Add comparison attributes via Products → Attributes — create attributes like "Material", "Warranty", "Compatible with" and assign values to each product
- Products must use the same attribute names for comparison rows to align correctly
使用YITH WooCommerce Compare(免费版):
- 从WordPress.org安装并激活插件
- 前往YITH → Compare → Settings
- 在Fields to compare中,选择要作为对比行展示的WooCommerce产品属性和自定义字段(例如颜色、材质、尺寸、重量)
- 将Maximum products设置为4
- 启用Highlight differences,以视觉方式突出显示产品存在差异的行
- 插件会在商店页面和归档页的产品卡片上添加「对比」按钮
- 当购物者添加产品时,页面底部会显示悬浮对比栏
准备产品数据:
- 通过Products → Attributes添加对比属性——创建「材质」「保修」「兼容设备」等属性,并为每个产品分配对应值
- 产品必须使用相同的属性名称,才能确保对比行正确对齐
BigCommerce
BigCommerce
Built-in comparison (Cornerstone theme):
- Go to Storefront → My Themes → Customize
- Navigate to Global → Product Compare (or Category Page → Product Compare depending on your theme version)
- Toggle Enable product comparison to On
- Set the Maximum products (default is 4)
- Configure which Product Custom Fields appear as comparison rows in Products → Product Custom Fields settings
- Shoppers see a "Compare" checkbox on product cards; the floating compare tray appears automatically
Adding spec data:
- Go to Products → [product] → Custom Fields and add name/value pairs (e.g., "Screen Size: 15.6 inches", "Battery Life: 10 hours")
- Use the same field names across comparable products so they align in the comparison table
内置对比功能(Cornerstone主题):
- 前往Storefront → My Themes → Customize
- 导航至Global → Product Compare(或根据主题版本选择Category Page → Product Compare)
- 将Enable product comparison切换为开启状态
- 设置Maximum products(默认值为4)
- 在Products → Product Custom Fields设置中配置要作为对比行展示的Product Custom Fields
- 购物者会在产品卡片上看到「对比」复选框;悬浮对比托盘会自动显示
添加规格数据:
- 前往Products → [对应产品] → Custom Fields,添加名称/值对(例如「屏幕尺寸:15.6英寸」「续航时长:10小时」)
- 同类产品使用相同的字段名称,确保它们在对比表格中正确对齐
Custom / Headless
自定义/无头电商
Comparison tray (floating bar as products are selected):
jsx
// ComparisonTray.jsx
export function ComparisonTray({ selectedProducts, onRemove, onClear }) {
if (selectedProducts.length === 0) return null;
const compareUrl = `/compare?${selectedProducts.map(p => `compare=${p.id}`).join('&')}`;
return (
<div className="comparison-tray" aria-live="polite" aria-label="Products selected for comparison">
<div className="tray-products">
{selectedProducts.map(product => (
<div key={product.id} className="tray-product">
<img src={product.image} alt={product.name} width="48" height="48" />
<button onClick={() => onRemove(product.id)} aria-label={`Remove ${product.name} from comparison`}>×</button>
</div>
))}
{Array.from({ length: Math.max(0, 4 - selectedProducts.length) }).map((_, i) => (
<div key={`empty-${i}`} className="tray-placeholder" aria-hidden="true">+</div>
))}
</div>
<div className="tray-actions">
<a href={compareUrl} className="btn-primary" aria-disabled={selectedProducts.length < 2}>
Compare ({selectedProducts.length})
</a>
<button onClick={onClear}>Clear all</button>
</div>
</div>
);
}Comparison table with sticky headers and difference highlighting:
jsx
export function ProductComparisonTable({ products, attributeGroups, showOnlyDifferences }) {
function isRowIdentical(attrKey) {
const values = products.map(p => p.attributes[attrKey]);
return values.every(v => v === values[0]);
}
return (
<div className="comparison-wrapper" style={{ overflowX: 'auto' }}>
<table className="comparison-table">
<caption className="sr-only">
Side-by-side comparison of {products.map(p => p.name).join(', ')}
</caption>
<thead>
<tr>
<th scope="col" className="attr-col">Attribute</th>
{products.map(product => (
<th key={product.id} scope="col">
<img src={product.image} alt={product.name} width="80" height="80" />
<a href={product.url}>{product.name}</a>
<strong>${product.price}</strong>
<button className="btn-primary">Add to Cart</button>
</th>
))}
</tr>
</thead>
<tbody>
{attributeGroups.map(group => (
<>
<tr key={`group-${group.label}`}>
<th scope="rowgroup" colSpan={products.length + 1}>{group.label}</th>
</tr>
{group.attributes.map(attrKey => {
if (showOnlyDifferences && isRowIdentical(attrKey)) return null;
return (
<tr key={attrKey} className={isRowIdentical(attrKey) ? 'identical-row' : 'different-row'}>
<th scope="row">{attrKey.replace(/_/g, ' ')}</th>
{products.map(p => (
<td key={p.id}>{p.attributes[attrKey] ?? 'N/A'}</td>
))}
</tr>
);
})}
</>
))}
</tbody>
</table>
</div>
);
}URL state for comparison (use to avoid polluting back-button history):
replaceStatejavascript
function toggleCompare(productId) {
const params = new URLSearchParams(window.location.search);
const current = params.getAll('compare');
if (current.includes(productId)) {
params.delete('compare');
current.filter(id => id !== productId).forEach(id => params.append('compare', id));
} else if (current.length < 4) {
params.append('compare', productId);
}
window.history.replaceState({}, '', `${window.location.pathname}?${params.toString()}`);
}对比托盘(添加产品时显示的悬浮栏):
jsx
// ComparisonTray.jsx
export function ComparisonTray({ selectedProducts, onRemove, onClear }) {
if (selectedProducts.length === 0) return null;
const compareUrl = `/compare?${selectedProducts.map(p => `compare=${p.id}`).join('&')}`;
return (
<div className="comparison-tray" aria-live="polite" aria-label="Products selected for comparison">
<div className="tray-products">
{selectedProducts.map(product => (
<div key={product.id} className="tray-product">
<img src={product.image} alt={product.name} width="48" height="48" />
<button onClick={() => onRemove(product.id)} aria-label={`Remove ${product.name} from comparison`}>×</button>
</div>
))}
{Array.from({ length: Math.max(0, 4 - selectedProducts.length) }).map((_, i) => (
<div key={`empty-${i}`} className="tray-placeholder" aria-hidden="true">+</div>
))}
</div>
<div className="tray-actions">
<a href={compareUrl} className="btn-primary" aria-disabled={selectedProducts.length < 2}>
Compare ({selectedProducts.length})
</a>
<button onClick={onClear}>Clear all</button>
</div>
</div>
);
}带固定表头和差异高亮的对比表格:
jsx
export function ProductComparisonTable({ products, attributeGroups, showOnlyDifferences }) {
function isRowIdentical(attrKey) {
const values = products.map(p => p.attributes[attrKey]);
return values.every(v => v === values[0]);
}
return (
<div className="comparison-wrapper" style={{ overflowX: 'auto' }}>
<table className="comparison-table">
<caption className="sr-only">
Side-by-side comparison of {products.map(p => p.name).join(', ')}
</caption>
<thead>
<tr>
<th scope="col" className="attr-col">Attribute</th>
{products.map(product => (
<th key={product.id} scope="col">
<img src={product.image} alt={product.name} width="80" height="80" />
<a href={product.url}>{product.name}</a>
<strong>${product.price}</strong>
<button className="btn-primary">Add to Cart</button>
</th>
))}
</tr>
</thead>
<tbody>
{attributeGroups.map(group => (
<>
<tr key={`group-${group.label}`}>
<th scope="rowgroup" colSpan={products.length + 1}>{group.label}</th>
</tr>
{group.attributes.map(attrKey => {
if (showOnlyDifferences && isRowIdentical(attrKey)) return null;
return (
<tr key={attrKey} className={isRowIdentical(attrKey) ? 'identical-row' : 'different-row'}>
<th scope="row">{attrKey.replace(/_/g, ' ')}</th>
{products.map(p => (
<td key={p.id}>{p.attributes[attrKey] ?? 'N/A'}</td>
))}
</tr>
);
})}
</>
))}
</tbody>
</table>
</div>
);
}对比功能的URL状态管理(使用避免污染返回按钮历史):
replaceStatejavascript
function toggleCompare(productId) {
const params = new URLSearchParams(window.location.search);
const current = params.getAll('compare');
if (current.includes(productId)) {
params.delete('compare');
current.filter(id => id !== productId).forEach(id => params.append('compare', id));
} else if (current.length < 4) {
params.append('compare', productId);
}
window.history.replaceState({}, '', `${window.location.pathname}?${params.toString()}`);
}Best Practices
最佳实践
- Limit comparison to 2–4 products — more than 4 columns breaks table layout on most screens; enforce this in the UI
- Group attributes by category — organize specs into groups (Display, Performance, Battery) to prevent a 50-row flat table
- Offer "show differences only" toggle — rows where all products share the same value add noise; provide an easy toggle
- Make the table horizontally scrollable on mobile — use on a wrapper; never hide columns to fit small screens
overflow-x: auto - Pre-populate from listing page — when a shopper clicks "Compare Now" after selecting items on the PLP, navigate with IDs in the URL
- Use consistent attribute naming — specs across products must use identical field names (e.g., "Screen Size" not sometimes "Display Size") for table rows to align
- 限制对比数量为2–4款产品——超过4列会在大多数屏幕上破坏表格布局;在UI中强制执行此限制
- 按类别分组属性——将规格分为不同组别(显示、性能、电池等),避免出现50行的扁平表格
- 提供「仅显示差异」开关——所有产品属性相同的行会增加冗余信息,提供便捷开关隐藏此类行
- 在移动端使表格可横向滚动——在容器上使用;切勿为适配小屏幕而隐藏列
overflow-x: auto - 从列表页预填充对比——当购物者在产品列表页选择商品后点击「立即对比」,通过URL携带产品ID跳转
- 使用统一的属性命名——不同产品的规格必须使用完全相同的字段名称(例如统一用「屏幕尺寸」,不要有时用「显示屏尺寸」),确保表格行正确对齐
Common Pitfalls
常见问题与解决方案
| Problem | Solution |
|---|---|
| Table overflows on mobile | Wrap in a scrollable container; use |
| Attributes missing for some products | Use "N/A" as the value — never skip the cell as it breaks column alignment |
| Comparison tray covers page content | Add |
| Products have different attribute sets | Normalize attribute keys across all compared products; fill missing values with |
| 问题 | 解决方案 |
|---|---|
| 表格在移动端溢出 | 将表格包裹在可滚动容器中;为第一列(属性标签)设置 |
| 部分产品缺少属性 | 使用「N/A」作为值——切勿跳过单元格,否则会破坏列对齐 |
| 对比托盘遮挡页面内容 | 当托盘显示时,为页面主体添加与托盘高度相等的 |
| 产品属性集合不同 | 统一所有对比产品的属性键;缺失值用 |
Related Skills
相关功能
- @product-page-design
- @faceted-navigation
- @accessibility-commerce
- @recently-viewed-products
- @product-page-design
- @faceted-navigation
- @accessibility-commerce
- @recently-viewed-products