min/max 仅限制日历UI可选范围且格式必须严格为YYYY-MM-DD,需JS实时校验+服务端验证防绕过;动态设置优先用setAttribute;联动时需同步清空对方min/max属性。

min 和 max 属性能控制日历 UI 的可点范围,但不能阻止手动输入非法日期;必须配合 JavaScript 实时校验 + 服务端二次验证,否则用户粘贴、键盘输入或禁用 JS 后仍可绕过。
min/max 只认严格 YYYY-MM-DD 格式,错一位就失效
浏览器对 min 和 max 的格式极其敏感:必须是形如 "2026-10-20" 的字符串,少一个零(如 "2026-10-2")、多一个斜杠("2026/10/20")、带时间部分("2026-10-20T00:00")都会被静默忽略——UI 不灰、输入不拦、checkValidity() 却返回 false。
- 用
new Date().toISOString().split('T')[0]最稳妥,但注意它返回的是 UTC 时间,东八区凌晨 0–1 点调用会得到前一天的日期 - 更可靠的手动拼接:
`${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}` - 动态设置时,优先用
input.setAttribute('min', '2026-10-20'),Safari 对input.min = '2026-10-20'的 UI 更新支持不稳定 - 若当前
input.value已超出新设的max,浏览器不会自动清空,需显式判断并重置:if (input.value && input.value > input.max) input.value = ''
联动起止日期时,min/max 清空逻辑不能漏
做“结束日期不能早于开始日期”这类联动,只设 end.min = start.value 是不够的。一旦用户清空了 start,end.min 必须同步清除,否则 end 将永远无法选择任何值(因为 min 被卡在一个已不存在的日期上)。
- 监听
start的change事件:若start.value === '',必须执行end.removeAttribute('min')或end.min = '' - 监听
end的change事件:若end.value && start.value && end.value ,应调用 <code>end.setCustomValidity('结束日期不能早于开始日期')并立即end.reportValidity() - 移动端 Safari 对
change触发不稳定,建议额外监听blur做兜底校验
用户仍能手动输入非法日期,min/max 不是安全锁
min 和 max 完全不限制键盘输入、粘贴、删除重输等行为。用户可以轻松在 input[type="date"] 中输入 "2025-01-01" 到一个 max="2024-12-31" 的框里,并成功提交。
立即学习“前端免费学习笔记(深入)”;
- 必须监听
input事件做实时校验:解析输入值是否符合YYYY-MM-DD格式,再比较字典序是否在范围内 - 非法时建议清空字段或重置为默认值(如
min),而非仅提示错误——避免用户反复提交失败 - 服务端必须重新解析并验证日期是否落在允许区间内,不可信任任何前端传来的
date字段 - 如需真正禁用非法输入,应放弃原生
type="date",改用第三方库(如 flatpickr)或自定义组件
最容易被忽略的是:不同浏览器对 min/max 的视觉反馈不一致——Safari 可能灰掉超限日期但不阻止输入,Chrome 会禁用日历中的超限项但允许键盘输入。别假设用户只会点日历。



















