买东西加购物车这事儿,谁还没干过呢。从点外卖到买衣服,那个小图标一跳一跳的,看着就带劲。但真到自己动手做这个效果,是不是有点懵?既要让东西飞过去,还得记住加了多少个,咋搞?今天就掰开揉碎,说说怎么用CSS和一组单选按钮,弄出个能无限点、还能自动飞入购物车的小玩意儿。这法子可能不是最完美的,但绝对够巧妙,看完就能上手。
这玩意儿叫啥,无限选择
无限选择,听着玄乎,其实说白了就是让页面上那些商品卡片,随便点哪个,它都能像被施了魔法一样,嗖地一下飞到购物车里去。想加多少加多少,没有数量限制,全靠CSS在背后撑场子,除了那个数数的小标记得用点JavaScript帮忙。核心就是玩转单选按钮那点事儿。
先搭架子,把商品摆好
做这事之前,得先把商品摆上桌。每个商品其实就是一个盒子,里面藏着两个长得一模一样的单选按钮,而且它们俩名字得一样,这样才是一个小组。
<div class="items flat-white">
<input type="radio" name="r3" title="Flat White">
<input type="radio" name="r3" title="Flat White">
</div>为啥要放俩?这就是个障眼法。点一下,其中一个被选中,另一个自动就弹开。这样一来一去,就有了“加购”这个动作的触发器。
为了让这些商品卡片能乖乖待在位置上,得给它们定好位。整个卡片盒子用绝对定位,里面的两个单选按钮也得绝对定位,并且铺满整个盒子。
.items {
position: absolute;
input {
position: absolute;
inset: 0;
}
}这个inset: 0;可是个好东西,它让按钮的上下左右都贴着盒子的边缘,这样点图片点文字,都能点到按钮,不会出现点不着的尴尬情况。
接下来就是把这些商品卡片,从购物车那个中心点,摆到它们各自该待的位置上。这就好比从圆心出发,把点发散到四周。用transform: translate来挪动它们,可以控制上下左右的距离。
.items {
--y: 100px; /* 从上往下飞的垂直距离 */
&:not(.cart) {
transform: translate(var(--x), calc(-1 * var(--y)));
}
&.espresso {
--x: 0px; /* 水平距离 */
}
&.cappuccino {
--x: -100%;
}
&.flat-white {
--x: 100%;
}
}这里用到了CSS变量,像--x和--y,就是为了方便调整每个商品的起始位置。比如浓缩咖啡就在正上方,卡布奇诺就往左偏,拿铁往右偏。这些数值可能需要微调,直到看着顺眼为止。
让商品飞起来,加点动效
布局搞定,重头戏来了。怎么让点击的那个商品,动画般地飞到购物车里去?关键就在:checked这个状态上。
当单选按钮被选中,也就是商品被点了一下之后,就让它发生位移和缩放,最终变成一个小点,消失在购物车的位置上。
input:checked {
transform: translate(calc(-1 * var(--x)), var(--y)) scale(0);
transition: transform .6s linear;
}这里有个小技巧,位移的距离正好是初始位置的相反数。比如原来在--x: 100%的位置,那就往左移动-100%,这样就能精准地飞回到原点。加上scale(0),让它消失在购物车那个点。最后加上.6s的过渡动画,就有了那个丝滑的飞行感。
数数加了多少,心里有数
光飞过去还不行,总得知道加了多少个吧。这时候就得请出JavaScript来帮个小忙,负责统计点击次数并更新显示。
let n = 0;
const CART_CNT = document.querySelector("output");
document.querySelectorAll("[type='radio']").forEach(radio => {
radio.onclick = () => {
CART_CNT.innerText = ++n;
CART_CNT.setAttribute("arial-label", `${n}`)
}
});这段代码干了这么几件事:先找到那个显示数量的地方(比如一个<output>标签),然后监听页面上所有的单选按钮。每点一下,就把计数n加一,然后更新显示的数字。顺带还更新一下arial-label,方便读屏软件读出当前有多少商品。
有一点得提一嘴,这版demo里加进去的东西可没法退出来,点了就认了,想好了再点哈。
屏幕阅读器那点事儿,得留心
说到这儿,得泼盆冷水。这个设计虽然看着酷,但对屏幕阅读器不太友好。每个商品里塞了两个功能相同的单选按钮,读屏软件可能会把它读成两个选项,或者来回切换时状态变化让用户摸不着头脑。虽然可以在代码里藏点提示文字,但终究不是最完美的方案。如果特别在意无障碍访问,可能得琢磨琢磨其他路子。
还有没有更香的法子
其实想让东西飞进购物车,不只有这一条路。现在浏览器有了个新玩意儿,叫视图过渡API。这玩意儿只用两个元素就能搞定过渡,一个商品,一个购物车,用CSS给它们起个名字,定义好动画,点一下就触发,干净利落,没有多余的按钮,也不用费心思维护状态。如果项目不用考虑太老旧的浏览器,这个方案绝对值得一试。
另外,如果商品就那么几样,用复选框也能凑合,每个商品一个复选框,点一下算一次,简单直接。但缺点就是加购次数有限,没那么灵活。
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 双单选按钮 | 无限次数,纯CSS动画 | 无障碍支持差,结构稍复杂 | 商品多,需无限添加,可接受一定局限 |
| 视图过渡API | 结构简洁,动画流畅 | 较新API,旧浏览器不支持 | 现代浏览器项目,追求极简代码 |
| 复选框方案 | 代码最简单 | 无法统计无限次数 | 商品数量少,加购次数有限 |
所以,如果项目里需要无限加购,又用不了视图过渡API,那这套双单选按钮的玩法,绝对是个值得往工具箱里收的好把式。虽然有点小瑕疵,但架不住它思路清奇,上手也快。
