頁基礎(chǔ)設(shè)計(jì)全攻略:從頁面骨架到交互游戲?qū)崙?zhàn))
還記得第一次用記事本寫網(wǎng)頁的體驗(yàn)嗎敲下幾行標(biāo)簽瀏覽器里就變出了帶標(biāo)題和段落的頁面那種“我居然能做出來一個(gè)頁面”的感覺至今很多學(xué)生跟我聊起來都還記得。而現(xiàn)在 HTML5 已經(jīng)遠(yuǎn)遠(yuǎn)不只是“加粗、換行、插圖片”這么簡(jiǎn)單了它承載著網(wǎng)頁結(jié)構(gòu)、多媒體播放、Canvas 繪圖、本地存儲(chǔ)、動(dòng)畫交互等一系列能力是整個(gè)前端開發(fā)的基石。這篇文章我想把“HTML5網(wǎng)頁基礎(chǔ)設(shè)計(jì)”這門課程的整體脈絡(luò)、核心知識(shí)點(diǎn)和學(xué)習(xí)路徑完整梳理一遍。無論你是剛接觸前端的學(xué)生還是準(zhǔn)備做網(wǎng)頁設(shè)計(jì)課程作業(yè)、想復(fù)刻超級(jí)瑪麗或 flappy bird 這類小游戲、又或者想做一個(gè)商品圖冊(cè)展示站點(diǎn)的初學(xué)者這篇文章都會(huì)給你一條清晰可執(zhí)行的路線。專欄內(nèi)容會(huì)覆蓋 HTML5 基礎(chǔ)語法、CSS3 樣式布局、JavaScript 交互邏輯以及動(dòng)畫、音視頻處理等熱門方向幫你避開我當(dāng)年踩過的那些坑用最短路徑把網(wǎng)頁做出來、做好看、跑得穩(wěn)。1. 課程整體設(shè)計(jì)與思路拆解1.1 為什么把“HTML5基礎(chǔ)”做成一個(gè)系列專欄很多初學(xué)者打開教程網(wǎng)站面對(duì)海量的標(biāo)簽、屬性、框架文檔會(huì)一頭霧水。單獨(dú)看某個(gè)標(biāo)簽的用法都會(huì)但真正做作業(yè)或做項(xiàng)目時(shí)完全不知道該從哪里下手。這個(gè)專欄的定位就是用“案例倒推知識(shí)點(diǎn)”的方式把 HTML5 里最常用、最核心的能力串起來。我先講清楚我為什么堅(jiān)持用案例倒推。我記得早期帶學(xué)生時(shí)習(xí)慣按部就班地講什么是 HTML、什么是 CSS、什么是 JavaScript結(jié)果講了四節(jié)課學(xué)生還在背標(biāo)簽等到做真實(shí)頁面時(shí)全部卡殼。后來我換了一種方式先給一個(gè)最終效果比如“5分鐘做一個(gè)產(chǎn)品圖冊(cè)頁面”然后帶著大家一步步拆解這個(gè)頁面由哪些結(jié)構(gòu)組成每個(gè)結(jié)構(gòu)對(duì)應(yīng)哪些標(biāo)簽再去補(bǔ)充這些標(biāo)簽的細(xì)節(jié)和延伸用法。效果立竿見影學(xué)生不僅記住了標(biāo)簽還明白了“為什么在這里用這個(gè)標(biāo)簽”。這個(gè)專欄整體分為四個(gè)階段第一階段HTML5 頁面骨架搭建解決“頁面有哪些部分組成”的問題涵蓋文檔結(jié)構(gòu)、文本標(biāo)簽、鏈接、圖片、列表、表格、表單這些基礎(chǔ)中的基礎(chǔ)。目標(biāo)是讓你不看任何參考也能手寫出一個(gè)結(jié)構(gòu)完整的頁面。第二階段CSS3 樣式與布局解決“頁面怎么變好看”的問題涵蓋選擇器、盒模型、Flexbox 和 Grid 布局、響應(yīng)式設(shè)計(jì)。這個(gè)階段做完你的頁面基本可以達(dá)到“能看得下去”的程度。第三階段JavaScript 與交互邏輯解決“頁面怎么動(dòng)起來”的問題涵蓋變量、函數(shù)、事件、DOM 操作、定時(shí)器。到了這一步你就能做輪播圖、點(diǎn)擊切換、表單驗(yàn)證這些真正有交互感的功能了。第四階段HTML5 高級(jí)特性實(shí)戰(zhàn)解決“頁面怎么更酷”的問題涵蓋 Canvas 繪圖、音視頻處理、動(dòng)畫、本地存儲(chǔ)。超級(jí)瑪麗復(fù)刻、flappy bird 復(fù)刻這些熱門案例都是在這一階段實(shí)現(xiàn)的。1.2 課程目標(biāo)學(xué)完能做什么需要投入多少時(shí)間很多同學(xué)問我“這門課學(xué)完能達(dá)到什么水平”我通常會(huì)給三個(gè)非常具體的驗(yàn)收標(biāo)準(zhǔn)第一能獨(dú)立完成一個(gè)靜態(tài)產(chǎn)品展示網(wǎng)站。包含導(dǎo)航欄、產(chǎn)品圖片、文字介紹、留言表單、頁腳。所有代碼手寫不用任何現(xiàn)成模板頁面在手機(jī)和電腦上都能正常瀏覽不出現(xiàn)錯(cuò)位。第二能實(shí)現(xiàn)三個(gè)常見交互特效。比如鼠標(biāo)懸停按鈕變色、圖片自動(dòng)輪播、回到頂部按鈕。這些特效背后都是同一種邏輯事件監(jiān)聽加 DOM 樣式或內(nèi)容修改。搞懂一個(gè)其他都是變體。第三能完成一個(gè)小型游戲或動(dòng)畫項(xiàng)目比如 flappy bird 復(fù)刻版。這個(gè)項(xiàng)目不用圖形素材直接用 Canvas 畫管子和小鳥配合 JavaScript 物理模擬和碰撞檢測(cè)邏輯。難度跨度大一些但做完以后你對(duì)整個(gè)前端開發(fā)的理解會(huì)上一個(gè)臺(tái)階。關(guān)于時(shí)間投入我的建議是每天至少一小時(shí)持續(xù)五到六周。這個(gè)時(shí)間表我試過很多次對(duì)于零基礎(chǔ)的學(xué)生來說足夠?qū)W完前三個(gè)階段。第四個(gè)階段屬于進(jìn)階可以視個(gè)人興趣和時(shí)間安排彈性學(xué)習(xí)。但要注意的是編程學(xué)習(xí)有一個(gè)不可壓縮的底線動(dòng)手時(shí)間??词榻坛滩蝗缱约簩懸槐榇a這句話在 HTML5 學(xué)習(xí)中尤其真實(shí)。2. 核心知識(shí)點(diǎn)拆解從頁面骨架到交互動(dòng)效2.1 HTML5 頁面骨架結(jié)構(gòu)標(biāo)簽的“語義化”思維很多人初學(xué) HTML 時(shí)覺得標(biāo)簽就是“背多分”確實(shí)基礎(chǔ)階段有一定記憶量但 HTML5 引入的語義化標(biāo)簽讓這個(gè)問題變得很有邏輯。過去我們用一堆div把頁面分區(qū)代碼看起來是“灰蒙蒙一片”別人難以理解哪塊是導(dǎo)航、哪塊是正文、哪塊是頁腳。HTML5 直接提供了headernavmainsectionarticleasidefooter這些語義明確的標(biāo)簽。我建議所有初學(xué)者在第一周就養(yǎng)成用語義化標(biāo)簽寫頁面的習(xí)慣。這不只是“規(guī)范”問題直接影響后續(xù)兩個(gè)方向一是搜索引擎優(yōu)化搜索引擎的爬蟲會(huì)優(yōu)先抓取mainarticle等標(biāo)簽里的內(nèi)容對(duì)頁面權(quán)重判斷有幫助二是無障礙訪問屏幕閱讀器會(huì)依據(jù)這些標(biāo)簽跳轉(zhuǎn)和朗讀語義化越好站點(diǎn)對(duì)不同人群的友好度越高。骨架搭建還有一個(gè)核心概念叫“文檔流”。瀏覽器渲染頁面時(shí)默認(rèn)從上到下、從左到右排列元素理解這一層你才能明白為什么一個(gè)div會(huì)乖乖占滿一整行而span會(huì)和文字排在同一行。課程里我會(huì)專門安排一個(gè)練習(xí)只用默認(rèn)的塊級(jí)和行級(jí)元素各排一版頁面再對(duì)比用 CSS 改顯示方式后的差異。這個(gè)對(duì)比做完你基本就理解了整個(gè)頁面排版的基礎(chǔ)邏輯。2.2 CSS3 樣式體系盒模型永遠(yuǎn)是第一道坎如果讓我只保留一個(gè)必講透的知識(shí)點(diǎn)我一定會(huì)選盒模型。網(wǎng)頁上每一個(gè)元素本質(zhì)都是一個(gè)矩形盒子由內(nèi)容content、內(nèi)邊距padding、邊框border和外邊距margin組成。初次接觸時(shí)你可能會(huì)問搞懂這四個(gè)區(qū)域很了不起嗎答案是布局錯(cuò)位、元素?cái)D在一起、間距不對(duì)百分之八十的根源就是沒搞懂盒模型。這里我講一個(gè)我經(jīng)常給學(xué)生做的實(shí)驗(yàn)。隨手寫一個(gè)寬度 300px 的盒子加上 20px 的內(nèi)邊距和 5px 的邊框。請(qǐng)問它在頁面上實(shí)際占據(jù)多寬如果回答是 300px那你用的是傳統(tǒng)的 content-box 思維如果回答是 350px那你已經(jīng)知道實(shí)際寬度是“內(nèi)容寬度 左右內(nèi)邊距 左右邊框”也就是 300 20×2 5×2。同一個(gè)問題也適用于 margin 的計(jì)算。在默認(rèn)的box-sizing: content-box模式下元素的尺寸按內(nèi)容區(qū)算padding 和 border 會(huì)把盒子撐大。而box-sizing: border-box則把 padding 和 border 都算進(jìn)指定的寬度內(nèi)。兩種模式?jīng)]有絕對(duì)對(duì)錯(cuò)但一個(gè)頁面里最好統(tǒng)一用一種否則切來切去很容易算錯(cuò)尺寸。2.3 JavaScript 交互邏輯從“靜態(tài)”到“動(dòng)態(tài)”的跨越HTML 和 CSS 解決的是“長(zhǎng)什么樣”JavaScript 解決的是“能干什么”。入門 JavaScript 不需要一上來就啃 ES6 規(guī)范和面向?qū)ο笙劝讶赂闱宄憔褪菚?huì)寫交互的了第一怎么選中頁面上的元素。document.getElementById、document.querySelector是最常用的兩個(gè)方法。querySelector因?yàn)榭梢韵?CSS 選擇器一樣用.class#id甚至父子組合實(shí)際開發(fā)中我更推薦初學(xué)者優(yōu)先掌握它。第二怎么給元素綁定事件。clickmouseovermouseoutscroll是最常見的幾個(gè)。比如實(shí)現(xiàn)一個(gè)鼠標(biāo)懸停變色的按鈕核心就是btn.addEventListener(mouseover, function() { btn.style.backgroundColor #ff6600; })就這么幾行。第三怎么修改元素的內(nèi)容和樣式。textContent改文字style.xxx改行內(nèi)樣式className或classList切換類名。這里有個(gè)值得注意的坑用style直接改樣式會(huì)生成行內(nèi)樣式級(jí)別很高后續(xù)如果再用外部樣式表去覆蓋會(huì)非常費(fèi)勁。所以項(xiàng)目里凡是涉及兩種以上樣式切換的我基本都用 classList 切換類名來實(shí)現(xiàn)代碼更干凈也容易維護(hù)。我見過太多初學(xué)者把這三件事混在一起學(xué)結(jié)果越學(xué)越亂。其實(shí)每一個(gè)交互特效歸根結(jié)底都是“選中元素 監(jiān)聽事件 修改狀態(tài)”的組合拳。理解了這一層輪播圖、菜單折疊、點(diǎn)贊變色、回到頂部全都一通百通。2.4 Canvas 與動(dòng)畫復(fù)刻小游戲背后的核心機(jī)制很多學(xué)生因?yàn)槌?jí)瑪麗復(fù)刻版和 flappy bird 復(fù)刻版對(duì) HTML5 產(chǎn)生了興趣。這些項(xiàng)目確實(shí)很拉風(fēng)但背后的核心技術(shù)其實(shí)就是一個(gè)Canvas 繪圖基礎(chǔ)。Canvas 是 HTML5 新增的畫布元素JavaScript 可以像拿畫筆一樣在上面繪制圖形、圖片和文字。畫布坐標(biāo)從左上角開始x 軸向右y 軸向下。畫一個(gè) 100×80 的綠色矩形代碼只需三行const canvas document.getElementById(gameCanvas); const ctx canvas.getContext(2d); ctx.fillStyle #2ecc71; ctx.fillRect(100, 80, 100, 80);getContext(2d)獲取上下文對(duì)象fillStyle設(shè)置填充色fillRect繪制填充矩形。flappy bird 的整個(gè)游戲循環(huán)就是反復(fù)清除上一幀畫面、更新小鳥位置、重新繪制背景、管道和小鳥。再疊加簡(jiǎn)單的重力加速度計(jì)算和矩形碰撞檢測(cè)一個(gè)能玩的復(fù)刻版就成型了。這套邏輯看著簡(jiǎn)單但實(shí)際運(yùn)行時(shí)有兩個(gè)非常容易踩的坑第一個(gè)是幀率控制。用循環(huán)直接重繪會(huì)導(dǎo)致速度不可控穩(wěn)妥的做法是用requestAnimationFrame來控制每幀調(diào)用它能自動(dòng)適配屏幕刷新率不會(huì)讓游戲在不同電腦上不同速度。第二個(gè)是碰撞檢測(cè)的精度。初學(xué)者最容易犯的錯(cuò)是用整個(gè)圖片矩形判斷碰撞實(shí)際視覺上小鳥的翅膀尖和管道邊緣碰一下就被判出局玩家體驗(yàn)會(huì)比較“挑剔”。合理做法是把碰撞檢測(cè)矩形做得比畫面小一圈留出幾像素的容錯(cuò)空間游戲手感會(huì)明顯舒服很多。動(dòng)畫的另一個(gè)方向是 CSS3 過渡與關(guān)鍵幀動(dòng)畫。像產(chǎn)品圖冊(cè)里那種鼠標(biāo)懸停時(shí)圖片放大緩動(dòng)、頁面加載時(shí)元素滑入效果用transition和keyframes都能優(yōu)雅實(shí)現(xiàn)而且比 JavaScript 逐幀控制更流暢因?yàn)闉g覽器會(huì)對(duì)這些變化做合成優(yōu)化減少性能消耗。2.5 音視頻與實(shí)用擴(kuò)展倍速播放、本地存儲(chǔ)這些需求怎么落地“HTML5視頻倍速”是近期搜得很熱的一個(gè)詞很多同學(xué)想給自己的網(wǎng)頁加上視頻播放功能。HTML5 直接用video標(biāo)簽嵌入視頻瀏覽器原生便帶播放控件但在 iPhone 上控件樣式很難完全統(tǒng)一且無法自定義倍速按鈕這些需求需要借助 JavaScript 的playbackRate屬性實(shí)現(xiàn)。示例代碼const video document.getElementById(myVideo); video.playbackRate 1.5; // 1.5倍速播放同理currentTime可以實(shí)現(xiàn)跳轉(zhuǎn)進(jìn)度volume可以控制音量。這些原生 API 非常豐富做網(wǎng)頁視頻播放器時(shí)值得好好翻一翻文檔。游戲和交互頁面里另一個(gè)高頻需求是本地?cái)?shù)據(jù)保存。過去網(wǎng)頁刷新后玩家的分?jǐn)?shù)、用戶的偏好設(shè)置都會(huì)消失現(xiàn)在 HTML5 提供了 localStorage 和 sessionStorage。localStorage 存的數(shù)據(jù)只要不主動(dòng)清除會(huì)一直保留適合保存“最高分”“主題偏好”這類信息sessionStorage 在瀏覽器標(biāo)簽頁關(guān)閉后就會(huì)被清理適合保存“本次會(huì)話的瀏覽記錄”這類臨時(shí)內(nèi)容。使用方式和 JavaScript 對(duì)象很相似// 保存 localStorage.setItem(highScore, 999); // 讀取 const highScore localStorage.getItem(highScore); // 刪除 localStorage.removeItem(highScore);不過要提醒一句localStorage 存儲(chǔ)的是字符串如果你要存對(duì)象或數(shù)組需要先用 JSON.stringify 轉(zhuǎn)成字符串讀取時(shí)再用 JSON.parse 解析回來。這個(gè)環(huán)節(jié)我見過不少人被卡住控制臺(tái)打印出來的一直是[object Object]其實(shí)就是忘了轉(zhuǎn)換格式。3. 實(shí)操環(huán)節(jié)從零構(gòu)建一個(gè)產(chǎn)品圖冊(cè)展示頁下面我以“HTML5實(shí)現(xiàn)好看的產(chǎn)品圖冊(cè)設(shè)計(jì)網(wǎng)站”為例把前面講的知識(shí)點(diǎn)串成一個(gè)完整項(xiàng)目。這個(gè)案例非常適合作為課程作業(yè)也適合初學(xué)網(wǎng)頁設(shè)計(jì)的同學(xué)練手。3.1 頁面結(jié)構(gòu)與素材準(zhǔn)備做頁面之前先畫一個(gè)簡(jiǎn)單的線框圖。這個(gè)產(chǎn)品圖冊(cè)網(wǎng)站我計(jì)劃包含四個(gè)區(qū)域頂部導(dǎo)航站名和菜單、主視覺橫幅大圖加標(biāo)題、產(chǎn)品列表區(qū)六張卡片網(wǎng)格、頁腳版權(quán)信息。然后準(zhǔn)備素材。找六張產(chǎn)品圖片建議統(tǒng)一為 600×600 像素或同比例圖片網(wǎng)上的免費(fèi)圖庫都可以用。如果圖片尺寸不統(tǒng)一后面做網(wǎng)格布局時(shí)會(huì)遇到對(duì)齊問題需要加 object-fit: cover 裁剪所以這里我直接準(zhǔn)備好了尺寸相同的圖片省掉很多麻煩。HTML 骨架用語義化標(biāo)簽搭建header classsite-header div classlogoMyProduct/div nav classmain-nav a href#home首頁/a a href#products產(chǎn)品/a a href#about關(guān)于/a /nav /header main section classbanner idhome h1精選產(chǎn)品圖冊(cè)/h1 p每一件產(chǎn)品都經(jīng)過精心打磨/p /section section classproduct-grid idproducts article classproduct-card img srcimages/product1.jpg alt產(chǎn)品1 h3產(chǎn)品名稱/h3 p簡(jiǎn)短的產(chǎn)品描述文字/p button classbtn-buy查看詳情/button /article !-- 重復(fù)六個(gè)這樣的卡片形成網(wǎng)格 -- /section /main footer classsite-footer p? 2025 MyProduct 保留所有權(quán)利/p /footer注意img標(biāo)簽上一定要寫alt屬性一是無障礙訪問需要二是圖片加載失敗時(shí)會(huì)顯示替代文字不至于出現(xiàn)一片殘缺區(qū)域。這個(gè)細(xì)節(jié)也經(jīng)常是網(wǎng)頁設(shè)計(jì)課程作業(yè)的評(píng)分點(diǎn)。3.2 CSS 樣式與 Grid 布局的關(guān)鍵代碼布局是整個(gè)項(xiàng)目最關(guān)鍵的部分。六個(gè)產(chǎn)品卡片要排成三列兩行的網(wǎng)格直接用 CSS Grid 是最省力的方案.product-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; max-width: 1200px; margin: 0 auto; padding: 40px 20px; } .product-card { border: 1px solid #eee; border-radius: 12px; overflow: hidden; background: #fff; transition: transform 0.3s ease, box-shadow 0.3s ease; } .product-card:hover { transform: translateY(-6px); box-shadow: 0 12px 24px rgba(0, 0, 0, 0.1); }這里grid-template-columns: repeat(3, 1fr)的含義是創(chuàng)建三列每列寬度為容器剩余空間的等分。gap指定卡片間距。卡片懸停時(shí)上移 6 像素并加深陰影形成“浮起來”的立體感過渡動(dòng)畫使用 transition 平滑呈現(xiàn)。手機(jī)端的適配也很簡(jiǎn)單再補(bǔ)一段媒體查詢media (max-width: 768px) { .product-grid { grid-template-columns: repeat(2, 1fr); } } media (max-width: 480px) { .product-grid { grid-template-columns: 1fr; } }這個(gè)案例里有幾個(gè)我特別想強(qiáng)調(diào)的細(xì)節(jié)。一是border-radius: 12px加上overflow: hidden的組合圖片圓角和卡片圓角才能同步生效否則圖片直角會(huì)頂出卡片圓角區(qū)域。二是圖片標(biāo)簽?zāi)J(rèn)會(huì)有約 4px 的底部間隙我通常會(huì)給img { display: block; width: 100%; }既消除間隙也讓圖片自適應(yīng)容器寬度。三是一張卡片內(nèi)部無論是圖片、標(biāo)題還是按鈕都要保持間距均勻我一般是給文字區(qū)域統(tǒng)一加 padding 而不是通篇 margin這樣更容易控制視覺節(jié)奏。3.3 JavaScript 交互篩選與彈窗的完整實(shí)現(xiàn)靜態(tài)頁面完成以后產(chǎn)品圖冊(cè)還需要兩個(gè)交互功能一是按類別篩選產(chǎn)品二是點(diǎn)擊按鈕彈出產(chǎn)品詳情。篩選功能的思路是給每個(gè)產(chǎn)品卡片設(shè)置>const filterButtons document.querySelectorAll(.filter-btn); const productCards document.querySelectorAll(.product-card); filterButtons.forEach((btn) { btn.addEventListener(click, () { const category btn.dataset.category; productCards.forEach((card) { if (category all || card.dataset.category category) { card.style.display block; } else { card.style.display none; } }); }); });btn.dataset.category讀取的是>const modal document.getElementById(modal); const modalImg document.getElementById(modalImg); const modalTitle document.getElementById(modalTitle); const closeBtn document.getElementById(modalClose); productCards.forEach((card) { const btn card.querySelector(.btn-buy); btn.addEventListener(click, () { const imgSrc card.querySelector(img).src; const title card.querySelector(h3).textContent; modalImg.src imgSrc; modalTitle.textContent title; modal.classList.add(show); }); }); closeBtn.addEventListener(click, () { modal.classList.remove(show); });遮罩層的 CSS 核心就兩個(gè)類默認(rèn)狀態(tài)下opacity: 0; visibility: hidden;不顯示加上.show類后改為opacity: 1; visibility: visible;配合 transition 實(shí)現(xiàn)淡入淡出。使用 visibility 比單純的 opacity 更靠譜因?yàn)橥该鞫葹?0 的元素仍然會(huì)響應(yīng)點(diǎn)擊事件visibility: hidden 則直接把交互屏蔽掉了。這幾個(gè)功能都完成后你會(huì)發(fā)現(xiàn)自己已經(jīng)同時(shí)用上了 HTML 結(jié)構(gòu)、CSS 布局和 JavaScript 事件處理。以一個(gè)小項(xiàng)目為支點(diǎn)把零散的知識(shí)點(diǎn)真正編織成了一個(gè)整體。4. 常見問題與排查技巧實(shí)錄4.1 樣式不生效與元素“憑空消失”做網(wǎng)頁一定會(huì)遇到“明明寫了 CSS 但頁面沒變化”或者“元素突然不見了”的情況。初學(xué)者最容易在這里消耗大量時(shí)間這里我給你一套排查順序第一步打開瀏覽器開發(fā)者工具快捷鍵一般是 F12切到 Elements/元素面板選中目標(biāo)元素看右側(cè) Styles/樣式面板里是否有生效的樣式有沒有被刪除線劃掉的屬性。所謂“被劃掉的屬性”通常是優(yōu)先級(jí)不足比如行內(nèi)樣式、ID 選擇器和類選擇器的優(yōu)先級(jí)差異導(dǎo)致的處理方式是提高選擇器權(quán)重或用!important但我個(gè)人不推薦動(dòng)不動(dòng)就上!important它會(huì)破壞樣式層的管理邏輯。第二步檢查引入順序。外部樣式表引入放在head標(biāo)簽里如果有多個(gè)樣式文件后面引入的樣式會(huì)覆蓋前面重復(fù)的屬性。如果你在頁面底部又寫了一段style標(biāo)簽它也可能覆蓋外部文件中的同名樣式。第三步看元素是否被其他元素“遮擋”或“擠出”。元素不見不代表它消失了可能被父級(jí)設(shè)了overflow: hidden也可能被別的元素用定位遮住了還有可能是寬度或高度計(jì)算成了 0。在開發(fā)者工具里給元素加一個(gè)醒目背景色或邊框很容易判斷它到底在不在原位置。4.2 盒子寬度“詭異”與尺寸計(jì)算問題“我已經(jīng)設(shè)置了 width: 300px為什么這個(gè)盒子占的寬度比 300px 大”這是我最常被問到的問題之一。答案前面講過默認(rèn)box-sizing: content-box下寬度只算內(nèi)容區(qū)padding 和 border 會(huì)額外加出來。解決辦法是用通配符把全局盒模型統(tǒng)一掉* { box-sizing: border-box; }這樣的話width 指定的是邊框以內(nèi)的總寬度包括 padding 和 border。我?guī)缀踉诿恳粋€(gè)項(xiàng)目里都會(huì)先用這條規(guī)則打底它能讓尺寸計(jì)算變得更直觀。同樣的邏輯也適用于 flex 子項(xiàng)和 grid 子項(xiàng)很多“卡片對(duì)不齊”的問題其實(shí)都是盒模型沒統(tǒng)一導(dǎo)致的。還有一類的尺寸問題和圖片相關(guān)比如圖片把容器撐爆了。無論容器多寬img { max-width: 100%;; }都能限制圖片不超出容器。這個(gè)規(guī)則在響應(yīng)式設(shè)計(jì)里是標(biāo)配。4.3 交互沒反應(yīng)控制臺(tái)報(bào)錯(cuò)與事件綁定時(shí)機(jī)寫 JavaScript 交互時(shí)最常見的尷尬是點(diǎn)擊按鈕沒有任何反應(yīng)控制臺(tái)也沒有任何報(bào)錯(cuò)。這時(shí)候優(yōu)先檢查三個(gè)點(diǎn)第一有沒有語法錯(cuò)誤。打開控制臺(tái)Console如果代碼有錯(cuò)誤它會(huì)直接顯示紅底信息。常見的錯(cuò)誤是少寫了一個(gè)花括號(hào)、引號(hào)沒閉合、中英文標(biāo)點(diǎn)混用。第二腳本放在哪里。如果你把script標(biāo)簽直接放在head里瀏覽器執(zhí)行腳本時(shí) DOM 還沒有解析完成document.querySelector會(huì)返回 null自然綁不上事件。解決方案有幾種把script放在/body之前使用defer屬性或者把綁定邏輯包在 DOMContentLoaded 事件里。我推薦剛?cè)腴T的同學(xué)直接使用第一種方案把腳本放在/body前面省心又直觀。第三是不是事件壓根沒綁上。在事件回調(diào)函數(shù)里第一行寫console.log(clicked);如果點(diǎn)擊后控制臺(tái)沒有輸出說明監(jiān)聽事件本身就沒綁上回到上一步檢查選擇器是否有拼寫錯(cuò)誤如果輸出了但頁面其他內(nèi)容沒變化再去檢查具體操作代碼。排查問題的心態(tài)也很重要。我見過不少人調(diào)試時(shí)報(bào)錯(cuò)信息一彈出來第一反應(yīng)就是去百度復(fù)制粘貼整個(gè)報(bào)錯(cuò)而完全沒有仔細(xì)看過報(bào)錯(cuò)內(nèi)容。實(shí)際上控制臺(tái)里那一行報(bào)錯(cuò)信息已經(jīng)把文件路徑、行號(hào)、錯(cuò)誤原因都寫得明明白白了。自己把報(bào)錯(cuò)從頭到尾讀一遍再去搜索或者求助效率和成長(zhǎng)速度都會(huì)翻倍。4.4 移動(dòng)端適配與圖冊(cè)展示優(yōu)化做產(chǎn)品圖冊(cè)時(shí)還有一類高頻問題桌面端看起來正常手機(jī)端一打開就亂套。最典型的三個(gè)表現(xiàn)圖片溢出、文字過大或過小、卡片擠成一列。應(yīng)對(duì)措施其實(shí)前面已經(jīng)覆蓋了大半我再補(bǔ)幾個(gè)要點(diǎn)viewport 視口標(biāo)簽必須寫一般在head里加這一行meta nameviewport contentwidthdevice-width, initial-scale1.0沒有這行代碼手機(jī)瀏覽器就會(huì)用默認(rèn)的 980px 視口寬度渲染頁面然后整體縮放結(jié)果就是文字變得特別小用戶需要放大才能看清。這個(gè)標(biāo)簽是移動(dòng)端適配的第一道防線。字體大小不要用 px 寫死可以考慮 rem 單位。rem 的值基于根元素的字體大小默認(rèn)根字號(hào)是 16px因此1rem 16px。你可以在媒體查詢里調(diào)整根字號(hào)整個(gè)頁面其他用 rem 設(shè)的尺寸會(huì)同比例縮放。這個(gè)做法比逐一改每個(gè)元素的尺寸要高效很多。點(diǎn)擊區(qū)域要足夠大按鈕高度至少 44px這是手指觸摸友好尺寸。移動(dòng)端上兩個(gè)相鄰按鈕間距太小的話很容易誤觸給按鈕留出些呼吸感。4.5 常見問題速查表現(xiàn)象常見原因解決方案頁面整體錯(cuò)位卡片擠成一團(tuán)盒模型尺寸計(jì)算混亂用* { box-sizing: border-box; }統(tǒng)一盒模型圖片把容器撐破圖片寬度不受控給img設(shè)置max-width: 100%文字移動(dòng)端太小缺少 viewport 視口設(shè)置在 head 中加 viewport meta 標(biāo)簽點(diǎn)擊按鈕無反應(yīng)JS 綁定時(shí)機(jī)過早導(dǎo)致元素未加載把 script 放到 body 末尾或用 DOMContentLoaded鼠標(biāo)懸停效果延遲或卡頓過渡屬性太多、性能消耗大優(yōu)先對(duì) transform 和 opacity 做過渡localStorage 存對(duì)象變 [object Object]存儲(chǔ)前未 JSON 序列化用 JSON.stringify 存用 JSON.parse 讀背景圖片或視頻在手機(jī)上不顯示移動(dòng)端對(duì)自動(dòng)播放和資源策略限制提供 poster 封面并檢查資源路徑和協(xié)議5. 學(xué)習(xí)路徑與進(jìn)階拓展建議5.1 從課程作業(yè)到獨(dú)立項(xiàng)目的成長(zhǎng)路線這門課的作業(yè)通常有兩個(gè)方向一是做產(chǎn)品展示站、個(gè)人主頁這類信息類頁面二是做小游戲復(fù)刻這類交互娛樂項(xiàng)目。不管選哪個(gè)方向我都建議你堅(jiān)持“先完成再完美”的原則。很多同學(xué)做作業(yè)時(shí)會(huì)在配色和字體上反復(fù)糾結(jié)結(jié)果核心功能還沒做完。正確的順序是先跑通功能和布局保證結(jié)構(gòu)完整、鏈接可點(diǎn)、按鈕可用再花時(shí)間打磨視覺細(xì)節(jié)。完成基礎(chǔ)作業(yè)以后你可以從三個(gè)方向做進(jìn)階拓展。第一個(gè)方向是頁面性能優(yōu)化壓縮圖片、懶加載、減少 HTTP 請(qǐng)求這些概念在你真正上線一個(gè)頁面后會(huì)變得非常重要。第二個(gè)方向是用戶體驗(yàn)細(xì)節(jié)比如表單輸入時(shí)的即時(shí)校驗(yàn)、加載過程中的骨架屏、空狀態(tài)時(shí)的友好提示。第三個(gè)方向是工程化把 CSS 拆分成模塊文件、用預(yù)處理器、通過構(gòu)建工具自動(dòng)化處理。這已經(jīng)接近職業(yè)前端開發(fā)的工作方式了但如果你是從課程作業(yè)起步逐步往這個(gè)方向靠攏過渡會(huì)非常自然。5.2 如何用好身邊的代碼資源網(wǎng)上有大量現(xiàn)成的 HTML5 頁面模板和代碼片段我的建議是“可以抄但不能白抄”。直接把整個(gè)模板下載下來改個(gè)名字當(dāng)作自己的作業(yè)上交于自己的學(xué)習(xí)是完全浪費(fèi)更重要的是老師或面試官一眼就能看出來模板代碼的風(fēng)格、結(jié)構(gòu)和你自己的水平嚴(yán)重不匹配。我的做法是拿到一個(gè)喜歡的模板后先通過開發(fā)者工具分析它的布局結(jié)構(gòu)蓋住 CSS 自己重新寫一遍樣式再對(duì)照原版差異。這種做法相當(dāng)于“臨摹”既能學(xué)到別人的布局思路和代碼組織方式又能保證代碼是你自己吃透的。遇到不會(huì)的屬性就查文檔順手在瀏覽器里試一下試完再放到項(xiàng)目里看效果這套流程下來印象會(huì)特別深刻。5.3 后面可以繼續(xù)深挖的方向?qū)W完 HTML5 基礎(chǔ)之后路線圖大致有這么幾個(gè)分支如果你想繼續(xù)走頁面開發(fā)路線接下來是 JavaScript 進(jìn)階ES6、模塊化、Vue 或 React 這類前端框架、構(gòu)建工具和工程化實(shí)踐。如果你想走可視化或游戲方向可以深入研究 Canvas 高級(jí)繪圖、WebGL、物理引擎。如果你想走移動(dòng)端方向可以了解 PWA 技術(shù)讓網(wǎng)頁可以離線訪問并部署到手機(jī)桌面。每個(gè)方向都有對(duì)應(yīng)的熱門項(xiàng)目可以做。比如學(xué)了 Canvas你可以嘗試做一個(gè)繪圖板應(yīng)用學(xué)了本地存儲(chǔ)可以做一個(gè)小型記賬本頁面學(xué)了音視頻 API可以做自己的視頻播放器。這些項(xiàng)目的共同特點(diǎn)是體量小、見效快、能覆蓋多個(gè)知識(shí)點(diǎn)非常適合在學(xué)完基礎(chǔ)后拿來鞏固和展示。給自己的學(xué)習(xí)留一點(diǎn)耐心HTML5 入門曲線其實(shí)不陡但它的知識(shí)點(diǎn)數(shù)量不少而且很多概念之間是交織的。HTML 負(fù)責(zé)骨架CSS 負(fù)責(zé)外觀JavaScript 負(fù)責(zé)行為三者各司其職又緊密結(jié)合。初學(xué)時(shí)你可能會(huì)覺得“我記不住那么多標(biāo)簽和屬性”這太正常了——做了幾年開發(fā)的人也在天天查文檔。更重要的不是背下所有 API而是建立“解決問題”的思路遇到一個(gè)需求能大致知道該用什么工具、代碼應(yīng)該怎么寫、出錯(cuò)時(shí)到哪里去排查。我強(qiáng)烈建議你不要抱著“看完所有章節(jié)再動(dòng)手”的心態(tài)來學(xué)習(xí)這門課。學(xué)完 HTML 基礎(chǔ)標(biāo)簽就可以做一個(gè)純文本頁面學(xué)完 CSS 基礎(chǔ)選擇器就可以給頁面換色學(xué)完事件監(jiān)聽就可以寫第一個(gè)可交互按鈕。每學(xué)完一塊就立刻做個(gè)看得見摸得著的東西出來這個(gè)成就感本身就是最好的學(xué)習(xí)動(dòng)力。別怕寫得爛每個(gè)寫得爛的頁面都是你下一次寫得更好的臺(tái)階。