原生 input[type="date"] 的 min/max 仅限制日历可选范围,不校验手动输入或粘贴;格式必须为 YYYY-MM-DD(补零),否则静默失效;动态设置需用 setAttribute 或触发 input 事件;起止日期联动时须主动清空 min/max。

原生 input[type="date"] 的 min 和 max 属性根本不是“限制输入”,只是限制日历弹窗里可点的日期;不校验手动输入、不拦截粘贴、不自动清空超限值,靠它防数据出错等于没防。
为什么设置了 min/max 却没效果
浏览器对格式极其敏感,错一位就静默失效——不是报错,是直接当没写:
-
min="2026-9-4"❌ 缺零,字符串比较时"2026-9-4" > "2026-09-04"成立,逻辑反转 -
min="2026/09/04"❌ 斜杠分隔,被丢弃 -
min=new Date().toISOString()❌ 得到"2026-09-04T01:28:33.123Z",必须用.slice(0, 10)或.split('T')[0] -
checkValidity()返回false,但 UI 不灰、不提示、用户照点照输
动态设置必须用 setAttribute 或强制重绘
直接赋值 input.min = "2026-09-04" 在 Safari(尤其 iOS ≤ 15.5)和部分旧 Chrome 中,日历控件完全不刷新:
- ✅ 可靠写法:
input.setAttribute('min', '2026-09-04') - ✅ 或赋值后手动触发:
input.dispatchEvent(new Event('input', { bubbles: true })) - ⚠️ 若当前
input.value已超出新max,浏览器不会清空,必须显式判断:if (input.value && input.value > input.max) input.value = ''
起止日期联动时,min 清空比设置更重要
只监听开始日期变更并设 end.min = start.value 是不够的。一旦用户清空开始日期,end.min 还卡在旧值上,end 就再也选不了任何日期:
立即学习“前端免费学习笔记(深入)”;
- 监听
start的change事件:若start.value为空,必须执行end.removeAttribute('min')或end.min = '' - 监听
end的change事件:若end.value ,调用 <code>end.setCustomValidity('结束日期不能早于开始日期')并立即end.reportValidity() - 移动端 Safari 的
change触发不稳定,建议加blur事件兜底
最易被忽略的是:所有浏览器都允许用户手动键入任意合法格式日期(比如 "1970-01-01"),且不触发任何原生提示。真正起作用的永远是 JS 实时校验 + 服务端二次解析,min/max 只是 UI 辅助,不是防线。



















