step="900"对应每15分钟一档,因type="time"的step单位为秒,故15×60=900;value必须为hh:mm且分钟数被步长整除,否则触发静默修正;step仅约束箭头/滚轮操作,不拦截手动输入,兼容性差,建议用select或第三方库兜底。

step="900"才是30分钟,不是step="30"
HTML input 的 type="time" 中,step 单位固定为**秒**,不是分钟、不是字符串、不认 "30m" 或 "00:30"。写 step="30" 实际是 30 秒——用户会看到 09:00 → 09:00:30 → 09:01:00,完全不是你想要的分钟粒度。
要实现「每30分钟一档」,必须换算:30 × 60 = 1800;「每15分钟」就是 900;「整点」即 3600。
-
step="60"→ 每1分钟(09:00、09:01、09:02…) -
step="300"→ 每5分钟(09:00、09:05、09:10…) -
step="900"→ 每15分钟(09:00、09:15、09:30…) -
step="1800"→ 每30分钟(09:00、09:30、10:00…)
value 必须秒数为 0,否则 step 失效
即使写了 step="1800",如果 value="09:07",浏览器会静默修正该值(比如跳到 09:00 或 09:30),导致初始状态错乱、拖动卡顿、箭头点击跳变异常。
正确做法是显式设对齐值:
- ✅
value="09:00"(秒部分隐含为 :00) - ✅
value="14:30"(合法,30 分钟档位) - ❌
value="09:07"(非法,触发静默修正) - ❌
value="09:30:15"(含秒,破坏对齐)
后端或 JS 初始化时也得确保传入的是 HH:MM 格式,且分钟数能被步长整除(如 30 分钟步长,只允许 00 或 30 分)。
step 只管箭头和滚轮,不管手动输入
step 对 type="time" 的约束非常有限:它只影响上下箭头、鼠标滚轮、触控板滚动等“原生增减行为”,但用户仍可直接输入任意时间,比如在 step="1800" 下输 09:17,浏览器不会拦截,提交时也不会报 stepMismatch(多数浏览器根本不对 time 类型做 step 校验)。
真要强制对齐,必须加 JS:
input.addEventListener('change', () => {
const [h, m] = input.value.split(':').map(Number);
const totalMinutes = h * 60 + m;
const stepMinutes = 30; // 对应 step="1800"
const rounded = Math.round(totalMinutes / stepMinutes) * stepMinutes;
const hh = String(Math.floor(rounded / 60)).padStart(2, '0');
const mm = String(rounded % 60).padStart(2, '0');
input.value = `${hh}:${mm}`;
});
注意监听 change 和 blur,避免用户输完直接失焦绕过校验。
兼容性差,别指望全平台生效
iOS Safari ≤15.4 完全忽略 step 对 type="time" 的作用;Android Chrome 表现尚可,但部分低端机型仍降级为 1 秒步进;Firefox 某些版本仅支持整数秒,step="900" 可能被截断。
如果你的应用必须稳定支持半小时/15分钟粒度,别押注原生 step:
- 用
select下拉菜单列出预设时间选项(最稳) - 引入轻量库如
flatpickr并配置minuteIncrement: 15 - 自研时间选择器,用两个
number输入框分别控小时/分钟,并限制分钟选项为 [0, 15, 30, 45]
原生 step 是锦上添花,不是兜底方案。它起作用的地方,往往是你没测试到的旧浏览器;它失效的地方,恰恰是用户正在用的设备。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











