補(bǔ)課:從HTML/CSS/JavaScript實(shí)例掌握核心機(jī)制)
簡介《HTML.CSS.JavaScript標(biāo)準(zhǔn)教程》實(shí)例版第二版是一套面向Web前端初學(xué)者與進(jìn)階開發(fā)者的實(shí)例型學(xué)習(xí)資料圍繞HTML結(jié)構(gòu)標(biāo)記、CSS樣式布局與JavaScript交互邏輯三大核心展開幫助讀者從零建立完整的前端知識(shí)體系并動(dòng)手實(shí)踐。資源包共收錄528個(gè)文件以286個(gè)html示例頁面、115張jpg與67張gif配圖為主輔以23個(gè)ppt課件、5個(gè)css樣式表、4個(gè)htm頁面及若干txt說明與psd源文件壓縮包約35.9MB目錄按章節(jié)組織便于對(duì)照知識(shí)點(diǎn)逐項(xiàng)查閱。內(nèi)容覆蓋HTML5音頻視頻與離線存儲(chǔ)、CSS盒模型與Flexbox/Grid布局、響應(yīng)式設(shè)計(jì)以及JavaScript基礎(chǔ)語法、DOM操作、AJAX異步通信和ES6箭頭函數(shù)、模板字符串、類與模塊等新特性每個(gè)知識(shí)點(diǎn)均配有可運(yùn)行的代碼示例。目前已有274人學(xué)習(xí)下載適合希望邊學(xué)邊練、將理論轉(zhuǎn)化為實(shí)際開發(fā)能力的讀者參考使用。1. 從一本舊書翻出的前端基本功為什么我還在推薦《HTML.CSS.JavaScript標(biāo)準(zhǔn)教程(實(shí)例版)(第2版)》前陣子幫一個(gè)剛轉(zhuǎn)行的朋友排查頁面問題他寫了個(gè)div套div的布局CSS 里用float清浮動(dòng)結(jié)果在移動(dòng)端全亂套。我問他盒模型怎么算的他愣了半天。這不是個(gè)例——現(xiàn)在很多人上手就是 Vue、React腳手架一跑組件一拼頁面能出來但一旦樣式錯(cuò)位、事件綁定失效、DOM 操作報(bào)錯(cuò)就徹底抓瞎。這本《HTML.CSS.JavaScript標(biāo)準(zhǔn)教程(實(shí)例版)(第2版)》恰好補(bǔ)的就是這塊地基。它不是那種翻兩頁就困的理論書而是每個(gè)知識(shí)點(diǎn)都配一個(gè)能跑起來的實(shí)例從!DOCTYPE html聲明到 JavaScript 判斷數(shù)據(jù)類型再到 CSS 樣式引入方式全是用小案例串起來的。適合誰剛?cè)腴T前端但不想只當(dāng)“調(diào)包俠”的人以及工作幾年但基礎(chǔ)概念一直模模糊糊、想回頭補(bǔ)課的人。我翻完的感受是它把“為什么這樣寫”講清楚了而不是只告訴你“這樣寫能跑”。2. 把實(shí)例跑起來環(huán)境、文件結(jié)構(gòu)與第一個(gè)可交互頁面2.1 選編輯器還是選 IDE別在工具上糾結(jié)太久拿到這本書的配套實(shí)例第一件事是決定在哪寫代碼。常見做法是 VS Code 加 Live Server 插件輕量、啟動(dòng)快、保存即刷新。如果你習(xí)慣 JetBrains 系WebStorm 也行但對(duì)純靜態(tài)頁面來說有點(diǎn)重。Ubuntu 用戶如果不想裝圖形化編輯器用 gedit 或 nano 直接改也行但調(diào)試體驗(yàn)差一截。我的建議是初學(xué)階段用 VS Code裝三個(gè)插件——Live Server、Prettier、Auto Rename Tag。Live Server 解決刷新問題Prettier 統(tǒng)一格式Auto Rename Tag 避免你改開標(biāo)簽忘了閉標(biāo)簽。書里的實(shí)例通常按章分文件夾每個(gè)實(shí)例一個(gè)獨(dú)立目錄里面至少有一個(gè).html文件CSS 和 JS 可能內(nèi)嵌也可能外鏈。你不需要把整本書的代碼一次性全下載下來跑按章按節(jié)來跑通一個(gè)再下一個(gè)。下面是一個(gè)典型實(shí)例的目錄結(jié)構(gòu)我按書里的組織方式還原一下chapter03/ ├── index.html ├── css/ │ └── style.css └── js/ └── main.js2.2 從 DOCTYPE 到字符編碼那些你復(fù)制粘貼時(shí)忽略的頭部很多新手直接復(fù)制書里的body部分把頭部丟了結(jié)果中文亂碼、樣式不生效。頭部這幾行看著不起眼但每一行都有用。下面是一個(gè)標(biāo)準(zhǔn)實(shí)例頁面的骨架!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title實(shí)例CSS 樣式引入方式對(duì)比/title !-- 外鏈樣式書里推薦的方式便于復(fù)用 -- link relstylesheet hrefcss/style.css /head body h1三種樣式引入方式/h1 p stylecolor: red;這是行內(nèi)樣式/p div classbox這是外鏈樣式控制的盒子/div script srcjs/main.js/script /body /html邏輯說明!DOCTYPE html告訴瀏覽器用標(biāo)準(zhǔn)模式渲染不加這行會(huì)觸發(fā)怪異模式盒模型計(jì)算方式都變了。langzh-CN對(duì)屏幕閱讀器和翻譯工具有意義。meta charsetUTF-8必須放在head最前面否則中文可能變問號(hào)。viewport那行是移動(dòng)端適配的前提書里實(shí)例版第 2 版已經(jīng)覆蓋了響應(yīng)式基礎(chǔ)。link引入外部 CSSscript放在/body前是為了不阻塞 DOM 解析。參數(shù)說明href路徑用相對(duì)路徑css/style.css表示當(dāng)前 HTML 同級(jí)目錄下的 css 文件夾。如果你把 CSS 和 HTML 放同一層直接寫style.css。src同理。書里有些實(shí)例把 JS 寫在head里那就要加defer屬性否則 DOM 還沒生成document.getElementById會(huì)返回 null。2.3 用一個(gè)小實(shí)例驗(yàn)證環(huán)境點(diǎn)擊按鈕改變文本跑通下面這個(gè)例子說明你的環(huán)境沒問題也說明你理解了 HTML 結(jié)構(gòu)、CSS 選擇器和 JS 事件綁定的最小閉環(huán)。!DOCTYPE html html langzh-CN head meta charsetUTF-8 title環(huán)境驗(yàn)證實(shí)例/title style #display { font-size: 20px; color: #333; margin: 20px 0; } button { padding: 8px 16px; cursor: pointer; } /style /head body div iddisplay原始文本/div button idchangeBtn點(diǎn)擊改變/button script // 獲取元素 var displayEl document.getElementById(display); var btnEl document.getElementById(changeBtn); var count 0; // 綁定點(diǎn)擊事件 btnEl.addEventListener(click, function() { count; displayEl.textContent 你點(diǎn)擊了 count 次; // 根據(jù)點(diǎn)擊次數(shù)切換顏色演示 JS 操作 CSS if (count % 2 0) { displayEl.style.color blue; } else { displayEl.style.color red; } }); /script /body /html邏輯說明getElementById拿到 DOM 元素addEventListener綁定 click 事件回調(diào)里修改textContent和style.color。這是最基礎(chǔ)的“結(jié)構(gòu) 樣式 行為”分離寫法書里從第 1 章就開始灌輸這個(gè)模式。參數(shù)說明count變量用來記錄點(diǎn)擊次數(shù)%取模判斷奇偶。如果你把a(bǔ)ddEventListener寫成onclick屬性也能跑但不利于維護(hù)書里推薦前者。提示如果你打開頁面發(fā)現(xiàn)按鈕沒反應(yīng)先按 F12 看 Console 有沒有報(bào)錯(cuò)。最常見的是script寫在了head里且沒加defer導(dǎo)致getElementById返回 null。3. CSS 布局與樣式引入從盒模型到五種布局方式的實(shí)例拆解3.1 盒模型和 box-sizing為什么你的寬度總是對(duì)不上書里講盒模型那章我建議反復(fù)看。CSS 盒模型分標(biāo)準(zhǔn)盒模型和 IE 盒模型區(qū)別在width是否包含padding和border。默認(rèn)是content-box你設(shè)width: 200px再加padding: 20px實(shí)際占寬是 240px。很多人布局對(duì)不齊就是這里沒算清楚。實(shí)例版里有一個(gè)對(duì)比案例我把它簡化成下面這樣/* 標(biāo)準(zhǔn)盒模型實(shí)際寬度 width padding border */ .box-content { box-sizing: content-box; width: 200px; padding: 20px; border: 5px solid #333; background: #f0f0f0; } /* IE 盒模型實(shí)際寬度 widthpadding 和 border 擠占內(nèi)容區(qū) */ .box-border { box-sizing: border-box; width: 200px; padding: 20px; border: 5px solid #333; background: #d0d0d0; }邏輯說明content-box下內(nèi)容區(qū)寬 200px加上左右 padding 各 20px、左右 border 各 5px總占寬 250px。border-box下總占寬就是 200px內(nèi)容區(qū)被壓縮到 150px。書里推薦全局設(shè)置* { box-sizing: border-box; }這樣計(jì)算寬度時(shí)不用做加法減少翻車概率。參數(shù)說明*通配符會(huì)影響所有元素包括偽元素一般夠用。如果你用第三方組件庫注意它可能自己重置了box-sizing別盲目覆蓋。3.2 五種布局方式的實(shí)例對(duì)比float、position、flex、grid、table書里有一章專門對(duì)比布局方式我按自己的理解整理成表格方便你選型布局方式適用場景書里實(shí)例主要坑點(diǎn)float文字環(huán)繞圖片、舊式多列圖文混排需要清浮動(dòng)父元素高度塌陷position彈層、固定導(dǎo)航、角標(biāo)返回頂部按鈕脫離文檔流層級(jí)要管 z-indexflex一維排列、居中、等分導(dǎo)航欄、卡片列表舊版瀏覽器前綴flex-basis 和 width 混用grid二維網(wǎng)格、復(fù)雜頁面后臺(tái)管理布局兼容性比 flex 稍差但現(xiàn)代瀏覽器都支持table表格數(shù)據(jù)、老式垂直居中數(shù)據(jù)報(bào)表語義不對(duì)響應(yīng)式困難書里對(duì) float 清浮動(dòng)的實(shí)例用了clearfix偽元素方案比overflow: hidden更可控。flex 那節(jié)講了justify-content和align-items的組合建議你每個(gè)屬性值都改一遍看效果。grid 部分實(shí)例版第 2 版有更新但如果你面向的是老項(xiàng)目先掌握 flex 就夠用。3.3 樣式引入三種方式行內(nèi)、內(nèi)嵌、外鏈的取舍書里明確推薦外鏈但也沒否定另外兩種。行內(nèi)樣式優(yōu)先級(jí)最高但沒法復(fù)用調(diào)試時(shí)臨時(shí)改可以正式代碼別用。內(nèi)嵌樣式寫在style里適合單頁面且樣式不多的情況。外鏈樣式用link引入瀏覽器可緩存多個(gè)頁面共用是標(biāo)準(zhǔn)做法。有一個(gè)細(xì)節(jié)link和import都能引入外部 CSS但import會(huì)等 HTML 解析到那行才開始加載可能造成閃屏?xí)锝ㄗh用link。!-- 推薦link 引入并行加載 -- link relstylesheet hrefcss/reset.css link relstylesheet hrefcss/main.css !-- 不推薦import 串行加載且必須寫在 style 最前面 -- style import url(css/main.css); /style邏輯說明多個(gè)link可以并行下載import是串行的。參數(shù)說明relstylesheet不能省否則瀏覽器不知道這是樣式表。如果你用構(gòu)建工具最終也會(huì)打包成一個(gè) CSS 文件但開發(fā)階段保持外鏈結(jié)構(gòu)清晰。4. JavaScript 核心機(jī)制數(shù)據(jù)類型、函數(shù)、事件與 DOM 操作實(shí)例4.1 判斷數(shù)據(jù)類型的四種方法typeof、instanceof、constructor、Object.prototype.toString書里講數(shù)據(jù)類型那節(jié)我補(bǔ)充一個(gè)實(shí)際工作中最常用的判斷函數(shù)。typeof對(duì)基本類型夠用但typeof null返回objecttypeof []也返回object。instanceof判斷原型鏈跨 iframe 會(huì)失效。constructor可以被改寫。最穩(wěn)的是Object.prototype.toString.call()。function getType(value) { // 先處理 null 和 undefined if (value null) return null; if (value undefined) return undefined; // 用 Object.prototype.toString 獲取精確類型 var type Object.prototype.toString.call(value); // 截取 [object Xxx] 中的 Xxx轉(zhuǎn)小寫 return type.slice(8, -1).toLowerCase(); } // 測試 console.log(getType(123)); // number console.log(getType(abc)); // string console.log(getType([])); // array console.log(getType({})); // object console.log(getType(null)); // null console.log(getType(function(){})); // function邏輯說明Object.prototype.toString.call(value)返回[object Array]這樣的字符串slice(8, -1)去掉[object和]再轉(zhuǎn)小寫。參數(shù)說明這個(gè)函數(shù)對(duì)基本類型和引用類型都有效除了自定義類實(shí)例會(huì)返回object需要配合instanceof進(jìn)一步判斷。書里實(shí)例版有類似的工具函數(shù)但沒這么完整我一般會(huì)把這個(gè)函數(shù)放在項(xiàng)目 utils 里。4.2 函數(shù)聲明與函數(shù)表達(dá)式的區(qū)別提升、this 和調(diào)用時(shí)機(jī)書里用實(shí)例對(duì)比了function foo() {}和var foo function() {}。前者會(huì)提升后者不會(huì)。在事件綁定和回調(diào)里這個(gè)區(qū)別很關(guān)鍵。// 函數(shù)聲明可以在聲明前調(diào)用 sayHello(); // 輸出 hello function sayHello() { console.log(hello); } // 函數(shù)表達(dá)式聲明前調(diào)用會(huì)報(bào)錯(cuò) // sayHi(); // TypeError: sayHi is not a function var sayHi function() { console.log(hi); }; sayHi(); // 輸出 hi邏輯說明函數(shù)聲明整體提升函數(shù)表達(dá)式只有變量聲明提升賦值不提升。參數(shù)說明在 ES6 之后箭頭函數(shù)沒有自己的this書里實(shí)例版第 2 版可能沒覆蓋箭頭函數(shù)但你可以自己補(bǔ)上。如果回調(diào)里需要this指向當(dāng)前元素用function而不是箭頭函數(shù)。4.3 事件綁定與事件對(duì)象從 onclick 到 addEventListener書里從onclick屬性講到addEventListener再到事件委托。事件委托是重點(diǎn)尤其在做列表點(diǎn)擊時(shí)不要給每個(gè)li綁事件綁在父級(jí)ul上通過event.target判斷點(diǎn)的是誰。ul idlist li>// 動(dòng)態(tài)創(chuàng)建列表 var data [蘋果, 香蕉, 橙子]; var ul document.createElement(ul); data.forEach(function(item) { var li document.createElement(li); li.textContent item; ul.appendChild(li); }); document.body.appendChild(ul); // 返回頂部按鈕 var backBtn document.createElement(button); backBtn.textContent 返回頂部; backBtn.style.position fixed; backBtn.style.bottom 30px; backBtn.style.right 30px; backBtn.addEventListener(click, function() { // 平滑滾動(dòng)到頂部 window.scrollTo({ top: 0, behavior: smooth }); }); document.body.appendChild(backBtn);邏輯說明createElement創(chuàng)建元素appendChild插入 DOM。window.scrollTo的behavior: smooth實(shí)現(xiàn)平滑滾動(dòng)書里老版本可能用setInterval逐步減scrollTop現(xiàn)代瀏覽器直接支持平滑滾動(dòng)。參數(shù)說明position: fixed讓按鈕固定在視口bottom和right控制位置。如果你要兼容很老的瀏覽器用document.documentElement.scrollTop 0代替。5. 避坑與排查實(shí)例跑不通時(shí)先看這五條5.1 中文亂碼現(xiàn)象是頁面顯示問號(hào)或方塊現(xiàn)象HTML 里寫的中文在瀏覽器里變成???或亂碼。原因meta charset沒寫、寫錯(cuò)位置、或者文件保存編碼和聲明不一致。解決確保meta charsetUTF-8是head的第一個(gè)子元素編輯器保存時(shí)選 UTF-8 無 BOM。如果還不行用 VS Code 右下角編碼切換成 UTF-8 再保存。5.2 樣式不生效現(xiàn)象是改了 CSS 但頁面沒變化現(xiàn)象修改style.css后刷新頁面樣式?jīng)]變。原因?yàn)g覽器緩存、選擇器權(quán)重不夠、路徑寫錯(cuò)、或者被其他樣式覆蓋。解決先按 CtrlF5 強(qiáng)制刷新再按 F12 看 Elements 面板里樣式有沒有被劃掉。如果路徑寫錯(cuò)Network 面板會(huì)顯示 404。權(quán)重問題用!important臨時(shí)驗(yàn)證但正式代碼別濫用。5.3 JS 報(bào)錯(cuò) “Cannot read property of null”現(xiàn)象是腳本中斷現(xiàn)象Console 里報(bào)Uncaught TypeError: Cannot read property xxx of null。原因getElementById沒找到元素通常是script在元素之前執(zhí)行了。解決把script放到/body前或者給script加defer屬性或者把代碼包在window.onload里。書里實(shí)例有些把 JS 放頭部你跑的時(shí)候注意調(diào)整。5.4 事件綁定多次觸發(fā)現(xiàn)象是點(diǎn)一次按鈕執(zhí)行了多次現(xiàn)象點(diǎn)擊按鈕回調(diào)執(zhí)行了兩次或更多。原因addEventListener被重復(fù)調(diào)用或者事件委托里沒判斷target。解決確保綁定代碼只執(zhí)行一次或者在綁定前先removeEventListener。事件委托里加if (target.tagName LI)過濾。書里事件那章有提到但新手容易忽略。5.5 浮動(dòng)導(dǎo)致父元素高度塌陷現(xiàn)象是背景色不見了現(xiàn)象父元素設(shè)了背景色但子元素浮動(dòng)后父元素高度變成 0背景色看不到。原因浮動(dòng)元素脫離文檔流父元素計(jì)算高度時(shí)忽略它們。解決給父元素加overflow: hidden觸發(fā) BFC或者用::after偽元素清浮動(dòng)。書里推薦后者代碼是.clearfix::after { content: ; display: block; clear: both; }邏輯說明clear: both清除左右浮動(dòng)display: block讓偽元素占一行。參數(shù)說明content: 不能省否則偽元素不生成。把這個(gè)類加到浮動(dòng)元素的父級(jí)上即可。6. 進(jìn)階技巧用實(shí)例版里的思路做一個(gè)小型倒計(jì)時(shí)組件書里最后幾章有綜合實(shí)例我挑一個(gè)倒計(jì)時(shí)的場景把 HTML、CSS、JavaScript 串起來。這個(gè)組件在很多活動(dòng)頁、秒殺頁里都能用而且能幫你理解Date對(duì)象、setInterval和 DOM 更新的配合。先看結(jié)構(gòu)div idcountdown span classnum iddays00/span 天 span classnum idhours00/span 時(shí) span classnum idminutes00/span 分 span classnum idseconds00/span 秒 /divCSS 部分用 flex 居中數(shù)字用等寬字體避免跳動(dòng)#countdown { display: flex; justify-content: center; align-items: center; font-size: 24px; font-family: Courier New, monospace; gap: 10px; } .num { background: #333; color: #fff; padding: 8px 12px; border-radius: 4px; min-width: 50px; text-align: center; }JS 邏輯設(shè)定一個(gè)目標(biāo)時(shí)間每秒計(jì)算差值更新 DOM。注意setInterval的時(shí)間不準(zhǔn)用Date.now()計(jì)算實(shí)際差值更穩(wěn)。// 目標(biāo)時(shí)間2026-12-31 23:59:59 var targetDate new Date(2026-12-31T23:59:59).getTime(); function updateCountdown() { var now Date.now(); var diff targetDate - now; // 如果時(shí)間到了停止計(jì)時(shí)并顯示 00 if (diff 0) { document.getElementById(days).textContent 00; document.getElementById(hours).textContent 00; document.getElementById(minutes).textContent 00; document.getElementById(seconds).textContent 00; clearInterval(timer); return; } // 計(jì)算天、時(shí)、分、秒 var days Math.floor(diff / (1000 * 60 * 60 * 24)); var hours Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); var minutes Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); var seconds Math.floor((diff % (1000 * 60)) / 1000); // 補(bǔ)零 document.getElementById(days).textContent days 10 ? 0 days : days; document.getElementById(hours).textContent hours 10 ? 0 hours : hours; document.getElementById(minutes).textContent minutes 10 ? 0 minutes : minutes; document.getElementById(seconds).textContent seconds 10 ? 0 seconds : seconds; } // 先執(zhí)行一次避免頁面加載后等 1 秒才顯示 updateCountdown(); var timer setInterval(updateCountdown, 1000);邏輯說明targetDate用 ISO 格式字符串創(chuàng)建Date對(duì)象getTime()轉(zhuǎn)成毫秒時(shí)間戳。diff是剩余毫秒數(shù)。天、時(shí)、分、秒的換算用取模和除法。補(bǔ)零用三元表達(dá)式。setInterval每 1000 毫秒執(zhí)行一次但實(shí)際間隔可能偏差所以每次都用Date.now()重新計(jì)算而不是累加。參數(shù)說明clearInterval(timer)在倒計(jì)時(shí)結(jié)束時(shí)清除定時(shí)器避免無意義執(zhí)行。如果你要支持多個(gè)倒計(jì)時(shí)把邏輯封裝成函數(shù)傳入目標(biāo)時(shí)間和 DOM 容器。這個(gè)組件我后來在好幾個(gè)活動(dòng)頁里復(fù)用改一下目標(biāo)時(shí)間就能上線。書里實(shí)例版沒有直接給這個(gè)案例但把Date、setInterval、DOM 操作都講到了組合起來就是這么一個(gè)東西。從那以后我每次寫倒計(jì)時(shí)都強(qiáng)制走一遍“先算差值再更新 DOM”的流程而不是用seconds--那種寫法因?yàn)楹笳咴陧撁媲械胶笈_(tái)時(shí)會(huì)變慢甚至卡住。希望這個(gè)思路幫到你。本文還有配套的精品資源點(diǎn)擊獲取