日式 RPG 的对话框有个很鲜明的特征:它不是「一个框」,而是层层套起来的框。从外到内通常是描边黑、留白、描边黑,中间才是文字。
传统做法是切一张九宫格图(9-slice)当 border-image。但其实纯 CSS 就够了。
用 box-shadow 叠出多层描边
关键在于:box-shadow 支持 inset,而且可以叠加多层。后写的被先写的盖住,所以从外到内的顺序要倒着写。
.rpg-frame {
background: #f8f0d8;
border: 4px solid #14181c;
box-shadow:
inset 0 0 0 4px #f8f0d8,
inset 0 0 0 8px #14181c,
6px 6px 0 0 rgba(0, 0, 0, 0.5);
}
拆开看:
border: 4px—— 最外圈描边inset 0 0 0 8px #14181c—— 先画一个 8px 的黑环inset 0 0 0 4px #f8f0d8—— 再用奶油色盖住外面 4px
结果就是从外到内:黑 → 奶油 → 黑。而最后那个 6px 6px 0 0 是硬偏移投影,注意 spread 和 blur 都是 0,这是像素风的关键。
那个闪烁的 ▼
RPG 对话框右下角总有个闪烁的小三角,暗示「按键继续」。用 CSS 三角形加 steps() 动画就够了:
.rpg-dialog__next {
position: absolute;
right: 12px;
bottom: 8px;
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 8px solid #e8a020;
animation: rpg-blink 1s steps(2, start) infinite;
}
@keyframes rpg-blink {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}
这里有个容易忽略的细节:用 steps(2, start) 而不是默认的缓动。像素风的东西不应该有平滑过渡——闪烁必须是瞬间的跳变,否则就失去了那种老主机的机械感。
同理,所有
transition都应该设成none。 悬停变色、菜单光标出现,全都应该是瞬时的。
菜单项的 ▶ 光标
RPG 的菜单里,当前选中项左边会出现一个三角形光标。实现上就是伪元素:
.rpg-menu-item::before {
content: "\25B6";
position: absolute;
left: 8px;
color: #e8a020;
opacity: 0;
}
.rpg-menu-item:hover::before,
.rpg-menu-item[aria-current="page"]::before {
opacity: 1;
}
注意同时处理了 :hover 和 aria-current——键盘导航和无障碍读屏也要能用,不能只做鼠标效果。
别忘了按钮要有「按下去」的手感
最后一件事。像素风的按钮如果不做位移,点起来是飘的。让它整体平移、阴影同步收缩,就有了物理按键的感觉:
.rpg-btn:active {
transform: translate(3px, 3px);
box-shadow: inset -4px -4px 0 0 rgba(0, 0, 0, 0.25);
}
这三像素的位移是整个设计里最便宜、也最有效的细节。