按功能与层级组织 · 同一组件提供多框架代码,复制即用
左右拖动分割线看改造前后。两层都是真 DOM,不是两张图拼的——所以右边那层照样能交互、能读屏。分割用 clip-path 而不是宽度,拖动时不触发重排;指针用 setPointerCapture 接管,手滑出容器也不会中断。滑块本身是 role="slider",方向键微调、Home/End 到两端,键盘用户不需要鼠标。
输入即过滤、↑↓ 移动、回车确认、Esc 关闭。焦点始终留在输入框,选中项用 aria-activedescendant 指出去——一旦把焦点移到列表项上,读屏用户每按一次方向键都会听到整个列表被重读。分组标题不参与键盘循环,跳过的逻辑放在拍平后的一维数组里做,不在渲染时判断。
三档并排,用边框粗细与阴影把推荐档抬起来,价格用等宽数字(tabular-nums)对齐——不加这条,¥0 和 ¥399 的小数点会错位,三张卡的价签看起来像没对齐。billing 参数让月付与年付共用同一套 DOM:年付只换数字与角标,不另做一套卡片。
一次性扫过的高光,不是循环呼吸。按钮底色固定、只有高光色跟着参数走——这两件事分开,才不会出现「拖了半天整颗按钮变色、那道光纹丝不动」的假参数。扫动用 ::before 的位移实现,不额外挂 DOM 节点,也不干扰 :active 的按压反馈。