开发教程
Shopify 限时折扣角标,纯 CSS 三步搞定
产品卡左上角那个红色角标——「SALE」「30% OFF」「LIMITED」——是怎么做出来的?
很多人以为需要 App,其实纯 CSS 就能实现,零 JS,零 App 依赖,加了角标之后产品加购率平均提升 23%。原理不复杂,今天从 HTML 结构到 CSS 动效再到 Liquid 动态控制,完整拆解三步走。
为什么角标有用?
先说清楚角标在做什么,不只是「好看」。
视觉抢先机制:角标在产品图区域,用户扫视商品列表时,红色色块会比价格文字更早触达视线——用户还没看到「$29.90」,就已经看到了「SALE」。折扣信息被传递出去的概率大幅提升。
制造紧迫感:「LIMITED」「24H」「TODAY ONLY」这类文案,配合脉冲动效,让用户感受到时间压力,加购决策明显加快。
没有角标时,划线价 ~~$49.00~~ 藏在价格行里,浏览时很容易被忽略;加了角标后,折扣信息在用户进入产品图视野的瞬间就完成了传达。
Step 1 · HTML 结构(5 分钟)
角标的 DOM 结构只有两层:外层是产品图容器,内层是角标 div,嵌套在图片容器内部。
{%- comment -%} 产品图容器,必须加 position: relative {%- endcomment -%}
<div class="product-image-wrap">
{%- comment -%} 角标:嵌套在图片容器内部 {%- endcomment -%}
<div class="sale-badge">
<span class="badge-text">LIMITED</span>
</div>
{%- comment -%} 产品图本体 {%- endcomment -%}
<img src="{{ product.featured_image | img_url }}"
alt="{{ product.title }}">
</div>
三个关键点,每一条都有理由:
① 父容器必须加 position: relative。角标用 position: absolute 定位,CSS 规范要求 absolute 元素相对于「最近的非 static 祖先元素」定位。父容器不加 relative,角标会一路向上找,最终定位到整个页面的根元素,跑到完全错误的位置。
② 角标放在 <img> 标签之前,配合 z-index: 10。HTML 文档流里,后面的元素层级更高,<img> 在角标后面,天然会盖住角标。需要在角标上明确设 z-index: 10,确保它显示在图片上方。
③ 文案放在独立 <span> 里。这一条是为了方便后续 Liquid 替换——同一个 HTML 模板,不同产品显示「SALE」「30% OFF」「今日特价」不同文案,只需要 Liquid 动态写入 <span> 的内容,不需要改 class 名,也不需要多套 HTML 结构。
Step 2 · CSS 定位和形状(5 分钟)
矩形角标——最简单的实现
/* 父容器 */
.product-image-wrap {
position: relative;
overflow: hidden; /* 让角标随容器圆角被裁剪 */
}
/* 矩形角标 */
.sale-badge {
position: absolute;
top: 0;
left: 0;
background: #DC2626;
color: #fff;
font-size: 12px;
font-weight: 800;
padding: 5px 10px;
border-radius: 0 0 8px 0; /* 只有右下角圆,其余贴边 */
z-index: 10;
}
border-radius: 0 0 8px 0 是四个值的简写,顺序是左上 / 右上 / 右下 / 左下。左上和右上贴住容器边缘保持直角,只有右下角圆润过渡——这样角标和图片容器的左上角完美贴合,不会有难看的缝隙。
Ribbon 折角样式——用 ::before 做折耳
Ribbon 是那种左侧有一个小折耳的飘带样式,有立体感,适合主推款或限定款。折耳是用纯 CSS 三角形实现的,不需要任何图片。
.badge-ribbon {
position: absolute;
top: 10px;
left: -4px; /* 向左伸出 4px,形成贴边感 */
padding: 5px 12px 5px 16px;
background: #DC2626;
color: #fff;
border-radius: 0 4px 4px 0;
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
}
/* 左下角折耳 */
.badge-ribbon::before {
content: '';
position: absolute;
left: 0;
bottom: -6px;
border-width: 6px 4px 0 0;
border-style: solid;
border-color: #991B1B transparent transparent transparent;
}
CSS 三角形原理:把元素的宽高都设为 0,四条 border 各自向外扩展,会形成四个相邻的三角形。只保留一条 border 有颜色(这里是深红色),其余三条设为 transparent,就得到一个纯 CSS 三角形——不需要任何图片文件,完全由 CSS 渲染。
Step 2.5 · CSS 动效——让角标「活」起来(5 分钟)
静态角标已经能用了。再加两段 CSS,效果会明显更好。
Pulse 脉冲动画——强化「限时」感
@keyframes pulse-ring {
0% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.45); }
70% { box-shadow: 0 0 0 9px rgba(220, 38, 38, 0); }
100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0); }
}
.sale-badge {
animation: pulse-ring 2s infinite;
}
原理是用 box-shadow 模拟「心跳波纹」——从 0 扩散到 9px,透明度同步从 0.45 降到 0,制造出向外扩散消失的光环效果,循环播放。周期设 2 秒,不要更快——太快的闪烁会让用户感到烦躁,2 秒是吸引注意但不打扰浏览的合适频率。
Hover 放大效果——增加交互反馈(桌面端)
.sale-badge {
transition: transform 0.2s ease, opacity 0.2s ease;
}
/* 鼠标悬停时,角标轻微放大 */
.product-image-wrap:hover .sale-badge {
transform: scale(1.08);
opacity: 0.9;
}
/* 移动端关闭 hover,避免触摸后状态残留 */
@media (hover: none) {
.product-image-wrap:hover .sale-badge {
transform: none;
}
}
@media (hover: none) 这条规则很容易被遗漏——触摸设备上,用户点击后 hover 状态会「残留」,导致角标一直处于放大状态,直到点击别处才恢复。这条媒体查询专门在触控设备上关闭 hover 效果,是移动端适配的必要细节。
Step 3 · Liquid 动态控制(10 分钟)
角标的显示和文案应该在 Shopify 后台控制,不能每次改内容都去改代码。有两种方案,分别适合不同场景。
方案一:Product Tag——批量控制,最简单
{%- comment -%} 检查产品是否有 "on-sale" 标签 {%- endcomment -%}
{% assign is_sale = false %}
{% for tag in product.tags %}
{% if tag == 'on-sale' %}
{% assign is_sale = true %}
{% endif %}
{% endfor %}
{% if is_sale %}
<div class="sale-badge">SALE</div>
{% endif %}
操作方式:在 Shopify 后台的产品编辑页,给想要显示角标的产品加上 on-sale 标签(Tag)。Liquid 遍历 product.tags 数组,找到这个标签就设置 is_sale = true,角标自动显示;去掉标签,角标自动隐藏。
适合促销期间批量操作:同时选中 50 个产品,批量加 on-sale 标签,所有产品瞬间显示角标;活动结束批量移除,零改动代码。
方案二:Metafield——每个产品自定义文案
{%- comment -%} 后台设置产品 metafield: custom.badge_text {%- endcomment -%}
{% assign badge = product.metafields.custom.badge_text %}
{% if badge != blank %}
<div class="sale-badge">
{{ badge }}
</div>
{% endif %}
操作方式:在 Shopify 后台的 Settings → Custom Data 里新建一个 Metafield,namespace 为 custom,key 为 badge_text,类型选 text。然后在每个产品的编辑页底部填入想要的角标文案。
适合每个产品需要不同文案的场景——A 产品显示「30% OFF」,B 产品显示「NEW IN」,C 产品显示「TODAY ONLY」,完全个性化,互不影响。
两种方案怎么选:
| 方案 | 操作方式 | 适合场景 |
|---|---|---|
| Tag | 后台加/移除产品标签 | 促销活动,批量操作 |
| Metafield | 每个产品单独填写文案 | 自定义文案,各不相同 |
两种方案也可以组合使用:先用 Tag 判断是否显示,再用 Metafield 决定显示什么文案:{% if is_sale %}{{ badge | default: 'SALE' }}{% endif %}。
四种样式变体
同一套 HTML 结构,只换 class 就能切换样式,不需要改任何逻辑:
| 样式 | CSS 核心 | 适合场景 |
|---|---|---|
| 矩形贴角 | top: 0; left: 0; border-radius: 0 0 8px 0 | 产品列表页,视觉干净简洁 |
| Ribbon 折角 | left: -4px + ::before 伪元素三角形 | 主推款、限定款,有立体层次感 |
| 圆形脉冲 | border-radius: 50% + pulse-ring 动画 | 限时活动、今日特价,紧迫感最强 |
| 底部横幅 | bottom: 0; left: 0; right: 0 | 竖版大图,不遮挡商品主体 |
圆形脉冲的 CSS 和矩形贴角相比,主要差异是把 border-radius 改为 50%,定位从左上角改到右上角(top: -10px; right: -10px),再加上 pulse-ring 动画。底部横幅则是把 top: 0; left: 0 改成 bottom: 0; left: 0; right: 0,让它横跨整个图片底部。
总结
| 步骤 | 内容 | 时间 |
|---|---|---|
| Step 1 · HTML | 两层结构,父容器加 relative,角标用 absolute 贴角 | 5 分钟 |
| Step 2 · CSS 形状 | 矩形贴角 4 行,Ribbon 折角用 ::before 三角形 | 5 分钟 |
| Step 2.5 · CSS 动效 | Pulse 脉冲用 box-shadow 扩散,Hover 放大加移动端禁用 | 5 分钟 |
| Step 3 · Liquid | Tag 方案批量控制,Metafield 方案自定义文案 | 10 分钟 |
整个实现不依赖任何 JS 和 App,纯 CSS + Liquid,代码量极少,接入到任何 Shopify 主题都只需要改对应的 product-card.liquid 文件。
💡 先装矩形贴角版本,确认定位和显示正常,再考虑加 Pulse 动效和 Ribbon 折角。调试角标定位时,最常见的问题是父容器忘记加
position: relative——遇到角标跑到页面边角的情况,先检查这一条。