必须声明doctype、lang和charset:须顶格首行,否则触发怪异模式致css/js异常;lang缺失影响可访问性与seo;meta charset须置于head最前,否则safari乱码、ie11降级。

模板层HTML必须声明DOCTYPE、lang和charset
不写或错位的!DOCTYPE html会让浏览器进入怪异模式,CSS盒模型、Flex布局甚至position: sticky都可能失效;lang缺失影响屏幕阅读器语种切换和SEO分词;meta charset="UTF-8"没放在前1024字节内,Safari可能乱码,IE11直接退化为Quirks Mode。
-
!DOCTYPE html必须是文件第一行,前面不能有空格、BOM或注释 -
中的值要与页面实际语言严格一致,动态模板需从后端注入,不能硬编码成lang="en"再靠JS改document.documentElement.lang -
<meta charset="UTF-8">必须在内,且位置尽可能靠前——它前面最多只能有!DOCTYPE和注释,不能有<link>或<script></script>
模板变量输出必须做HTML实体转义
CMS模板里常见{{ title }}、{% content %}这类占位符,如果后端没转义就直接插入HTML,XSS漏洞立刻成立。比如用户输入<script>alert(1)</script>,原样输出就会执行。
- 所有动态内容插入到HTML上下文时,必须用对应语言的安全转义函数:PHP用
htmlspecialchars($str, ENT_QUOTES, 'UTF-8'),Node.js模板引擎(如Nunjucks)默认开启autoescape,但|safe过滤器要慎用 - 插入到
href、src、onclick等属性值中时,需额外校验协议白名单(只允许https:、/、#),不能只依赖HTML转义 - 富文本字段(如编辑器输出)不能简单转义,要用DOMPurify等库净化,且禁止
style、on*、javascript:等危险内容
语义化标签不能被模板逻辑破坏结构
模板里用{% if has_sidebar %}<aside>...</aside>{% endif %}没问题,但若写成<main>{% for item in list %}<article>...{% endfor %}</article></main>,而list为空,就会导致<main></main>空标签——这本身合法,但若CSS依赖main > article选择器,样式就丢了;更严重的是,<main></main>在可访问性上要求“页面有且仅有一个”,嵌套或重复生成会破坏AT导航流。
-
<main></main>、<header></header>、<footer></footer>这类全局唯一标签,必须由最外层模板控制,子模板/组件不能自行包裹 -
<section></section>、<article></article>可以按数据循环,但需确保父容器语义合理,避免<div><section><div><article></article></div></section></div>这种冗余嵌套 - 条件渲染时检查是否产生孤立闭合标签,例如
{% if user %}<nav>...</nav>{% endif %}导致<nav></nav>空节点,不如改为{% if user and nav_items %}<nav>...</nav>{% endif %}
静态资源路径和属性值必须用模板语法生成
手写src="/static/img/logo.png"看似省事,但一旦CDN切换、版本哈希或构建路径变更,所有模板都要人工改;更隐蔽的问题是,alt="{{ alt_text }}"里如果alt_text为空,就会输出alt=""——这是正确做法,但若写成alt="{{ alt_text|default('logo') }}"又可能把空字符串变成字面量"logo",覆盖了本意。
- 所有
src、href、poster等路径,统一走{{ static_url('img/logo.png') }}或{{ url_for('static', filename='img/logo.png') }}这类函数,便于统一处理CDN、hash、代理 - 布尔属性如
required、disabled,不要写required="{{ field.required }}",应写{% if field.required %}required{% endif %},避免输出required="False"这种非法值 -
class拼接用class="{{ 'btn btn--primary ' + extra_class|default('')|trim }}",别用class="btn btn--primary {{ extra_class }}",防止多出空格或开头空格导致选择器失效
doctype-first、attr-lowercase、attr-quote-style,且把模板编译后的最终HTML作为输入源——因为很多问题(如未闭合标签、错误嵌套)只在变量展开后才暴露。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











