
做个人网页这件事最劝退新手的从来不是写代码而是写完了给谁看。本地双击 HTML 文件能看到效果可一旦要把链接发给朋友、印在名片上、贴在海报角落就卡住了——没有服务器没有域名也不想为了一张只有自己看的页面去买空间。我最早也是这么过来的后来固定在GitHub Pages上做静态网页托管只要有网页源码推上去就是一个可以对外访问的网址全程零成本。这篇内容就是把这套流程从头到尾拆开讲从一份能跑的html 网页制作骨架开始到仓库怎么建、文件怎么传、Pages 怎么开、二维码制作怎么把网址变成一张能扫的图最后把上线后真正会踩的坑一个个列出来。适合完全没碰过 Git 的新手也适合已经会写前端、只是没做过部署的朋友源码部分我会给可直接抄的示例。1. 方案选型为什么个人网页优先考虑 GitHub Pages1.1 先把静态和动态这条线划清楚很多人一上来就问能不能做登录、能不能存数据这其实是在问动态站。静态站指的是服务器只负责把 HTML、CSS、JS、图片这些文件原样发给浏览器页面里的一切变化都由浏览器端的 JavaScript 完成。GitHub Pages 就是典型的静态托管它不给你数据库不给你后端进程也不会替你执行任何服务端代码。这个限制听起来很硬但对个人网页来说反而够用。个人主页、作品集、活动落地页、简历页、说明书、小工具页面、文档站本质都是把内容展示出来不需要服务端参与。真正的分界线只有三条要不要用户登录、要不要把用户输入存进数据库、要不要服务端定时跑任务。三条里有一条为真就不该硬上静态托管否则你会花大量时间在绕路上。反过来说如果你的需求是我有一个 HTML 文件想让大家都能打开那静态托管就是最短路径没有之一。它的部署动作本质就是把文件放进一个公开目录理解这一点之后后面所有操作都会变得顺理成章。1.2 几种零成本托管方式的横向对比我把常见的选择拉成一张表方便你按自己的情况对号入座。注意这里比较的是个人小页面场景不是生产级业务。方式成本上手难度是否需要自己写部署脚本适合谁本地 HTML 文件直接分享零极低不需要只给自己看、临时预览GitHub Pages零低到中不需要推送即部署有源码、想要固定网址的人通用对象存储静态托管按量计费个人量级几乎为零中视情况已有云账号、要绑自有域名自购云服务器每月固定支出高需要明确要做动态站的人从这张表能看出关键差异GitHub Pages 的部署动作和版本管理是同一套东西你把代码推上去站点就更新了不用额外学一套发布流程。对于我以后还会不断改这个页面的人来说这一点省下的时间非常可观。注意静态托管只负责把文件发出去。页面里如果引用了自己写的接口地址那个接口需要另外找地方部署不要以为开了 Pages 就万事大吉。1.3 选它之前你需要接受的两个前提第一个前提是公开性。免费账户下的 Pages 站点是公开可访问的任何人拿到网址都能打开。所以不要把身份证照片、私人联系方式、内部文档塞进仓库也不要把密钥、令牌这类东西写进 JS 文件——前端代码在浏览器里是明文可见的注释、变量、请求地址全都能被看到。第二个前提是异步生效。你推送代码之后平台需要构建和分发通常几分钟内完成。急着刷新看不到更新是常态不代表失败。我习惯的做法是推完之后先去做别的事十分钟后回来一次性验证比每隔十秒刷新一次高效得多。把这两点提前说清楚是为了避免后面产生为什么我的隐私没了为什么改了没反应这类误会。接受它们之后剩下的流程就非常顺了。2. 网页源码准备从能打开到能上线2.1 一个最小可用页面的骨架标题里特别提到需要有网页源码这是整件事的地基。没有源码后面全是空谈。我建议哪怕你只想放一张图也老老实实写一个结构完整的index.html因为它决定了站点能不能被正确识别为首页。下面是我常用的最小骨架直接可以拿去改!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title我的个人主页/title meta namedescription content个人作品与联系方式汇总页 link relstylesheet href./css/style.css /head body header classsite-header h1你好我是某某/h1 p classsubtitle前端练习 / 手工作品 / 摄影记录/p /header main classcontent section classcard h2关于我/h2 p这里放一段自我介绍两三句话就够了。/p /section section classcard h2作品/h2 ul lia href./works/demo1.html作品一/a/li lia href./works/demo2.html作品二/a/li /ul /section /main footer classsite-footer p联系邮箱exampleexample.com/p /footer /body /html骨架里有几个容易被忽略但很关键的点。meta charsetUTF-8决定中文会不会变成乱码缺了它页面标题和正文可能全是一堆方块。meta nameviewport决定手机上打开时是不是按桌面宽度缩放缺了它手机上字小到看不清。langzh-CN看着没用但影响浏览器对断词和朗读的处理写上不亏。再配一个最简单的样式表让页面至少不至于难看:root { --ink: #222222; --muted: #666666; --line: #e5e5e5; } * { box-sizing: border-box; } body { margin: 0; font-family: -apple-system, PingFang SC, Microsoft YaHei, sans-serif; color: var(--ink); line-height: 1.7; background: #fafafa; } .site-header, .content, .site-footer { max-width: 720px; margin: 0 auto; padding: 24px 16px; } .card { background: #ffffff; border: 1px solid var(--line); border-radius: 10px; padding: 16px 20px; margin-bottom: 16px; } .subtitle { color: var(--muted); }这套代码的特点是没有依赖任何外部框架不会因为某个 CDN 挂了导致页面全白。新手最常犯的错是从某个现成的html css 网页制作成品里复制代码结果引用了十几个外链文件一上线就各种加载失败。我的建议是先用纯手写跑通一次确认部署链路没问题之后再考虑加框架。2.2 目录结构与命名约定源码放得乱不乱直接决定你后续维护愿不愿意继续改。我推荐的目录结构是按类型分而不是按页面分my-site/ ├── index.html ├── 404.html ├── css/ │ └── style.css ├── js/ │ └── main.js ├── images/ │ └── avatar.png └── works/ ├── demo1.html └── demo2.html这样分的好处是当你需要改全局样式时只需要动css/style.css一个文件。如果按页面分目录每个页面一份样式改一个圆角要改五次迟早会改漏。命名上有几条硬经验全部用小写字母单词之间用短横线连接不要用中文、空格和特殊符号。原因很实在——服务器环境普遍区分大小写你本地写Images/avatar.png能打开传上去之后写成images/avatar.png就 404 了这类问题排查起来特别浪费时间。空格更麻烦浏览器会把空格编码成%20手工拼接链接时极易出错。首页文件名必须叫index.html。这不是建议是约定服务器收到目录请求时会默认找这个文件。你叫home.html、main.html都不会被自动加载访问根路径就是 404。2.3 相对路径与绝对路径样式失效八成在这这是新手掉坑率最高的地方我单独拎出来讲。路径写法有两种相对路径./css/style.css、../images/a.png根路径/css/style.css完整地址https://example.com/css/style.css问题出在根路径上。很多人本地用编辑器预览时写/css/style.css没问题因为本地服务的根目录就是项目根目录。但部署到https://用户名.github.io/仓库名/这种子路径下根变成了域名根而不是仓库根/css/style.css会去找https://用户名.github.io/css/style.css直接 404。所以给个人页面写代码时我统一用相对路径./css/style.css表示当前文件所在目录下的 css 文件夹../表示上一级。这样无论页面挂在域名根还是子目录都能正确找到资源。提示如果确实需要根路径比如做单页应用的路由可以在 HTML 的 head 里加一段base href./让所有相对链接以当前目录为基准解析。但这是兜底手段能改路径就别用它。另外提醒一句图片引用的路径、JS 里动态拼接的路径、CSS 里background: url(...)的路径三处都要检查。我见过太多次样式加载了但背景图没了最后发现是 CSS 里的相对路径基准是 CSS 文件本身的位置而不是 HTML 的位置所以要从css/目录往上跳一级写成../images/bg.png。3. 上传到 GitHub 并开启 Pages 的完整流程3.1 仓库命名与可见性怎么选先注册账号然后新建仓库。仓库名这里有个分岔口选错了会影响最终网址的形态。如果仓库名写成用户名.github.io比如zhangsan.github.io那么站点地址就是https://zhangsan.github.io/干净利落一个账号只能有一个这样的仓库。如果仓库名是别的东西比如my-site地址就变成https://zhangsan.github.io/my-site/。我的建议是先随便建一个普通仓库跑通流程确认自己会用之后再决定要不要开那个同名仓库做主页。因为同名仓库一旦建错改名之后缓存和链接都会有残留容易让人怀疑人生。可见性方面免费账户的 Pages 只能从公开仓库发布部分付费方案支持私有仓库发布具体以平台当前政策为准这个会变不要照抄旧教程。所以直接选公开即可。公开不代表你的草稿会被人看到——仓库里可以放.gitignore排除本地笔记、原始设计稿这些不想公开的东西。3.2 网页端拖拽上传零基础首选如果完全没用过 Git第一条路就是网页端上传五分钟能走完。打开新建好的仓库页面点击Add file选择Upload files。把整个项目文件夹里的文件拖进上传区。注意拖的是文件本身不是外面那一层文件夹否则会多出一层嵌套目录。在下方Commit changes区域写一句提交说明比如首次提交主页与样式。点击绿色按钮确认提交。上传完成后仓库文件列表里应该能直接看到index.html在根目录而不是在某个子文件夹里。这一条极其重要——如果index.html被套在my-site/index.html里Pages 是找不到它的访问根路径必然是 404。上传时常见的错误就是把文件夹拖进去了导致多一层。发现多了一层不要紧点进文件用重命名功能把路径里的多余目录去掉就行。这种方式适合文件少、改动不频繁的情况。它的缺点也很明显每次改一个字符都要重新上传整个文件时间长了会烦。3.3 Git 命令行上传长期维护更省事只要你打算持续维护这个页面就值得花二十分钟学几条命令。装好 Git 之后在项目目录里依次执行# 初始化本地仓库 git init # 把所有文件加入暂存区 git add . # 提交一次快照 git commit -m feat: 初始版本包含首页与样式 # 把默认分支名改成 main git branch -M main # 关联到远程仓库地址换成你自己的 git remote add origin https://github.com/你的用户名/你的仓库名.git # 首次推送 git push -u origin main第一次推送会要求登录。用浏览器弹出的授权流程走一遍即可授权完成后本地会保存凭据后续推送不用反复输入。之后每次修改只需要三条命令git add . git commit -m style: 调整卡片间距 git push我特别建议养成写清楚提交说明的习惯。三个月后你回头看fix: 修复移动端标题溢出比更新有用一百倍因为你能一眼看出哪次改动引入了问题也方便回退到某一个已知正常的版本。注意仓库根目录会有一个隐藏的.git文件夹它是版本记录本体不要手动删除也不要用别的方式覆盖它否则历史记录就断了。3.4 Pages 开关与分支目录配置文件传上去之后站点不会自动开启需要手动打开一次开关。进入仓库页面找到Settings左侧菜单里找到Pages。在Source处选择Deploy from a branch然后Branch选main或者你实际使用的主分支Folder选/ (root)也就是根目录保存之后页面顶部会提示站点正在构建。构建完成后同一页面会显示你的访问地址。这里有个细节值得说清楚Folder选根目录还是/docs目录决定了平台去哪找你的 HTML。选/docs是一种常见的组织方式好处是源码和成品分开放适合源码需要编译的项目。但如果你只是手写静态页选根目录最省事少一层心智负担。另外如果项目里存在.nojekyll文件一个内容为空的文件平台会跳过某套静态站点生成器的处理流程。这对目录名以下划线开头的项目很重要因为那套生成器会把_assets这类目录直接忽略掉导致资源全丢。手写项目里放一个.nojekyll是无害的我一般都会加上图个安心。3.5 首次部署后的验证清单构建完成后别急着发朋友圈按这个清单走一遍检查项期望结果出问题先看哪里根地址能否打开看到首页内容index.html是否在根目录样式是否生效布局正常、不是纯文字堆叠路径是否写成了根路径图片是否显示全部正常加载文件名大小写是否一致手机打开是否正常字不糊、不横向滚动viewport标签是否漏了子页面链接是否可用点击能跳转相对路径层级是否正确一个很实际的建议用手机流量不是同一个 Wi-Fi打开一次。局域网环境和外部环境的差异有时候能暴露出你本地完全看不到的问题比如某个资源其实加载失败但被浏览器缓存掩盖了。4. 二维码制作把网址变成可扫码入口4.1 二维码到底是怎么把一串网址装进去的二维码的本质是一种二维条码它把数据按特定规则编码成一堆黑白小方块。你不需要理解编码的全部数学过程但需要理解三个参数因为它们直接决定扫得出来还是扫不出来。第一个是数据内容也就是你要写进去的那串字符。这里要注意二维码里存的是纯文本扫出来是什么就是什么它不会自动补https://。所以生成时必须写完整的地址否则扫码工具会当成一段普通文字而不是链接。第二个是纠错等级。二维码带有冗余校验信息允许图案被遮挡或磨损一部分还能被正确读取。等级从低到高大致对应可损坏面积的小、中、较大、大四档冗余越多同样的数据需要占用的图形面积就越大。第三个是静区也就是二维码四周必须留出的空白边距。规范里推荐至少留出四个模块宽度的白边。很多人做美化时把白边裁掉或者把二维码贴在深色背景上结果扫半天扫不出来问题就出在这。理解了这三个参数后面选工具、调参数、做美化都有了判断依据而不是靠碰运气。4.2 版本、纠错等级与容量怎么选二维码有不同的版本版本越高图形越大能装的数据越多。版本 1 是 21×21 的方块矩阵之后每升一版边长增加 4 个模块。容量和纠错等级是互相挤占的关系同样大的图形纠错等级越高能装的数据越少。下面这张表是常用的几档参考值单位是字节一个英文字符算 1 字节版本矩阵尺寸低档纠错中档纠错较高纠错高档纠错121×211714117225×2532262014329×2953423224433×3378624634537×37106846044拿我们的实际场景算一下一个形如https://zhangsan.github.io/my-site/的地址长度大约 40 个字符用版本 3 的中档纠错就够了还有余量。如果有人用短一些的用户名和仓库名比如https://z3.github.io/s/长度不到 25 个字符版本 2 就够。选择策略很简单能用低纠错就用低纠错但前提是二维码要印在干净、平整、光照良好的位置。如果要印在名片、贴纸、包装上可能被手指摸、被折、被油污覆盖那就把纠错提升一档牺牲一点容量换可靠性。这个取舍很清楚不需要纠结。提示不要盲目追求版本越高越保险。版本越高图形越密在小尺寸打印或低分辨率屏幕上模块可能糊成一团反而更难扫。目标是刚好够用。4.3 本地批量生成Python 实操在线生成工具很多打开网页输网址就能出图适合偶尔做一张。但如果你要管理多个页面、多张二维码或者要给一批链接都生成图本地脚本会省掉大量重复劳动。以 Python 为例装好依赖后是这样用的pip install qrcode[pil]单张生成的核心代码import qrcode url https://zhangsan.github.io/my-site/ qr qrcode.QRCode( versionNone, # 自动选择最小可用版本 error_correctionqrcode.constants.ERROR_CORRECT_M, box_size10, # 每个模块 10 像素 border4, # 静区宽度按规范留 4 模块 ) qr.add_data(url) qr.make(fitTrue) img qr.make_image(fill_colorblack, back_colorwhite) img.save(my_site_qr.png) print(已生成数据长度, len(url))几个参数值得展开说。versionNone配合make(fitTrue)让程序自动选最小的够用版本比自己猜版本省事。box_size决定单模块的像素尺寸10 是比较稳的值缩放到 300 像素左右打印很清晰如果你要小尺寸展示可以降到 6 到 8。border4就是前面说的静区别改成 0。如果是一批链接用 CSV 驱动会顺手很多import csv import os import qrcode os.makedirs(output, exist_okTrue) with open(urls.csv, encodingutf-8) as f: reader csv.DictReader(f) # 表头需要包含 name, url 两列 for row in reader: qr qrcode.QRCode( versionNone, error_correctionqrcode.constants.ERROR_CORRECT_M, box_size10, border4, ) qr.add_data(row[url].strip()) qr.make(fitTrue) path foutput/{row[name].strip()}.png qr.make_image(fill_colorblack, back_colorwhite).save(path) print(生成完成, path)跑完之后output目录里就是一批以名称命名的图片直接往文档、海报、PPT 里拖就行。这种做法的好处是留痕链接改了你重新跑一次脚本所有二维码同步更新不用挨个去在线工具里重做。4.4 美化二维码的边界在哪很多人想让二维码带上自己的头像、配色、logo。技术上完全可以实现但要理解代价你在二维码上盖的每一块东西都是在消耗纠错余量。如果选的是中档纠错理论冗余比较充裕在中心位置盖一个面积不大的 logo 通常没问题。但如果选的是低档纠错再盖 logo 就很容易扫不出来。另外一个常被忽视的点是对比度二维码靠黑白模块的明暗差异被识别浅灰配浅蓝、白底配浅黄这类搭配肉眼看挺好看摄像头读起来很吃力。我自己的做法是分两步先生成一张纯黑白的图实测能扫再在此基础上做美化每改一步都用手机实测一次。听起来笨但比全做好了才发现扫不出来要高效得多。注意美化后一定要用不同设备试扫。手机屏幕扫一遍打印出来扫一遍不同品牌的扫码工具各试一次。我在浅色背景上吃过亏屏幕上好扫打印出来就废了。4.5 生成后必做的三项验证二维码做完别直接就用了三项验证能帮你省掉后面被追问的尴尬。第一项是扫码结果的字符串比对。别只看跳转成功了要看清扫出来的文本和你的目标地址是不是一字不差。多一个斜杠、少一个字符可能就跳到别的路径去了。第二项是缩放测试。把图片缩到你实际使用的最小尺寸——比如名片上的 2 厘米见方——再扫一遍。很多二维码在大图时没问题缩到实印尺寸就糊了原因通常是模块尺寸太小或者四周白边被裁掉了。第三项是弱光测试。把手机屏幕亮度调到较低在室内普通照明下扫一次。如果这一关能过实际使用中的容错空间就比较大了。5. 上线后常见问题与排查实录5.1 页面 404 与白屏速查表站点上线后遇到的绝大多数问题都逃不出下面这几类。我把它整理成一张速查表出问题时从上往下核对现象最可能的原因解决动作访问根地址显示 404根目录没有index.html把首页文件移到仓库根目录首页能开样式全丢CSS 路径写成了根路径/css/...改成./css/...图片显示裂图文件名大小写不一致统一改为小写并同步引用页面一片白JS 报错中断了渲染打开控制台看报错信息子页面 404相对路径层级算错检查../的层数手机上看排版错乱缺viewport标签在 head 里补上白屏这一类我要单独说一句静态页面白屏九成以上是 JavaScript 执行报错。可能是某个变量的名字写错了可能是引用了没加载成功的库。打开浏览器开发者工具看控制台里的第一条红色报错基本就能定位。养成先看控制台的习惯能省掉大量瞎猜的时间。另外还有一个隐蔽的情况页面引用了外部字体或图标库那家服务响应慢或者不可用导致文字长时间不显示。诊断方法是在网络面板里看有没有一直处于等待状态的请求。这也是我一直推荐手写纯本地资源的原因之一依赖越少故障面越小。5.2 二维码扫不出来的六种原因二维码这边的问题集中在明明生成了就是扫不出来按出现频率排一下数据太长地址特别长时程序会选高版本图形密集。适当缩短路径或者用自己域名的短路径。静区被裁为了排版好看把四周白边切掉了。补回至少四模块的空白。对比度不足深色底配深色码、浅色底配浅色码摄像头难以分辨。回到黑白。尺寸太小印刷后单模块小于约 0.5 毫米摄像头解析困难。放大二维码或降低版本。中心覆盖过多logo 面积超过纠错余量。缩小 logo或把纠错等级提一档重新生成。表面反光或有纹理贴在有光泽的材质或者花纹背景上光线干扰严重。换位置或者加一块纯白底。我踩过最典型的一次是把二维码放在一张有木纹的背景图上屏幕上扫得挺好打印到牛皮纸上就完全读不出来。后来加了一个白色圆角矩形做底衬问题立刻消失。所以给二维码一个安静的白底这条比什么美化技巧都管用。5.3 改完代码但页面没变怎么办这是最让人心慌的一类问题明明改了文件刷新页面还是旧样子。排查顺序是这样先确认推送是否真的成功。打开仓库页面看文件内容是不是已经更新了。如果仓库里还是旧代码那是本地推送环节的问题跟托管无关。再确认构建是否完成。回到 Pages 设置页看有没有构建中的提示或者失败记录。首次构建和批量改动时等待时间会比平时长一些。最后考虑缓存。浏览器会缓存 CSS 和 JS静态文件尤其明显。这时候用无痕窗口打开一次或者强制刷新通常就能看到新版本。如果确认是缓存问题可以在引用样式时加一个版本参数比如./css/style.css?v2改动时把数字往上加能有效绕开缓存。提示不要在同一个页面里既改文件又部署多次然后分不清哪次生效。一次改完、一次推送、一次验证节奏清楚问题也好定位。6. 几个可以立刻用上的扩展玩法6.1 用 404 页面做一次温和的引导在根目录放一个404.html当访问到不存在的路径时平台会自动展示它。这个页面不需要复杂写一句没找到这个页面再给一个返回首页的链接体验就已经比浏览器默认的报错页好很多。有个小技巧是可以在 404 页面里加一段轻量的跳转逻辑把用户导回首页。但要克制不要做成强制跳转否则用户在地址栏里输错一个字符就被弹走感觉会很烦躁。温和的提示加一个链接比强行重定向更舒服。这个页面对应二维码也有用如果你打印出去的二维码对应的页面以后调整了路径旧二维码扫出来会落到 404用户至少还能看到一句人话而不是一个冷冰冰的错误。6.2 给站点加一个自动生成二维码的小页面这是一个挺实用的自用工具做一个本地页面输入框里粘贴网址点一下就在页面上画出对应二维码。实现上可以引入一个轻量的二维码生成库全部在浏览器端完成不需要任何后端。我个人的用法是把它放在站点的一个子路径下比如./tools/qr.html需要做二维码时打开它输入当前页面的地址右键保存图片。这样整条链路都在自己手里不依赖第三方网站的可用性和隐私策略。当然这个页面本身也可以是一个很好的练习项目涉及的输入处理、Canvas 绘制、图片导出都是很典型的前端操作。需要注意的是生成的二维码要留足静区导出的时候别让图片边缘贴着码点。这一点在自己的工具里反而更容易控制因为参数都在代码里明摆着。6.3 长期维护的三个小习惯第一个习惯是给每次改动写清提交说明。这不是形式主义当你半年后回来改页面能靠提交记录快速回忆起上次改了什么、为什么改。我在实际使用中发现只需要一句话就能省下十几分钟的翻代码时间。第二个习惯是把源文件和成品分开管理。手写静态页无所谓但如果你以后引入了构建流程就把源码和产物分目录避免两边混在一起、改了源码忘记重新构建。第三个习惯是每上线一个新页面就顺手生成二维码并归档。在本地建一个qr目录按页面名称命名图片同时留一份对应的链接清单。链接变了重新跑一次脚本覆盖即可不用去翻聊天记录找当初生成的图。这套流程我自己跑了好几年最大的感受是真正的门槛从来不在技术本身而在于一开始有没有把路径和目录这些小事理清楚。路径对了、首页文件位置对了、二维码白边留够了剩下的就是不断往页面里加内容。如果你手上正好有一份写好的源码今晚就能把它变成一个能分享出去的地址顺手再做张二维码贴在你想贴的地方。