纯HTML从零搭建个人博客页面:语义化标签与Flexbox布局实战
2026/9/18 18:50:30 网站建设 项目流程

用纯HTML写个人博客页面,这事儿听起来像新手练习,但真动手写的时候,你会发现“纯HTML”这三个字藏着不少门道:少了CSS页面根本没法看,加了CSS又觉得好像不“纯”了;标签全用div堆,浏览器能跑但结构一塌糊涂;写完一刷新正常,换个浏览器直接崩。我这篇文章就把这些坑都填平,用一份可以直接复制运行的纯HTML代码,带你从零搭出一个个人博客页面——带导航、文章列表、侧边栏和页脚,结构清晰,换浏览器不乱。适合刚学完HTML标签、想做第一个完整页面的人,也适合需要交网页设计作业的在校生,或者想快速出个博客静态原型再接后端的前端初学者。你只需要一个文本编辑器和浏览器,就能跟着跑完整个流程。

1. 先想清楚:所谓“纯HTML”到底纯在哪

1.1 纯HTML不是“没有样式”

很多人一看“纯HTML”三个字,就理解成只用标签、完全不要CSS。这个理解其实把路走窄了。真正在工作中或者交作业时说“我要纯HTML做一个个人博客页面”,通常指的是不依赖任何框架、不引入外部文件、不写JavaScript逻辑,而不是禁止使用<style>标签。一个真正的博客页面,哪怕再简单,也需要基本的排版:标题要醒目,正文字号要舒服,页面四周要有留白。这些硬需求靠HTML标签本身是没法实现的,所以现实中大家说的“纯HTML页面”,基本都是“一个HTML文件内部包含CSS”的单文件方案。

用内嵌<style>而不是外部样式表,原因很实际:交付文件只有一个,拷到任何环境都能直接打开,双击浏览器就能跑。我把样式直接放在<head>里的<style>标签中,整个页面的样式都在这个标签里维护。对做作业、演示、原型这类场景,这比把CSS单独拆一个文件再引进来要省心得多——你不用担心别人拷贝的时候漏了那个CSS文件。

1.2 为什么坚持用语义化标签

<div><div>当然也能搭出页面,但有三个问题:搜索引擎看不懂,屏幕阅读器读不爽,你自己过一个月回来看代码也看不懂。HTML5提供了一套语义化标签,像<header><nav><main><article><aside><footer>。它们的作用就像书里的章、节、注释、页脚,代码一打开,每一块是干嘛的一目了然。

我见过太多新手写了半天标签,页面看起来一样,但代码的可维护性天差地别。语义化的核心意义不只是给机器看的,更是给你自己看的。你写的博客页面将来大概率会改——可能是加一篇新文章,可能是调整导航菜单。如果整个页面就是十几个<div>套在一起,你找一个内容区域的位置都要翻半天;换成语义化标签,<article>里就是文章主体,<aside>里就是侧边栏,改起来痛快得多。

1.3 布局方案:为什么选Flexbox而不是定位或浮动

用Flexbox做整体布局,是这份代码里最关键的一个设计决策。我没有选定位布局,因为定位布局对新手不友好,一个position: relative套一个absolute,稍不留神就叠层穿帮;也没选传统的float,因为float的设计初衷是让文字环绕图片,不是用来搭页面框架的,想用它搭两栏布局,就得手动清浮动,写起来绕而且行为不稳定。Flexbox进入主流浏览器视野这么多年,兼容性早就稳了,写两栏布局只需要display: flex加一个justify-content: space-between,代码短,行为直观,新手上手成本最低。

不过要补充一句:布局方案一定要先想清楚再写,别一上来就乱试。个人博客无非就是“主要内容加侧边栏”的两栏,或者干脆单栏往下排。两者都可以,没有对错之分,只有风格差异。我这份代码用的是两栏布局,因为页面信息量更足,看起来更接近真实博客的观感。

2. 标准HTML5文档骨架,一个标签都不能少

2.1 DOCTYPE和meta,少了就是给自己挖坑

页面开头必须写<!DOCTYPE html>,这是告诉浏览器“请按标准模式解析我”。不写会怎样?浏览器会进入“怪异模式”,各种元素的默认样式和行为跟标准模式完全不一样,盒模型会退回老IE那一套。你算好的宽度,在怪异模式下可能多出几个像素,页面就错位了。所以不管页面多简单,第一行一定不能省。

<html lang="zh-cn">这个属性也容易被忽略。lang声明页面的主要语言,浏览器拿到后会据此处理断行、发音、标点和默认字体选择。虽然不写大多数时候也能正常显示,但规范就是不完整,写上是零成本的事,给自己页面补上这一层信息总没错。

<meta charset="utf-8">是另一个绝对不能省的标签。没有它,你用中文字符写的内容很容易显示成乱码。原因在于浏览器碰到没有编码声明的HTML文件,只能按默认编码去猜,猜对了万事大吉,猜错了满屏都是“�”这种替代字符。虽然现代浏览器普遍默认UTF-8,但如果你手动换过编辑器设置,或者文件里混入了特殊字符,编码问题还是会冒出来。

还有一个viewport标签,<meta name="viewport" content="width=device-width, initial-scale=1.0">,这句话对手机浏览器尤其重要。没有它,移动端浏览器默认按桌面宽度渲染页面,然后整体缩小,用户需要手指捏合放大才能看清字。加上这句,页面宽度才会跟随设备宽度自适应。个人博客虽然是桌面展示居多,但手机浏览的需求现在谁都不敢忽略。

2.2 head里的title和style写法

<title>决定浏览器标签页上显示的文字,也是搜索引擎结果里的大标题。建议把页面核心词放前面,写成“阿泽的个人博客”或“个人博客 - 记录与分享”这种格式,别用“未命名文档”这种占位符,一看就是半成品。我在代码里写的标题是“记录与分享 - 阿泽的个人博客”,兼顾了品牌名和信息量。

<style>放在<head>里是标准的“内嵌样式”方式,作用域是当前整个文档。这里必须注意作用域问题:<style>里定义的样式对全页生效,但你如果只希望某个区块有特定样式,就要用类名或ID去限定。我刚学的时候犯过这个错,给<p>定义了红色,结果全页面所有段落都红了。所以后面代码里,正文、侧边栏、页脚的样式基本都通过类名来绑定,各自独立,互不干扰。

2.3 页面结构分区规划

一份博客页面的正文区,至少可以拆成几个清晰的功能块。我习惯用一个表格来梳理:

区块标签实际职责
页首<header>博客主标题、简介、作者信息
导航<nav>菜单链接,页面内部锚点跳转
主体<main>博客文章列表核心区
侧边<aside>博主介绍、热门文章、标签云
页脚<footer>版权声明、联系方式

代码里严格按这个分区来写,每个区块之间用HTML注释<!-- 页首 --><!-- 主体 -->做分隔。这样一段代码放在那儿,不用解释,别人扫一眼就能看清结构,这是纯HTML页面保证可维护性的第一道防线。

3. 核心模块逐一拆解,每个区块都有讲究

3.1 header:博客门面的写法

<header>里的内容未必多,但它直接决定访客打开页面的第一印象。我的做法是:一个博客主标题用<h1>,一个副标题或简介用<p>,再配一个圆形头像占位。这里有个SEO层面的硬规则:<h1>是页面中最高级别的标题,一份页面最多只能出现一个<h1>,它代表整个页面的主题,搜索引擎基本靠它判断页面内容方向。其余模块的标题,层级从<h2>开始依次向下。

这也就是说博主文章列表里的每篇文章标题,以及侧边栏里各板块的小标题,层级都要比<h1>低。我见过很多人把博主姓名、文章标题、侧边栏标题全用<h1>,整页四五个大标题,语义已经乱了。想一下报纸:头版头条只有一个,其它都是次要新闻,页面标题层级也是这个道理。

副标题我写得比较克制,一行字就够了,多了反而抢主标题的戏。头像占位用一个带文字和圆形的div实现,后面你想换成真人头像,把这块代码替换成<img>标签即可。

3.2 nav:用锚点实现页面内跳转

导航菜单我用<ul><li>组织,语义清晰,而且后面加样式也方便。菜单项分别是“首页”“文章”“关于我”“联系”,每个链接指向页面内部对应的锚点区域:<a href="#home"><a href="#articles"><a href="#about"><a href="#contact">。这些id对应页面上某个区块的id属性值,点击链接后浏览器会自动滚动到对应区域,整个跳转过程不需要任何JavaScript参与。

锚点链接是纯HTML页面里少有的“自带交互”功能,完全由浏览器原生支持。但写它有两个硬性约束:第一,id值在整个页面内必须唯一,不能有两个id="about";第二,id命名建议用小写英文加连字符,比如article-list,比直接用中文或带空格的名字兼容性好得多,也不会在URL解析时出问题。我实际写页面的时候,发现浏览器对id大小写不敏感,但很多编辑器和代码检查工具是敏感的,所以干脆统一小写,省得后面踩坑。

3.3 main文章区:一篇文章块该包含什么

文章列表是整个博客页的核心内容区。每个文章条目我用<article>包裹,里面放三样东西:文章标题用<h3>、发布日期用<time>、内容摘要用<p>,最后加一个“阅读全文”链接。一个<article>代表一篇完整、可独立分发的内容块,非常适合做博客文章的容器。

日期这块有个细节很多人没注意:建议用<time datetime="2024-11-28">2024年11月28日</time>这种方式写。datetime属性能给机器提供标准格式的时间,搜索引擎能正确识别;用户看到的是友好中文日期,机器读到的是结构化时间,两全其美。直接用一段“发布时间:2024/11/28”也不是不行,但既然HTML5提供了<time>标签,用上也就是多写一个属性的功夫,规范一点总没错。

摘要部分我刻意压到一到两句话。太长的摘要会让页面显得臃肿,用户滑半天看不到一篇完整文章结构。末尾的“阅读全文链接”是必备的,它暗示文章还有后续内容。虽然是静态页面,链接暂时指向#,但后面接上真实路径只需改一处。注意#在HTML里是“空链接”的常见写法,但严格来说指向自身不是有效交互,所以我在代码里特意加了个read-more类名,将来切换时也方便。

3.4 aside侧边栏:把页面信息量做足

<aside>用来放与主体内容关系没那么紧密、但能提升页面价值的信息。我在侧边栏放了三个组件:博主名片、热门文章列表、标签云。

博主名片是一张小卡片,里面放头像占位和一段个人简介。真实博客里,这里还要放社交账号链接,比如GitHub、微博、公众号。纯HTML阶段先用简单文字占位,后续扩展成链接列表很容易。

热门文章列表复用文章列表的写法,但每条更短,只放标题链接。

标签云是一组<a>链接,每个标签表示一个内容分类。标签的作用是聚合相关文章,让访客点击某个标签就能看到同类内容。纯静态页面只能把每个标签链接指向空地址,但我用CSS给标签加了底色、圆角和内边距,视觉上已经很有博客那味儿了。这里有个小建议:标签文字尽量短,控制在2到6个字之间,太长的标签在云布局里容易折行、破坏对齐。

3.5 footer页脚:页面的最后一环

页脚用<p>包裹“© 2024 阿泽的个人博客”这类版权文字,需要的话再加一句个人签名。这里有个编码细节我吃了不少苦头——版权符号©,在HTML里直接输入这个字符也没问题,但如果你的编辑器偶尔会把文件编码搞乱,就极容易显示成乱码。稳妥的做法是用实体写法&copy;,纯文本形式,不管什么编码环境都不会出错。同理,»这个箭头符号也可以写成&raquo;,纯文本更安全。

页脚内容真不多,但它是页面完整性的最后一环。见过不少页面内容往下滑到头,页面突然空白断掉,没有任何收尾信息,体验非常不好。哪怕只写一行“用纯HTML手工搭建”,也给了访客一个明确的结束感。

4. 完整可运行代码,直接复制就能用

4.1 纯HTML个人博客页面完整代码

下面的代码是一个完整的HTML文件,把前面所有思路落地。你把它复制到一个文本编辑器里,保存为index.html,双击用浏览器打开就能看到效果。

<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>记录与分享 - 阿泽的个人博客</title> <style> /* 全局重置 */ * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, sans-serif; background: #f5f6f8; color: #333; line-height: 1.6; } /* 页首 */ header { background: #2c3e50; color: #fff; padding: 40px 20px; text-align: center; } header h1 { font-size: 32px; margin-bottom: 8px; } header p { color: #aab; font-size: 14px; } /* 导航 */ nav { background: #34495e; } nav ul { list-style: none; display: flex; justify-content: center; gap: 30px; padding: 12px 0; } nav a { color: #fff; text-decoration: none; font-size: 15px; padding: 4px 8px; border-radius: 4px; } nav a:hover { background: #f39c12; color: #2c3e50; } /* 主体布局 */ .wrapper { max-width: 1100px; margin: 0 auto; display: flex; gap: 20px; padding: 20px; flex-wrap: wrap; } main { flex: 1; min-width: 280px; background: #fff; border-radius: 8px; padding: 20px; } main h2 { font-size: 22px; border-bottom: 2px solid #f39c12; padding-bottom: 6px; margin-bottom: 18px; } article { background: #fafafa; border-radius: 6px; padding: 16px; margin-bottom: 16px; border-left: 4px solid #f39c12; } article h3 { font-size: 18px; margin-bottom: 6px; } article time { color: #999; font-size: 12px; display: block; margin-bottom: 8px; } article p { color: #666; font-size: 14px; } article a.read-more { display: inline-block; margin-top: 8px; color: #f39c12; text-decoration: none; font-size: 14px; } article a.read-more:hover { text-decoration: underline; } /* 侧边栏 */ aside { width: 300px; background: #fff; border-radius: 8px; padding: 20px; } aside h3 { font-size: 16px; border-left: 4px solid #f39c12; padding-left: 10px; margin-bottom: 14px; margin-top: 20px; } aside h3:first-of-type { margin-top: 0; } .profile { text-align: center; margin-bottom: 10px; } .avatar { width: 72px; height: 72px; border-radius: 50%; background: #f39c12; color: #fff; margin: 0 auto 10px; display: flex; align-items: center; justify-content: center; font-size: 28px; font-weight: bold; } .profile p { font-size: 13px; color: #777; margin-top: 8px; } .hot-list { list-style: none; } .hot-list li { margin-bottom: 8px; font-size: 14px; } .hot-list a { text-decoration: none; color: #555; } .hot-list a:hover { color: #f39c12; } .tag-list { display: flex; flex-wrap: wrap; gap: 8px; } .tag-list a { display: inline-block; background: #eef2f7; color: #2c3e50; border-radius: 12px; padding: 4px 12px; font-size: 12px; text-decoration: none; } .tag-list a:hover { background: #f39c12; color: #fff; } /* 页脚 */ footer { background: #2c3e50; color: #aaa; text-align: center; padding: 20px 0; margin-top: 20px; } /* 移动端适配 */ @media (max-width: 768px) { .wrapper { flex-direction: column; } aside { width: 100%; } nav ul { flex-wrap: wrap; gap: 12px; } } </style> </head> <body> <!-- 页首区域 --> <header> <h1>记录与分享</h1> <p>阿泽的个人博客 - 写代码,也写生活</p> </header> <!-- 导航菜单 --> <nav> <ul> <li><a href="#home">首页</a></li> <li><a href="#articles">文章</a></li> <li><a href="#about">关于我</a></li> <li><a href="#contact">联系</a></li> </ul> </nav> <!-- 主体内容区 --> <div class="wrapper"> <!-- 文章列表 --> <main id="articles"> <h2>最新文章</h2> <article> <h3>用纯HTML写一个个人博客页面,需要注意什么?</h3> <time datetime="2024-11-28">2024年11月28日</time> <p>很多人觉得纯HTML页面就是标签的堆叠,其实不然。一个能让浏览器正常展示、结构清晰、方便后期改造的静态页面,写起来有非常多细节。</p> <a href="#" class="read-more">阅读全文 »</a> </article> <article> <h3>语义化标签到底有什么用</h3> <time datetime="2024-11-20">2024年11月20日</time> <p>header、main、article、aside、footer……这些标签不是用来替代div的花架子,它们的语义化价值体现在可维护性、无障碍访问、SEO等多个维度。</p> <a href="#" class="read-more">阅读全文 »</a> </article> <article> <h3>Flex布局学习笔记:两栏博客布局</h3> <time datetime="2024-11-10">2024年11月10日</time> <p>两栏布局是博客页面最经典的形态。用Flex实现两栏布局,关键就三行代码,但理解行为背后的原理,能帮你少踩很多坑。</p> <a href="#" class="read-more">阅读全文 »</a> </article> </main> <!-- 侧边栏 --> <aside id="about"> <div class="profile"> <div class="avatar">泽</div> <h3>关于博主</h3> <p>95后程序员,热爱前端开发,喜欢分享技术学习笔记和生活随笔。</p> </div> <h3>热门文章</h3> <ul class="hot-list"> <li><a href="#">HTML入门需要掌握哪些标签</a></li> <li><a href="#">CSS选择器优先级详解</a></li> <li><a href="#">2024年值得关注的前端方向</a></li> </ul> <h3>标签分类</h3> <div class="tag-list"> <a href="#">HTML</a> <a href="#">CSS</a> <a href="#">JavaScript</a> <a href="#">前端</a> <a href="#">学习笔记</a> <a href="#">生活随笔</a> </div> </aside> </div> <!-- 页脚区域 --> <footer id="contact"> <p>&copy; 2024 阿泽的个人博客 | 用纯HTML手工搭建</p> </footer> </body> </html>

4.2 代码里的关键设计点

这份代码用box-sizing: border-box做了一个全局重置。这一行的意思,是让所有元素的宽度计算包含内边距和边框,而不是默认的content-box。很多初学者被宽度算不准的问题折磨,根源就是没加这行。加了之后,你写width: 300px就说的是整个盒子的宽度,不会因为加了padding就撑破布局。

nav ul用Flex做了水平导航,justify-content: center让菜单居中,gap控制菜单间隙。这里我没有用margin来分开菜单项,而是用gap,好处是不用担心最后一个菜单项多出多余的右边距。Flex的gap属性在现代浏览器里已经非常成熟,放心用。

页面主体用.wrapper做了一层限制宽度为1100px的容器,再配合margin: 0 auto水平居中。这里必须解释一下flex-wrap: wrap的作用:当屏幕宽度不够时,主体和侧边栏默认行为是一左一右排列,可能挤得很窄,加了wrap后,侧边栏会自动换行落到主体下方,配合媒体查询做到移动端单栏显示,这就让页面在手机上也有一个可接受的布局。

媒体查询那段是移动端适配的关键。@media (max-width: 768px)的意思是“当视口宽度小于等于768像素时,应用花括号内的样式”。这里我只做了三件事:把.wrapper改成纵向排列、让aside宽度占满整行、让导航菜单允许换行。三行代码,解决了手机打开页面时两栏挤成一团的问题。

5. 写完之后这样自查,常见问题逐个说清

5.1 浏览器显示不一致,先查这三个地方

纯HTML页面理论上在任何现代浏览器里都能正常解析,但为什么你写的页面有时候在Chrome里好好的,Edge里就乱了?我排查下来,多半是这三个原因。

第一,标签没有闭合。浏览器对未闭合标签有一定容忍度,但不同浏览器容错策略不一样,恢复出来的DOM结构可能不同,样式跟着就乱了。检查办法很笨但有效:用VS Code打开文件,如果标签名下面出现黄色波浪线,基本就是没闭合或写错了。

第二,CSS里用了没有加浏览器前缀的新特性。这个问题在这份代码里基本不存在,因为只用了Flexbox和基本盒模型,这两个在主流现代浏览器里的支持度非常稳定。但如果你往里面加新东西,比如gap用在Grid布局之外的场景,就要小心兼容性。

第三,页面引用了外部字体或图标库,某个浏览器因为网络或权限问题没加载到,布局就不一样了。纯HTML页面如果依赖外链,就要提前把“外链拿不到”的情况考虑进去,做好字体回退。比如代码里font-family我写了四个候选字体,第一个不行就换下一个,目的就是防止某个系统缺字体导致页面显示异常。

5.2 页面显示乱码,九成是编码问题

网页显示乱码,核心矛盾是“文件实际编码”和“浏览器猜测编码”不一致。你保存文件时用的如果不是UTF-8,而<meta charset="utf-8">又声明了UTF-8,浏览器按UTF-8去解析一个GBK文件,必然出错。解决办法:文件务必用UTF-8格式保存。在VS Code里,看右下角编码按钮,如果是“UTF-8”就没事,如果显示“GBK”之类的,点开选择“通过编码保存”,再选UTF-8。

这里还有个偏门细节:如果代码里有中文引号、中文括号等全角字符,更要确保文件编码正确。我自己测试的时候,在部分编辑器里全角符号会被自动转成半角,甚至直接吞掉,导致页面出现莫名的排版错乱。所以写完代码后,我习惯用浏览器开一遍,再检查一下有没有全角半角混用的问题。

5.3 锚点跳转不好使,检查id唯一性

页面写好后,你点击导航菜单,页面没有滚动到对应区块,那就是锚点失效了。常见原因就两类:一是目标区块上压根没写id属性,链接没有目标可跳;二是页面里有重复的id值,浏览器不知道该跳哪个。用浏览器开发者工具按Ctrl+F搜索id="about",看看查出来几处,如果不止一处,改掉多余的那个。

还有一个经常被忽略的点:href="#about"只对页面内元素的id生效,对name属性是不响应的。老HTML里用<a name="">做锚点的写法在HTML5已经过时了,别再用。我见过不少人把nameid混在一起用,结果页面怎么点都不跳。

5.4 手机打开很丑,就是没写媒体查询

我这份代码如果少了@media (max-width: 768px)那段,手机上打开就是两栏挤在一起,侧边栏宽度只有300px被硬压缩,字都看不清。加了媒体查询后,窄屏下面自动变单栏,页面阅读体验才正常。

验证办法很简单:在Chrome里按F12打开开发者工具,点左上角第二个图标切换到移动设备模拟,顶部可以选iPhone、安卓等预设机型,刷新看看布局变化。如果发现侧边栏没有落到正文下方,检查.wrapperflex-direction: column是否生效,再确认媒体查询里max-width写的是不是768px。

5.5 想要换成自己的内容,最省力的改法

页面框架做好之后,替换内容是最常见的需求。我建议按这个顺序改:先改<header>里的博客名和副标题,再改导航菜单里四个链接的文字和锚点目标,然后改<main>里的文章标题、日期、摘要,接着替换侧边栏的博主简介、热门文章、标签,最后把页脚版权年份改成当前年份。每一步都只动文字,不碰结构,不容易出错。

如果文章数量变多,不必在页面上堆砌太多篇幅,可以做成“文章列表只展示最新几篇”,像代码里写三条就够。真实博客是靠后台动态渲染这个区块,静态页面阶段先展示三到五条,内容完整又不显得臃肿。

我实际写这种页面写了很多次,最大的体会是:纯HTML不是做不出好东西,而是不能被“纯”字束缚住思路。把HTML结构写清楚,用内嵌CSS做好样式和响应式,页面已经能很好看了。等哪天你想给它加评论、加搜索、加后台管理,再把这个静态页当成骨架,往里面填动态逻辑也不迟。至少这份纯HTML的底子打得正,后面不管接什么框架,都不会被结构拖后腿。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询