尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

原生HTML/CSS/JS打造高性能个人作品集

原生HTML/CSS/JS打造高性能个人作品集 简介这是一份面向前端初学者与个人开发者的设计型实战资源提供一套开箱即用的HTMLCSSJavaScript个人作品集源码助力快速搭建专业级在线作品展示平台。资源共51个文件包含12个HTML页面含首页、作品页、404页等、10个JS脚本涵盖轮播、懒加载、搜索、图标交互等动态功能、4个CSS样式表主样式自定义字体图标配套、9张JPG与6张PNG作品图、3个SVG图标及EOT/TTF/WOFF/WOFF2等多格式字体文件整体压缩包仅4.13MB轻量易部署。已有115人学习下载适合用于求职展示、自由职业接单或技术博客集成。读者可直接运行查看响应式布局与交互动效深入理解目录结构如dist构建输出、archives归档、images资源分类、现代前端资源组织规范并复用其中的tocbot导航、busuanzi统计、remixicon图标库等实用模块。1. 为什么一个“纯静态”的个人作品集反而比用 React/Vue 搭的更难让人记住你花三天用 Vite Tailwind 搭了个炫酷作品集部署到 Vercel链接发朋友圈——结果三个月后没人点开连你自己都记不清首页轮播图第 3 张是什么项目。这不是代码问题是信息密度与用户注意力的错配。真正被 HR、设计总监、技术主管反复打开的个人作品集往往不是框架最潮的那个而是加载快首屏 0.8s、结构清3 秒内看懂你是谁/做什么/有什么成果、可离线关掉 Wi-Fi 仍能翻项目详情、无依赖不靠 CDN、不等 JS 加载完才渲染文字。而 HTML CSS JavaScript 这套“老三样”恰恰是唯一能同时满足这四条硬指标的技术栈。它不追求“现代前端工程化”而是回归本质用语义化标签组织内容用 CSS 控制视觉节奏与呼吸感用轻量 JS 做精准交互增强比如点击项目弹出详情时只加载对应 DOM 片段而非整页重绘。本文不讲“怎么写第一个 div”而是带你从零构建一个可直接部署、SEO 友好、适配宽屏1440px与窄屏375px、带渐进式图片加载与键盘导航支持的个人作品集源码骨架——所有代码可复制即用所有样式参数有明确物理意义所有 JS 行为可预测、可调试、可关闭而不崩 UI。适合刚转行的前端新人快速上线真实作品也适合资深工程师做技术简历的“最小可信载体”。2. 用原生三件套搭作品集为什么选section而不是div为什么prefers-reduced-motion必须写进 CSS2.1 页面骨架从!doctype html到main的 7 层语义结构很多新手一上来就写div classcontainer结果 SEO 抓取不到核心内容屏幕阅读器读成“一堆没名字的盒子”。真正的作品集骨架必须严格遵循 HTML5 语义层级。我们不用框架但用标准!doctype html html langzh-cn head meta charsetutf-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta namedescription content前端工程师张三的个人作品集专注响应式开发与性能优化 title张三 | 前端作品集/title link relstylesheet hrefstyle.css /head body header rolebanner nav aria-label主导航 ul lia href#about关于我/a/li lia href#projects作品/a/li lia href#contact联系/a/li /ul /nav /header main rolemain section idabout aria-labelledbyabout-heading h1 idabout-heading我是张三/h1 p专注前端性能与无障碍访问的实践者/p /section section idprojects aria-labelledbyprojects-heading h2 idprojects-heading近期作品/h2 !-- 项目卡片将在此插入 -- /section section idcontact aria-labelledbycontact-heading h2 idcontact-heading联系我/h2 form idcontact-form label forname姓名/label input typetext idname required button typesubmit发送/button /form /section /main footer rolecontentinfo pcopy; 2024 张三. 所有代码开源于 GitHub./p /footer script srcscript.js defer/script /body /html注意role属性不是装饰是给辅助技术如读屏软件提供上下文的关键。aria-labelledby明确绑定标题与区块避免“section 1”“section 2”这种无意义播报。nav包裹导航而非div classnav让 ATAssistive Technology知道这是“主导航”不是普通容器。2.2 CSS 布局策略用clamp()替代媒体查询用aspect-ratio控制卡片比例1440px 宽屏不是“大屏”而是设计师交付稿的基准宽度375px 不是“小屏”而是 iPhone SE 的物理视口。硬写media (min-width: 1440px)会导致在 1600px 屏幕上字体突然变大、留白失控。正确做法是用clamp()实现流体缩放/* style.css */ :root { --text-base: clamp(1rem, 2.5vw, 1.25rem); /* 最小 16px最大 20px中间按视口宽度线性缩放 */ --spacing-unit: clamp(0.5rem, 1.2vw, 0.75rem); } body { font-size: var(--text-base); line-height: 1.6; margin: 0; color: #333; } .project-card { aspect-ratio: 4 / 3; /* 无论图片原始尺寸如何卡片始终维持 4:3 比例 */ width: 100%; max-width: 360px; border-radius: 8px; overflow: hidden; box-shadow: 0 4px 12px rgba(0,0,0,0.08); }aspect-ratio是现代 CSS 的关键突破——它让卡片高度不再依赖图片加载完成避免布局抖动layout shift。配合object-fit: cover图片自动裁切居中无需 JS 计算宽高比。2.3 JavaScript 交互原则只增强不接管只加载不渲染很多作品集用 JS 动态生成全部 HTML结果搜索引擎抓到空main用户禁用 JS 后页面一片空白。我们的 JS 定位非常明确仅增强已有 HTML 的交互体验且所有功能在 JS 失效时降级为原生行为。例如项目卡片展开详情// script.js document.addEventListener(DOMContentLoaded, () { // 仅对已存在的 .project-card 添加点击监听 document.querySelectorAll(.project-card).forEach(card { card.addEventListener(click, function(e) { // 阻止默认跳转如果卡片内有 a 标签 if (e.target.tagName A) return; const detailId this.dataset.detailId; const detailEl document.getElementById(detailId); // 只显示/隐藏不创建新 DOM if (detailEl) { detailEl.classList.toggle(visible); // 触发 aria-expanded 状态更新 const btn this.querySelector([aria-expanded]); if (btn) { btn.setAttribute(aria-expanded, detailEl.classList.contains(visible)); } } }); }); // 键盘支持Enter 或 Space 键触发展开 document.addEventListener(keydown, e { if (e.code Enter || e.code Space) { const focused document.activeElement; if (focused focused.classList.contains(project-card)) { focused.click(); } } }); });逻辑说明dataset.detailId从 HTML 中读取如div classproject-card>picture source media(min-width: 1440px) srcsetprojects/project-1-1440w.webp 1x, projects/project-1-1440w2x.webp 2x typeimage/webp source media(min-width: 768px) srcsetprojects/project-1-768w.webp 1x, projects/project-1-768w2x.webp 2x typeimage/webp source srcsetprojects/project-1-375w.webp 1x, projects/project-1-375w2x.webp 2x typeimage/webp !-- fallback for non-WebP browsers -- img srcprojects/project-1-375w.jpg srcsetprojects/project-1-375w.jpg 1x, projects/project-1-375w2x.jpg 2x alt项目‘数据看板’界面截图 width375 height250 loadinglazy decodingasync /picture参数说明width/height必填防止布局抖动浏览器据此预留空间loadinglazy延迟加载非首屏图片decodingasync告诉浏览器“这张图解码可以慢一点别卡住页面渲染”srcset中1x/2x对应设备像素比DPR而非屏幕宽度——iPhone 14 Pro 的 DPR 是 3但2x已覆盖绝大多数高 DPI 设备。3.2 字体加载用font-display: swap防止 FOIT用size-adjust保行高自定义字体如思源黑体、HarmonyOS Sans加载慢会导致文字消失FOIT或突然跳动FOUT。font-display: swap是底线font-face { font-family: HarmonyOS Sans; src: url(./fonts/HarmonyOS_Sans_W3.woff2) format(woff2); font-weight: 300; font-style: normal; font-display: swap; /* 文字先用系统字体显示字体加载完再替换 */ size-adjust: 100%; /* 防止替换后行高突变 */ }关键细节font-display: swap不是万能药——若字体文件过大100KB用户会看到明显闪烁。必须配合 WOFF2 压缩比 TTF 小 60%size-adjust: 100%是 Chrome 109 新增属性强制新字体继承原字体的cap-height和x-height避免换字体后段落高度塌陷或撑开不要用import加载字体改用link relpreload提前获取link relpreload href./fonts/HarmonyOS_Sans_W3.woff2 asfont typefont/woff2 crossorigin4. 避坑那些让作品集在面试官电脑上“集体翻车”的 4 个真实场景4.1 现象作品集在 Windows Edge 浏览器里导航菜单错位但在 Chrome 正常原因CSS Grid 在旧版 Edge 18中不支持gap属性而你用了grid-gap: 1rem解决检查caniuse.com确认目标浏览器支持度用 Autoprefixer 编译 CSS或手动降级.nav-list { display: grid; /* 替代 grid-gap */ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); } .nav-list * { margin-right: 1rem; /* 用 margin 模拟 gap */ } .nav-list *:last-child { margin-right: 0; }4.2 现象项目卡片点击后详情弹窗闪一下就消失原因event.preventDefault()写在了错误位置或卡片内嵌了a href#导致页面跳顶解决统一用e.stopPropagation()阻止事件冒泡而非盲目preventDefault()卡片结构改为div classproject-card内部链接用button或span[rolelink]避免语义冲突详情弹窗用position: fixedz-index而非absolute防止父容器overflow: hidden截断。4.3 现象作品集部署到 GitHub Pages 后所有图片 404原因本地路径用./images/logo.png但 GitHub Pages 默认根目录是/username.github.io/相对路径解析失败解决所有资源路径用绝对路径/images/logo.png以/开头或在head中添加base href/统一基准 URL构建前用脚本校验find . -name *.html -exec grep -l \.\./ {} \;查找非法上级引用。4.4 现象iOS Safari 上轮播图自动播放卡顿CPU 占用飙升原因用了setIntervaltransform: translateX()未启用 will-change 或硬件加速解决改用 CSSkeyframesanimation浏览器自动启用 GPU 加速添加will-change: transform到轮播容器关键帧动画必须用transform: translateX()禁用left/top触发型重排用requestAnimationFrame替代setInterval控制节奏避免丢帧。5. 性能验证与无障碍审计用 Lighthouse axe-core 做出“可测量”的作品集5.1 Lighthouse 评分不是目标而是诊断入口很多人把 Lighthouse 分数当 KPI结果为了“性能 95 分”删掉所有动画作品集变得像文档网站。正确做法是用 Lighthouse 定位瓶颈而非追求分数。运行命令本地起服务后npx lighthouse http://localhost:5000 --view --output-dir./report --chrome-flags--headless --no-sandbox --presetdesktop --throttling-methoddevtools重点关注三项First Contentful Paint (FCP)应 ≤ 1.2s。若超时检查是否阻塞渲染的 CSS/JSlink relstylesheet是否在headscript是否加deferCumulative Layout Shift (CLS)应 ≤ 0.1。若超标检查图片/视频是否缺失width/height广告位是否预留空间Accessibility重点看 “Heading levels should only increase by one”标题层级跳跃和 “Buttons have an accessible name”按钮无文字。血泪经验Lighthouse 的“SEO”分项里“Document does not have a meta description”警告可忽略——作品集本质是个人品牌不是内容站但“Links do not have descriptive text”必须修复否则读屏软件读成“点击这里”毫无意义。5.2 axe-core用代码级规则验证无障碍Lighthouse 的无障碍检测是浅层扫描axe-core 才是深度手术刀。集成方式!-- 在开发环境页面底部加入 -- script srchttps://cdnjs.cloudflare.com/ajax/libs/axe-core/4.7.2/axe.min.js/script script axe.run().then(results { console.group(无障碍问题汇总); results.violations.forEach(violation { console.log(❌ ${violation.id}: ${violation.description}); violation.nodes.forEach(node { console.log( → ${node.target[0]} (${node.failureSummary})); }); }); console.groupEnd(); }); /script常见修复项img缺alt用alt项目‘智能表单’的后台管理界面而非alt截图button缺aria-labelbutton aria-label展开项目详情 onclick.../button表单控件缺labellabel foremail邮箱/labelinput idemail typeemail而非仅靠 placeholder。5.3 真实设备测试为什么模拟器永远代替不了真机iOS Safari开启“设置 辅助功能 缩放 更大文本”测试字体是否溢出容器Android Chrome在地址栏输入chrome://flags/#force-dark-mode启用深色模式验证 CSS 变量是否适配Windows High Contrast Mode按Left Alt Left Shift Print Screen开启检查颜色对比度是否 ≥ 4.5:1用 WebAIM Contrast Checker 验证。后悔药技巧在style.css顶部加一行media (forced-colors: active) { * { forced-color-adjust: none; } :focus { outline: 2px solid Highlight; } }强制颜色模式下保留你的设计意图同时确保焦点可见。6. 进阶技巧用 CSS 自定义属性实现“主题开关”并让 JS 仅做状态同步6.1 主题切换的本质不是换 CSS 文件而是切换变量值很多作品集用 JS 动态切换link hrefdark.css结果导致 FOUCFlash of Unstyled Content和重复请求。真正高效的做法是一套 CSS多套变量值JS 只负责存取 localStorage 并设置根元素 class。/* style.css */ :root { --bg-primary: #ffffff; --text-primary: #333333; --border-color: #e0e0e0; --card-shadow: 0 2px 8px rgba(0,0,0,0.06); } media (prefers-color-scheme: dark) { :root { --bg-primary: #1a1a1a; --text-primary: #f0f0f0; --border-color: #333333; --card-shadow: 0 2px 8px rgba(0,0,0,0.3); } } /* 用户手动切换时覆盖系统偏好 */ body.theme-dark { --bg-primary: #121212; --text-primary: #e0e0e0; --border-color: #424242; --card-shadow: 0 4px 16px rgba(0,0,0,0.4); } body { background-color: var(--bg-primary); color: var(--text-primary); border-color: var(--border-color); } .project-card { box-shadow: var(--card-shadow); }6.2 JS 逻辑只做三件事——读 localStorage、设 class、存新值// script.js function initTheme() { const savedTheme localStorage.getItem(theme); const systemPrefersDark window.matchMedia((prefers-color-scheme: dark)).matches; if (savedTheme dark || (!savedTheme systemPrefersDark)) { document.body.classList.add(theme-dark); } else { document.body.classList.remove(theme-dark); } } function toggleTheme() { const isDark document.body.classList.contains(theme-dark); document.body.classList.toggle(theme-dark); localStorage.setItem(theme, isDark ? light : dark); } // 绑定到按钮 document.getElementById(theme-toggle).addEventListener(click, toggleTheme); // 监听系统主题变化用户在系统设置里改 window.matchMedia((prefers-color-scheme: dark)).addEventListener(change, e { if (!localStorage.getItem(theme)) { document.body.classList.toggle(theme-dark, e.matches); } }); initTheme();参数说明localStorage.getItem(theme)优先级高于prefers-color-scheme尊重用户显式选择matchMedia().addEventListener()是响应式监听不是轮询零性能损耗document.body.classList.toggle()比className ...更安全避免覆盖其他 class。6.3 验证主题切换是否生效用getComputedStyle读取实时变量值调试时不要靠肉眼判断主题是否切换成功。在控制台执行// 获取当前 --bg-primary 值 getComputedStyle(document.documentElement).getPropertyValue(--bg-primary).trim() // 返回 #121212 表示深色主题已激活 // 检查是否应用了 theme-dark class document.body.classList.contains(theme-dark) // true/false这才是可验证、可自动化、可写入 CI 测试的方案。我坚持用这套 HTML/CSS/JS 三件套搭作品集不是因为“怀旧”而是因为它把技术复杂度锁死在可穷举、可验证、可离线运行的范围内。框架会过时API 会废弃但header永远是headerflex布局在 2024 年和 2034 年行为一致localStorage的 API 从 IE8 到 Chrome 125 没变过。当你把作品集当成一个“数字名片”而非“技术 Demo”你就不会再为“该不该学 Next.js”焦虑——你会专注把“我是谁”“我做过什么”“你怎么联系我”这三句话用最稳定、最快速、最包容的方式送到每一个打开链接的人眼前。希望帮到你。本文还有配套的精品资源点击获取
返回列表