
打開瀏覽器準備做一個登錄表單的時候很多人心里想的是“這還不簡單一個輸入框、一個密碼框、一個按鈕半小時搞定。”結果真的做出來往往是這樣輸入框和按鈕寬度對不齊密碼框和用戶名框肉眼可見地差了幾個像素按鈕的圓角又和輸入框不是同一套風格整個表單放在頁面中間搖搖晃晃換個屏幕尺寸就垮掉一半。更別提在手機上打開明明設計稿里很精致的登錄頁直接變成了一個被拉伸變形的“半成品”。這個場景我見過太多次了。登錄表單是前端練習里最常見的起點但它恰恰是一個“看起來很簡單做精致很難”的項目。它不需要復雜邏輯不需要數據庫不需要后端接口只需要 HTML 和 CSS就能把布局、排版、狀態、反饋、響應式、可訪問性這些基礎功全部過一遍。換句話說登錄表單不是一個“展示你會寫標簽”的作業而是一個檢驗你前端基本功是否扎實的微場景。這篇文章我會帶著你從零構建一個干凈、簡單、可用的登錄表單 UI并在每一步解釋“為什么這么做”而不是只貼一段代碼讓你復制。同時也會把新手最容易踩的坑、排查順序、以及從“能用”到“好用”的工程化思路講清楚。1. 登錄表單看著簡單為什么做出來總差一口氣1.1 很多人的第一版登錄表單長什么樣先復盤一下最常見的“新手登錄表單”寫法不加語義化標簽直接一個div套一個input再來一個button樣式隨便寫兩行然后發現按鈕寬度和輸入框對不齊于是手寫一個固定width: 300px再調一調 margin勉強對齊了。但換個瀏覽器、換個字體大小又歪了。表面上這是“CSS 沒調好”實際上問題出在更底層的地方沒有先定義頁面的基礎樣式CSS Reset 或 Normalize。沒有建立統一的間距、顏色、圓角、字體變量。沒有理解box-sizing: border-box對寬度計算的影響。沒有利用 Flexbox 或 Grid 來管理布局而是依賴手動像素微調。這些問題的根源不是“不會寫 CSS”而是把登錄表單當成一個靜態圖片來做而不是當成一個系統來搭。當你只是手動調像素時每次調整都是在打補丁只有當你把布局方式、盒子模型、間距系統想清楚時調整才是可預期的。1.2 它真正考驗的是布局控制力和細節判斷登錄表單有一個特點視覺元素少所以任何一點偏差都會被放大。按鈕和輸入框的對齊只要差 2 個像素肉眼就能看出來。圓角、陰影、邊框顏色稍微不一致整個頁面的質感就降一檔。所以登錄表單真正考驗的不是“你懂多少標簽”而是三件事布局控制力你能不能用一個穩定的方式讓表單在頁面中居中并且在不同寬度下保持一致性。細節判斷力你能不能辨別 4px 和 8px 圓角的差異、#333和#555的視覺輕重、邊界陰影應該多柔和。狀態完整性你能不能讓聚焦、懸停、錯誤、禁用這些狀態都有反饋而不是只有一個默認樣子。這三件事恰恰是前端開發里最值錢的基本功。所以不要小看登錄表單它是最好的“前端基本功訓練場”。2. 從零構建登錄表單先搭結構再談樣式2.1 HTML 結構語義化優先不要為了省標簽破壞結構好的 HTML 不是“越少越好”而是“語義清晰、結構完整”。登錄表單的核心結構應該包含!DOCTYPE html html langzh-cn head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title登錄/title link relstylesheet hrefstyle.css /head body main classlogin-page section classlogin-card h1 classlogin-title歡迎登錄/h1 p classlogin-subtitle請輸入您的賬號和密碼/p form classlogin-form idloginForm autocompleteon div classform-field label forusername用戶名/label input typetext idusername nameusername placeholder請輸入用戶名 autocompleteusername required / /div div classform-field label forpassword密碼/label input typepassword idpassword namepassword placeholder請輸入密碼 autocompletecurrent-password required / /div div classform-options label classcheckbox-label input typecheckbox nameremember / span記住我/span /label a href# classforgot-link忘記密碼/a /div button typesubmit classsubmit-btn登 錄/button /form p classregister-tip 還沒有賬號a href#立即注冊/a /p /section /main /body /html這里有幾個值得注意的點main用來標識頁面主要內容區域有助于可訪問性和 SEO 語義理解。section classlogin-card把整張登錄卡片作為獨立區域。label forusername與input idusername通過for和id關聯點擊 label 時輸入框會自動聚焦這是可訪問性里很基礎的一環。autocomplete屬性讓瀏覽器可以正確提示已保存的用戶名和密碼不要省略。required標識必填項在原生表單校驗里未填寫時提交會給出提示。這些細節不屬于“UI 美化”但它們是登錄表單能真正被使用的必要條件。2.2 CSS 重置與基礎變量給頁面一個干凈的起點瀏覽器默認樣式是大家不約而同的“敵人”。不同瀏覽器對body的 margin、input的邊框、按鈕的字體繼承都有自己的默認行為。所以寫任何頁面之前第一步是統一基礎。/* 基礎重置 */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } body { min-height: 100vh; display: flex; align-items: center; justify-content: center; font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Arial, PingFang SC, Microsoft YaHei, sans-serif; background: #f0f2f5; color: #1a1a1a; line-height: 1.5; } input, button { font: inherit; color: inherit; }這段代碼做了幾件事box-sizing: border-box讓width包含padding和border。這是一個幾乎必須放在最前面的規則否則你在設置width: 100%又要加 padding 時實際寬度會超出容器。body使用 Flex 布局讓登錄卡片居中min-height: 100vh保證整個視口高度。font-family使用系統字體棧既不用加載外部字體又能在不同系統下獲得一致的觀感。input, button { font: inherit }解決表單控件不繼承字體的問題。很多瀏覽器里輸入框默認用系統字體不寫這句你的輸入框字體就和頁面其他部分不一致。2.3 Flex 布局為什么不用“魔法數字”來居中在早期前端開發中讓元素在頁面垂直居中是一個經典難題。有人用position: absolute top: 50% margin-top: -Xpx也有人用table-cell方案這些都能實現但都比較脆弱。現在最常見的方案是 Flexbox.login-page { width: 100%; min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; }注意這里我把 Flex 容器從body移到了.login-page而body只負責基礎樣式。這樣做的好處是結構更清晰如果你以后想加一個頁頭或頁腳頁面結構調整時不會動到底層布局。align-items: center負責垂直居中justify-content: center負責水平居中padding: 20px保證小屏幕下卡片不會貼邊。如果你希望在未來支持更復雜的頁面柵格也可以使用 CSS Grid.login-page { display: grid; place-items: center; min-height: 100vh; }place-items: center一行同時完成水平和垂直居中。對于登錄表單這種單一卡片場景Flex 和 Grid 都行選哪個不重要重要的是你知道自己在用什么方式布局而不是靠一堆margin-top硬懟。2.4 登錄卡片讓內容有一個清晰的容器干凈的表單 UI通常會有一張“卡片”把表單內容裝起來讓它和背景形成層次感.login-card { width: 400px; max-width: 100%; background: #ffffff; border-radius: 16px; padding: 40px 32px; box-shadow: 0 8px 30px rgba(0, 0, 0, 0.08); } .login-title { font-size: 24px; font-weight: 600; margin-bottom: 4px; text-align: center; } .login-subtitle { font-size: 14px; color: #666666; text-align: center; margin-bottom: 24px; }這里的關鍵點是width: 400px是桌面端比較合適的表單寬度不會太寬也不會太窄。max-width: 100%確保在小于 400px 的屏幕上卡片會自動收縮而不是溢出。border-radius: 16px是當下比較流行的卡片曲率既不過于“生硬”也不至于像膠囊。box-shadow用 8px 垂直偏移和 30px 模糊半徑形成一個柔和的懸浮感。注意陰影可以很輕但不要用又黑又重的粗陰影。3. 決定登錄表單質感的幾個關鍵細節3.1 寬度與間距讓所有控件在同一個節奏里登錄表單的視覺穩定感主要靠寬度和間距的一致性。常見做法是讓所有輸入框和按鈕寬度一致.form-field { margin-bottom: 20px; } .form-field input { width: 100%; height: 44px; padding: 0 14px; }這里width: 100%配合父容器的 padding讓輸入框和按鈕擁有相同的寬度。不要設置width: 395px這種固定值因為當屏幕縮小或者字體縮放時固定值會讓布局變形。控件高度統一設置為44px也有意義。44px 是移動端中比較合理的觸控高度同時也符合很多主流設計系統的尺寸規范。間距上我建議先建立一個簡單的間距刻度:root { --space-xs: 4px; --space-sm: 8px; --space-md: 16px; --space-lg: 24px; --space-xl: 32px; }雖然登錄表單用不了這么多變量但建立間距系統能讓你在調整時保持一致性不會出現“這里 20px、那里 18px、另一個地方 22px”的隨機感。3.2 輸入框樣式從瀏覽器默認樣式到品牌化樣式瀏覽器默認的輸入框樣式通常比較樸素甚至在不同系統中差異很大。為了讓輸入框看起來干凈統一需要覆蓋默認樣式.form-field input { width: 100%; height: 44px; padding: 0 14px; font-size: 14px; border: 1px solid #d0d5dd; border-radius: 8px; background: #ffffff; outline: none; transition: border-color 0.2s, box-shadow 0.2s; } .form-field input::placeholder { color: #999999; } .form-field input:focus { border-color: #4a6cf7; box-shadow: 0 0 0 3px rgba(74, 108, 247, 0.15); }這里有幾個容易被忽略的點outline: none去掉默認的聚焦外框但同時必須用box-shadow補上自定義聚焦效果否則鍵盤用戶無法分辨當前焦點在哪里。transition讓邊框顏色和陰影變化變得平滑不會在聚焦時有“瞬變”的頓挫感。::placeholder用來調整占位符顏色。注意不同瀏覽器可能有不同的默認 placeholder 透明度所以顯式設置顏色更穩妥。3.3 標簽和選項區小元素也要保持對齊輸入框上方可以放置標簽也可以只使用 placeholder。如果使用標簽注意標簽和輸入框之間的間距通常 6-8px 比較合適.form-field label { display: block; font-size: 14px; font-weight: 500; margin-bottom: 6px; color: #333333; }display: block是為了讓 label 獨占一行否則它和輸入框會處在同一水平線上。表單中間的“記住我”和“忘記密碼”區域適合用 Flex 規劃對齊.form-options { display: flex; align-items: center; justify-content: space-between; margin-bottom: 24px; font-size: 14px; } .checkbox-label { display: flex; align-items: center; gap: 6px; color: #555555; cursor: pointer; } .forgot-link { color: #4a6cf7; text-decoration: none; } .forgot-link:hover { text-decoration: underline; }這一段的重點在于不要手動用空格去對齊“記住我”和“忘記密碼”而是用justify-content: space-between讓它們分布在兩端。這樣無論屏幕多寬布局都穩定。3.4 主按鈕讓用戶一眼知道該點哪里主按鈕是登錄表單的視覺重心。它應該比輸入框更醒目同時保持風格統一.submit-btn { width: 100%; height: 44px; border: none; border-radius: 8px; background: #4a6cf7; color: #ffffff; font-size: 15px; font-weight: 500; cursor: pointer; transition: background-color 0.2s, transform 0.1s; } .submit-btn:hover { background: #3b5de3; } .submit-btn:active { transform: translateY(1px); } .submit-btn:disabled { background: #a5b4fc; cursor: not-allowed; }border: none去掉默認邊框因為按鈕本身的背景色已經足夠區分。:hover狀態讓用戶感知可點擊。:active時輕微下壓 1px模擬物理按鍵的反饋。:disabled狀態在表單提交過程中可以配合 JS 使用防止重復提交。下面是可以復用的完整style.css內容/* 基礎重置 */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } :root { --primary: #4a6cf7; --primary-hover: #3b5de3; --border-color: #d0d5dd; --text-dark: #1a1a1a; --text-gray: #666666; --radius-md: 8px; --radius-lg: 16px; } body { min-height: 100vh; font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Arial, PingFang SC, Microsoft YaHei, sans-serif; background: #f0f2f5; color: var(--text-dark); line-height: 1.5; } input, button { font: inherit; color: inherit; } /* 布局 */ .login-page { width: 100%; min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; } .login-card { width: 400px; max-width: 100%; background: #ffffff; border-radius: var(--radius-lg); padding: 40px 32px; box-shadow: 0 8px 30px rgba(0, 0, 0, 0.08); } .login-title { font-size: 24px; font-weight: 600; margin-bottom: 4px; text-align: center; } .login-subtitle { font-size: 14px; color: var(--text-gray); text-align: center; margin-bottom: 24px; } /* 表單字段 */ .form-field { margin-bottom: 20px; } .form-field label { display: block; font-size: 14px; font-weight: 500; margin-bottom: 6px; color: #333333; } .form-field input { width: 100%; height: 44px; padding: 0 14px; font-size: 14px; border: 1px solid var(--border-color); border-radius: var(--radius-md); background: #ffffff; outline: none; transition: border-color 0.2s, box-shadow 0.2s; } .form-field input::placeholder { color: #999999; } .form-field input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(74, 108, 247, 0.15); } /* 選項區域 */ .form-options { display: flex; align-items: center; justify-content: space-between; margin-bottom: 24px; font-size: 14px; } .checkbox-label { display: flex; align-items: center; gap: 6px; color: #555555; cursor: pointer; } .forgot-link { color: var(--primary); text-decoration: none; } .forgot-link:hover { text-decoration: underline; } /* 登錄按鈕 */ .submit-btn { width: 100%; height: 44px; border: none; border-radius: var(--radius-md); background: var(--primary); color: #ffffff; font-size: 15px; font-weight: 500; cursor: pointer; transition: background-color 0.2s, transform 0.1s; } .submit-btn:hover { background: var(--primary-hover); } .submit-btn:active { transform: translateY(1px); } .submit-btn:disabled { background: #a5b4fc; cursor: not-allowed; } /* 注冊提示 */ .register-tip { text-align: center; font-size: 14px; color: var(--text-gray); margin-top: 24px; } .register-tip a { color: var(--primary); text-decoration: none; } .register-tip a:hover { text-decoration: underline; }4. 從單頁面到真實場景登錄表單的工程化意識4.1 狀態反饋登錄中、失敗、空輸入都要有響應一個干凈的登錄表單 UI不只是靜態樣式好看還要覆蓋使用過程中的動態狀態。最常見的三種狀態空輸入提交用戶點了登錄但用戶名或密碼為空。不要只依賴瀏覽器默認提示最好在業務層給出明確錯誤文案。登錄中連接接口期間按鈕應該變成禁用狀態并顯示“登錄中...”之類的文字或加載圖標防止用戶重復點擊。登錄失敗后端返回錯誤時頁面需要展示錯誤信息比如放置在表單頂部或對應輸入框下方。這些邏輯雖然需要 JavaScript 參與但設計 UI 時就要先留好位置。例如.form-error { background: #fff1f0; border: 1px solid #ffccc7; color: #cf1322; padding: 10px 14px; border-radius: 8px; font-size: 13px; margin-bottom: 16px; display: none; }當 JS 檢測到錯誤時把display: none改成block即可。這些樣式不是“額外工作”而是讓表單從“靜態圖”變成“可用產品”的必經一步。4.2 可訪問性label、aria 和鍵盤操作可訪問性聽起來是個大詞但在登錄表單里落實到具體操作就幾件事每個輸入框都有label且for屬性指向對應id。點擊標簽文本時輸入框會聚焦這對鼠標用戶也是便利。聚焦狀態不要只靠“邊框顏色”區分最好同時有陰影變化。因為顏色識別對部分視覺障礙用戶不友好而形狀和亮度變化更容易被感知。鍵盤用戶可以通過 Tab 鍵在輸入框、按鈕、鏈接之間切換。因此不要用tabindex-1隨意移除元素的 Tab 順序也不要用div模擬按鈕。aria-requiredtrue不是必須的但如果你在 JS 里做復雜校驗可以用aria-invalid和aria-describedby來關聯錯誤提示。例如一個有錯誤信息的輸入框div classform-field label forusername用戶名/label input typetext idusername nameusername aria-invalidtrue aria-describedbyusername-error / p idusername-error classerror-text用戶名不能為空/p /div這樣屏幕閱讀器可以正確朗讀出錯誤關聯關系。看似細枝末節但這是“干凈 UI”里被很多人忽略的一部分。4.3 響應式小屏幕不是簡單縮小很多新手做響應式以為只要在窄屏上縮小字號、減少 padding 就行。其實關鍵不是“縮小”而是“重新安排層級”。對于登錄表單最常遇到的問題是在手機上400px 的卡片可能比屏幕還寬。雖然前面加了max-width: 100%能避免溢出但內邊距、字號、按鈕高度可能需要進一步調整。常見做法是增加一個媒體查詢media (max-width: 480px) { .login-card { padding: 28px 20px; } .login-title { font-size: 20px; } .form-field input, .submit-btn { height: 48px; } }為什么不縮小輸入框高度因為在手機上更大的觸控區域有利于操作準確性。響應式的核心不是“等比縮小”而是“適應目標設備的交互方式”。4.4 安全與前后端配合的邊界純 HTML/CSS 的登錄表單只是一個 UI 殼真正的登錄邏輯必須由后端配合完成。作為前端開發者你需要至少在 UI 層面做到幾件事密碼框使用typepassword輸入內容不顯示明文。autocomplete屬性建議保留方便瀏覽器密碼管理器。提交時使用 HTTPS不要在 URL 上拼接用戶名和密碼。不要把密碼存在 localStorage 或 Cookie 里這是后端登錄態管理的事。前端可以做一些基礎校驗但真正的鑒權必須依賴后端前端校驗只是為了提升體驗。這一點說清楚很重要一個精致的登錄頁面不能替代安全策略。登錄表單可以沒有后端但只要是真實項目就永遠存在“前端 UI”和“后端鑒權”之間的邊界。5. 新手最容易踩的坑和排查順序5.1 按鈕和輸入框寬度對不齊這是登錄表單最經典的問題。常見原因有三個沒有設置box-sizing: border-box導致輸入框的width: 100%加上 padding 和 border 后實際寬度超出容器。按鈕和輸入框的父容器寬度不同比如按鈕外面多套了一層div而這個div沒有設置寬度。按鈕的默認border和輸入框的默認border計算方式不同。排查順序先給所有元素加上box-sizing: border-box看是否解決。再檢查按鈕和輸入框是否處于同一個父容器內。最后檢查按鈕是否有width: 100%以及是否被display: inline-block或inline影響了寬度計算。用瀏覽器開發者工具選中按鈕和輸入框對比它們的實際內容寬度和盒模型是最快的方式。5.2 placeholder 顏色在不同瀏覽器里不一致不同瀏覽器對 placeholder 的默認樣式處理不同有的偏灰有的帶透明度。要統一可以同時設置::placeholder和::-ms-input-placeholder老版本 Edge不過現在主流瀏覽器對::placeholder的支持已經比較一致。input::placeholder { color: #999999; opacity: 1; }注意opacity: 1因為 Firefox 默認會給 placeholder 加透明度導致顏色看起來比預期的淡。5.3 表單提交后頁面刷新或跳轉如果使用了form標簽點擊提交按鈕時瀏覽器默認會執行表單提交導致頁面刷新。這是原生 HTML 行為不是 Bug。如果你只是做一個靜態 UI 演示不想刷新頁面最簡單的辦法是不用form改用div包住輸入框和按鈕。但如果你想保留表單語義更合理的做法是用 JavaScript 阻止默認提交document.getElementById(loginForm).addEventListener(submit, function (e) { e.preventDefault(); // 執行登錄邏輯 });我建議保留form結構因為語義化更好且在真實項目中提交行為是合理的。5.4 CSS 類名沖突與優先級問題如果頁面同時引入了 Bootstrap 等 CSS 框架或者你復用了其他項目里的樣式類名沖突很容易出現。排查順序打開瀏覽器開發者工具的 Elements 面板選中問題元素查看 Computed 樣式。看看是哪條規則生效哪條規則被覆蓋。再檢查是否因為選擇器優先級不同導致你自己的樣式沒生效。避免類名沖突的常見做法是給登錄表單的根節點加一個獨立前綴比如.login-card內部的樣式都寫在它下面盡量避免裸寫.input、.button這種全局類名。5.5 排查總鏈路從現象到原因再到解決方案拿“登錄按鈕樣式不對”舉例完整的排查鏈路是看現象按鈕寬了樣式沒生效背景色不對字體不繼承看輸入CSS 文件是否已正確 link文件路徑有沒有錯是不是改了style.css而實際加載的是style2.css看環境瀏覽器是否緩存了舊的 CSS開發者工具里有沒有報 404是不是有瀏覽器擴展在干擾頁面看參數選擇器路徑對不對類名寫沒寫錯優先級有沒有被更高優先級覆蓋是否被!important壓制看工具邊界CSS 語法有沒有拼寫錯誤某些屬性在當前瀏覽器是否不支持Flex 布局的父容器和子元素關系是否誤解了這個鏈路適用于幾乎所有前端樣式問題。不要一開始就懷疑“是不是瀏覽器有 bug”絕大多數問題都出在輸入、路徑、選擇器和優先級上。6. 從“能預覽”到“長期可維護”把登錄表單當成組件來做6.1 不只是“一個頁面”而是一個可復用組件當你寫完了登錄表單不要急著關掉編輯器。試著問自己幾個問題如果未來需要做一個注冊頁面我能復用哪些樣式如果用戶名的輸入框樣式要變我需要改動幾個地方如果換一個主色我是不是要改十幾個位置如果你把顏色、圓角、間距、陰影都定義成 CSS 變量那么換膚只是改一個變量的事情。如果表單控件的樣式是獨立的類那么注冊表單可以直接復用。這就是“組件化思維”即使你只用 HTML 和 CSS不用 React 或 Vue也可以把樣式拆分成像組件一樣的結構。登錄表單不是終點它是你第一次建立“可復用樣式模塊”意識的機會。6.2 判斷一個 UI 組件是否合格的五個問題你可以把這套判斷標準用在登錄表單上也可以用在以后任何 UI 組件上結構是否語義化不依賴純div堆砌用到了form、label、button這類合適的標簽。布局是否穩定不靠魔數像素微調而是依靠 Flex/Grid 和統一間距系統。狀態是否完整默認、聚焦、懸停、禁用、錯誤狀態都有定義。邊界是否清晰小屏幕、超大屏幕、字體縮放時不會突然變形。樣式是否可復用顏色、間距、圓角使用變量或獨立類方便后續擴展。如果你做完登錄表單后這五個問題都能回答清楚那這個練習的意義就遠遠超過“做了一個頁面”。6.3 下一步引入交互和真實接口當表單的靜態 UI 已經穩定下一步可以嘗試這些方向用 JavaScript 做實時校驗比如用戶名長度、密碼復雜度。模擬接口請求展示“登錄中”的加載狀態。增加一個“顯示/隱藏密碼”的切換按鈕。把登錄卡片改成雙欄布局左側放品牌介紹右側放登錄表單。嘗試加入暗色模式用 CSS 變量切換主題。這些方向都會讓你更深入理解 HTML/CSS 與 JavaScript 和產品設計之間的關系。登錄表單是一個極好的起點因為它小但五臟俱全。最后別把登錄表單只當成一次作業很多人在學前端時做完登錄表單就急著去學下一個框架。這種做法其實浪費了它最好的價值。登錄表單是少數幾個能完整覆蓋“結構 - 樣式 - 狀態 - 交互 - 響應式 - 可訪問性 - 前后端協作”鏈條的小項目。它像一個微縮模型規模不大但每一個環節都切得動、看得見、改得著。你可以給它加一個密碼可見性切換加一個加載動畫加一個錯誤提示加一個響應式斷點。每次加需求你都會發現原來“干凈的 UI”不是靜態的而是在邊界情況下也不崩壞、在用戶操作時也有反饋、在代碼維護時也足夠清晰。如果你現在剛開始練習我的建議是不要滿足于“和教程一樣”。把代碼寫完后試著問自己——如果我把主色從藍色改成綠色需要改幾處如果我要把表單寬度從 400px 變成 600px頁面會怎樣如果我要加一個“記住我”的默認勾選狀態放在哪里最合理把這些問題想一遍再改一遍代碼比多看十篇教程都有用。