聊到HTML入门作业,十个里至少有八个跟表单和表格有关。最近帮人看前端基础作业,收到两份很典型的要求:一份是“图书信息登记页面”,表单录数据、表格列清单;另一份是“学生成绩登记与统计页面”,表单收成绩、表格算汇总。这两道题看起来基础,实际上把HTML表单的所有核心控件、表格的语义化结构、合并单元格,甚至老式的表格页面布局都串起来了。这篇就用这两个经典作业案例,把从需求拆解到完整代码的过程完整跑一遍。适合刚学完HTML基础、想找实际操作练手的人,也适合正在做类似课程作业的同学直接对照参考。
1. 先拆题:两个作业案例到底在考什么
1.1 为什么“表单+表格”是作业标配
很多初学者觉得作业里表单和表格放一起是巧合,其实这就是Web开发里最典型的一个信息管理界面形态:上面是录入区,收集用户输入;下面是展示区,把数据列成表格给人看。比如后台管理系统的商品上架、员工信息维护、订单一览,底层都是这个套路。
表单负责“收集数据”,表格负责“展示数据”,两者配合就是一个完整的小型管理页面。课程作业选这两个来考,是因为它们把HTML里最常见的一组标签全部覆盖了:表单涉及form、input、select、textarea、label、fieldset,表格涉及table、thead、tbody、tfoot、th、td、colspan、rowspan。一套作业做完,HTML最核心的交互组件和结构化组件就都过了一遍。
1.2 案例A:图书信息登记页面的需求拆解
图书信息登记这个题目通常长这样:需要设计一个页面,用于录入图书的书名、作者、ISBN编号、出版日期、分类、阅读状态和价格,然后把已录入的图书以表格形式展示出来。
把它拆开看,表单部分考的是“控件选型”。书名是单行短文本,用input type="text";价格是数值,可以用input type="number"并且限制范围;出版日期有专门的input type="date",会弹出日期选择器;分类属于固定选项,用select下拉更省空间;阅读状态只有已读、未读、在读几种情况,用radio单选最直观。
表格部分考的是“信息呈现”。表格需要给每一列设置清晰的表头,行的组织要一致,必要的时候还要给表格加caption说明表标题。这个案例做完,基本上就把一个数据表格从结构到展示的完整流程走了一遍。
1.3 案例B:学生成绩登记与统计页面的需求拆解
学生成绩登记与统计比案例A上了一个台阶。它要求表单能录入姓名、学号、平时成绩、期末成绩,同时需要一个成绩表格,汇总每个学生的总成绩和等级,并且在表格底部展示全班平均分。
这个题目的考点很明确:首先表单要考数值输入的限制,成绩0到100之间,不能乱填;其次表格的语义化结构要完整,表头用thead,数据区用tbody,统计区用tfoot;最后还要用到合并单元格,表头里“平时/期末”两项属于“成绩”这个大列的细分,需要colspan跨列,序号列从第一行表头跨到第二行,需要rowspan跨行。
更有意思的是,有些版本的作业会额外要求用表格做整个页面的框架,比如顶部是标题栏、左侧是导航菜单、右侧是内容区、底部是页脚,这属于“表格布局页面”的经典考法。两个案例结合起来,正好把表格的数据功能和布局功能都练到了。
2. 表单部分:控件选型、校验和布局一次讲透
2.1 表单骨架:form、fieldset、legend、label怎么搭配
写表单第一步是搭骨架,不是急着堆输入框。骨架由四层组成:最外层是form,声明数据要往哪提交、用什么方式提交;里面用fieldset把控件按逻辑分组,比如案例A里“图书基本信息”一组;legend是分组的标题,浏览器会在组外框左上角显示一行说明文字;label负责关联具体的控件,点击文字就能聚焦到输入框。
<form action="#" method="post"> <fieldset> <legend>图书基本信息</legend> <label for="bookTitle">书名</label> <input type="text" id="bookTitle" name="bookTitle"> </fieldset> </form>这里有个初学者很容易漏掉的细节:label的for属性必须跟对应input的id值一致。很多人在input上写了name却忘了id,导致label用不了。name和id是两个完全不同的东西,name是提交给后端用的字段名,id是页面里定位这个元素的标识,二者缺一不可。
2.2 输入控件怎么选:从文本到日期再到单选复选
控件选型说白了就是“什么数据用什么控件”。案例A里已经用到了好几种,这里展开说一下选型逻辑。
单行文本用input type="text",适合书名、作者、ISBN这类短内容。多行文本用textarea,适合填写简介、备注。数字用input type="number",浏览器会自动校验内容是不是数字,还可以配合min、max、step控制范围和步长。日期用input type="date",PC端Chrome会直接弹出日历选择器。下拉框用select配合option,适合分类这种固定选项,优点是节省页面空间,用户不会填错。单选用radio,同一组选项要保持name值相同,这样浏览器才会把它们当成一组,实现互斥选择。复选用checkbox,适合“是否重修”“是否借阅过”这种标记类选项。
这里重点说一下radio的坑。三个单选框如果name不一致,用户可以同时选中多个,那就失去了单选的意义。我在批类似作业时见过不少人把三个name写成三个不同的值,实际页面一跑,点哪个亮哪个,完全没互斥效果。另外,如果要设置默认选中,直接在对应的input上加checked属性就行,不用写checked="checked",HTML5模式下写checked就生效。
2.3 让浏览器帮忙校验:required、pattern、min、max
作业里经常要求“不能为空”“格式要正确”。如果只用纯HTML,不用JavaScript,靠的是HTML5的原生表单校验属性。
required让浏览器在提交时检查字段有没有值,空值会弹出提示并阻止提交。pattern用正则约束内容格式,比如ISBN的写法可以写成pattern="[0-9-]{10,17}",它允许10到17位的数字或连字符组合。min和max用于限制数值范围,成绩就用min="0" max="100"。type="email"会自动校验邮箱格式,type="number"自动校验是否为数字,这些都属于“免费的校验”,比起写一堆JS来验证要省事得多。
要注意的是,原生校验的逻辑是“输入框内容不满足约束时,点提交会弹出提示并且不发送表单”。这个提示文案浏览器默认是英文的,可在input上加title属性补充说明,这样用户悬停或看到提示时更容易明白哪里填错了。作业里如果只要求静态页面,原生校验完全够用。
2.4 表单排版:CSS布局和“表格布局表单”的旧写法
表单控件默认是竖着排列的,直接写能看但不好看,所以需要排版。现在主流做法是用CSS布局,比如案例A里我用.form-row把每个label和控件放在一行,label设置固定宽度并右对齐,看起来整齐。
但作业里偶尔会考一种老式写法:用表格来排表单控件。写法是form套table,table里若干行,第一行放label,第二行放input,利用表格的自动对齐让整个表单排列整齐。这个写法在早期Web开发里非常普遍,因为那时候CSS还不成熟,用表格排版是唯一简单靠谱的方式。
<form> <table> <tr> <th>书名</th> <td><input type="text" name="bookTitle"></td> </tr> <tr> <th>作者</th> <td><input type="text" name="bookAuthor"></td> </tr> </table> </form>需要记住的是,form包table是合法的,反过来在table里直接嵌套form是不推荐的,因为表单控件可能无法正常关联提交。用表格排表单在今天已经很少用了,但理解它的原理可以帮助你读懂老代码。作业里既然教了这个技巧,就说明课程想让你明白表格的对齐能力有多强,这点在后面的“表格布局页面”里还会再遇到。
2.5 GET还是POST:作业里提交地址怎么处理
表单的method属性决定数据怎么发给服务器。GET会把表单字段拼在URL后面,比如提交后地址变成?bookTitle=xxx&author=yyy,好处是方便调试和分享,坏处是数据暴露在地址栏里,不适合提交密码或大段内容。POST把数据放在请求体里,地址栏不会显示,适合提交数据、保存信息。
作业里通常没有写好的后端接口,action往往填#,意思是不跳转到其他页面,提交时停留在当前页。这种写法点提交后页面会刷新一下,看起来“数据没保存”,这其实是正常的,因为浏览器没有后端配合,表单数据发出去也没人接收。如果老师只要求静态页面,你大可放心用action="#" method="post"。
我见过一种常见误解:有人以为action="#method="post"填上之后,提交的数据会被保存在页面里。实际上纯HTML没有任何本地存储能力,要真正保存数据得配合后端程序或本地存储,这不是HTML能单独完成的。作业里演示效果到“提交刷新”这一步就算完成。
3. 表格部分:语义化、合并单元格与页面布局
3.1 不要再一个table打天下:thead、tbody、tfoot各司其职
很多初学者写表格就是一堆tr和td堆到底,虽然浏览器能正常显示,但少了三层结构标签:thead、tbody、tfoot。这三个标签不会改变页面的视觉效果,但把表格分成了表头、主体、表尾三个逻辑部分,对样式控制和语义表达都有帮助。
表头区放th标签,浏览器默认加粗居中,一般用于列标题。主体区放真正的数据行,用td。表尾区适合放汇总行,比如成绩表格的“平均分”那一行。使用tfoot之后,即使tbody里的数据很多,滚动页面时表格底部的统计行也能被浏览器识别为独立区块,方便统一处理样式。
从语义化的角度讲,th和td的区别不只是加粗和居中。th告诉屏幕阅读器“这一格是表头,用于描述整列或整行的含义”,对无障碍访问很重要。作业里如果要求语义结构完整,记得thead、tbody、tfoot三个都要出现。
3.2 合并单元格的“格子守恒定律”:colspan和rowspan实战
合并单元格是表格最考验逻辑的部分,很多人的表格错位都出在这。colspan表示单元格横向跨几列,rowspan表示单元格纵向跨几行。比如“成绩”表头想覆盖“平时”和“期末”两列,就在“成绩”这一格写colspan="2";序号列想让两个表头行都共享同一格,就写rowspan="2"。
我习惯用“格子守恒定律”来检查合并有没有写对:每一行的总列数必须相等。计算方法是把这一行所有单元格的colspan值累加起来(没写rowspan的按1算,写了rowspan的也要按列数算进去),得到的结果应该等于表格的总列数。如果某一行加起来比总列数少一列,那多半是colspan少写了1;如果多了一列,那多半是某一行多写了一个td。
举例来说,案例B的成绩表总列数是7列:序号、学号、姓名、平时、期末、总分、等级。表头第一行有4个rowspan="2"的单元格,占4列,再加上“成绩”这个colspan="2"占2列,最后“总分”占1列,一共4+2+1=7列。第二行用来补全第一行被合并掉的平时和期末两列,所以只有2个th。这个计算过程一写出来,逻辑就清楚了。
3.3 表格布局页面框架:经典写法与为什么不推荐
“表格布局”这个词在HTML作业里通常指用表格搭建整个页面的骨架。经典结构是一个外层table,第一行放顶部标题栏,colspan="2"横跨全页;第二行左侧单元格固定宽度放导航菜单,右侧单元格放主要内容;第三行又是colspan="2"的底部页脚。案例B的页面框架就是这样设计的。
这个写法的好处是简单粗暴,不用写任何CSS,表格的单元格天然具备宽度、对齐、嵌套等布局能力。早期浏览器CSS支持很差,表格布局几乎是唯一可靠的方案,也因此留下了大量用表格堆出来的老站点。
但放在今天,表格布局的缺点非常明显。第一,表格的结构标签是为了表示数据而设计的,拿它做布局会让HTML语义变得混乱,屏幕阅读器读起来很痛苦。第二,表格嵌套过多时页面代码极难维护,改一列样式可能要动十几个td。第三,表格布局天然不支持响应式,手机端不会自动重排。所以现在的实际开发中,页面整体布局首选CSS排版,表格只负责展示真正的数据。
作业里如果明确要求“使用表格布局页面”,那你就按经典写法来,同时心里明白这是一个历史产物;如果要求不严,更建议用CSS布局,并且可以在作业说明里写下你选择CSS的理由,这反而能成为加分项。
3.4 表格样式三板斧:边框、内边距和斑马纹
纯HTML表格的默认样式很朴素,边框细得看不清,单元格之间还有双线间距。为了作业效果更好看,通常要给表格写一点基础CSS。我建议先从三个方向下手。
第一是边框。table { border-collapse: collapse; }可以把相邻单元格的边线合并成一条,否则表格会出现双线。给th, td加border: 1px solid #ccc;,整个表格的格子轮廓就出来了。第二是内边距。th, td { padding: 8px; }让内容不贴边,看起来更透气。第三是斑马纹。用tr:nth-child(even) { background: #f9f9f9; }给偶数行加浅色背景,阅读长表格时不容易看串行。
这三个样式加起来不到十行代码,但表格的观感会发生质变。进阶一点还可以给表头加背景色,比如th { background: #4a90d9; color: #fff; },整个表格立刻从“作业的草稿”变成“可以拿去演示的成品”。这些CSS不是HTML的重点,但能让作业在验收时第一印象好很多。
4. 两个案例的完整代码与实现详解
4.1 案例A完整代码:图书信息登记
案例A的核心思路是“上半部分表单录入,下半部分表格展示”。表单字段覆盖了文本、数字、日期、下拉、单选、按钮这些常见控件,表格则用caption加thead加tbody组成标准结构。
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>图书信息登记</title> <style> body { font-family: "Microsoft YaHei", sans-serif; background: #f5f5f5; padding: 20px; } .container { max-width: 800px; margin: 0 auto; background: #fff; padding: 25px; border-radius: 8px; } h1 { text-align: center; color: #333; } form { margin-bottom: 30px; } fieldset { border: 1px solid #ddd; border-radius: 6px; padding: 15px 20px; margin-bottom: 15px; } legend { color: #555; font-weight: bold; } .form-row { margin-bottom: 12px; } .form-row label { display: inline-block; width: 100px; text-align: right; margin-right: 10px; } .form-row input[type="text"], .form-row input[type="number"], .form-row input[type="date"], .form-row select { width: 260px; padding: 5px; } .btn-group { text-align: center; margin-top: 15px; } .btn-group input { padding: 6px 18px; margin: 0 6px; cursor: pointer; } table { width: 100%; border-collapse: collapse; } th, td { border: 1px solid #ccc; padding: 8px; text-align: center; } th { background: #4a90d9; color: #fff; } tr:nth-child(even) { background: #f9f9f9; } </style> </head> <body> <div class="container"> <h1>图书信息登记</h1> <form action="#" method="post"> <fieldset> <legend>图书基本信息</legend> <div class="form-row"> <label for="bookTitle">书名</label> <input type="text" id="bookTitle" name="bookTitle" placeholder="请输入书名" required> </div> <div class="form-row"> <label for="bookAuthor">作者</label> <input type="text" id="bookAuthor" name="bookAuthor" required> </div> <div class="form-row"> <label for="isbn">ISBN</label> <input type="text" id="isbn" name="isbn" placeholder="13位数字,可带连字符" pattern="[0-9-]{10,17}" required> </div> <div class="form-row"> <label for="publishDate">出版日期</label> <input type="date" id="publishDate" name="publishDate" required> </div> <div class="form-row"> <label for="category">图书分类</label> <select id="category" name="category"> <option value="计算机">计算机</option> <option value="文学">文学</option> <option value="历史">历史</option> <option value="科学">科学</option> <option value="其他">其他</option> </select> </div> <div class="form-row"> <label>阅读状态</label> <input type="radio" id="statusRead" name="status" value="已读" checked> <label for="statusRead">已读</label> <input type="radio" id="statusUnread" name="status" value="未读"> <label for="statusUnread">未读</label> <input type="radio" id="statusReading" name="status" value="在读"> <label for="statusReading">在读</label> </div> <div class="form-row"> <label for="price">价格(元)</label> <input type="number" id="price" name="price" min="0" max="1000" step="0.1" required> </div> </fieldset> <div class="btn-group"> <input type="submit" value="添加图书"> <input type="reset" value="重置"> </div> </form> <h2>图书列表</h2> <table> <caption>馆藏图书清单</caption> <thead> <tr> <th>序号</th> <th>书名</th> <th>作者</th> <th>ISBN</th> <th>出版日期</th> <th>分类</th> <th>状态</th> <th>价格</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>深入理解计算机系统</td> <td>某作者</td> <td>978-7111-00000-0</td> <td>2021-06-01</td> <td>计算机</td> <td>已读</td> <td>89.00</td> </tr> <tr> <td>2</td> <td>活着</td> <td>某作者</td> <td>978-7506-00000-0</td> <td>2020-09-15</td> <td>文学</td> <td>在读</td> <td>35.50</td> </tr> <tr> <td>3</td> <td>JavaScript高级程序设计</td> <td>某作者</td> <td>978-7111-00001-7</td> <td>2019-11-20</td> <td>计算机</td> <td>未读</td> <td>128.00</td> </tr> </tbody> </table> </div> </body> </html>4.2 案例A关键实现点:表单控件组合与表格列设计
案例A里值得注意的第一个细节是pattern="[0-9-]{10,17}"这个校验。它允许10到17位数字或连字符,基本覆盖了常见ISBN写法。但要注意当年份、出版社编号不规范时,这个正则可能误判,所以只适合演示效果,真实项目里ISBN校验要用更精确的算法。
第二个细节是单选按钮的写法。三个radio的name都是status,所以浏览器知道它们是一组,value分别是已读、未读、在读,提交后后端接收到的就是这三个值之一。第一个radio加了checked,页面加载时默认选中已读,这对用户体验有实际意义。
第三个细节是表格的“列设计”。表头8列,数据行就要一一对应8个td,这个对应关系一旦错位,表格内容就会往左或往右偏一格,看起来乱七八糟。自查方法就是数列数:thead里几个th,tbody每一行就必须几个td,不能多也不能少。
4.3 案例B完整代码:成绩登记、统计与表格页面框架
案例B的页面比案例A复杂一些,它融合了表格的数据功能和布局功能。外层表格负责整个页面的框架,内层表格负责成绩数据展示。表单字段包括姓名、学号、平时成绩、期末成绩,外加一个复选的重修标记,成绩表用colspan和rowspan做了一个双行表头,底部用tfoot放平均分。
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>学生成绩登记与统计</title> <style> body { font-family: "Microsoft YaHei", sans-serif; } .page-table { width: 900px; margin: 20px auto; border-collapse: collapse; } .page-table td { border: 1px solid #ccc; vertical-align: top; padding: 12px; } .page-header { background: #3b6ea5; color: #fff; text-align: center; height: 60px; } .page-nav { width: 160px; } .page-nav ul { list-style: none; padding: 0; margin: 0; } .page-nav li { padding: 8px 12px; margin-bottom: 6px; background: #efefef; } .page-footer { text-align: center; background: #eee; height: 40px; } .data-table { width: 100%; border-collapse: collapse; margin-top: 10px; } .data-table th, .data-table td { border: 1px solid #aaa; padding: 6px; text-align: center; } .data-table th { background: #5b8dcf; color: #fff; } .data-table tfoot td { background: #eef4fb; font-weight: bold; } .form-row { margin-bottom: 8px; } .form-row label { display: inline-block; width: 80px; text-align: right; margin-right: 8px; } </style> </head> <body> <table class="page-table"> <tr> <td colspan="2" class="page-header">某学院课程管理系统</td> </tr> <tr> <td class="page-nav"> <ul> <li>学生管理</li> <li>成绩管理</li> <li>课程管理</li> <li>系统设置</li> </ul> </td> <td> <h3>成绩登记</h3> <form action="#" method="post"> <div class="form-row"> <label for="stuName">姓名</label> <input type="text" id="stuName" name="stuName" required> </div> <div class="form-row"> <label for="stuId">学号</label> <input type="text" id="stuId" name="stuId" pattern="[0-9A-Za-z]{6,12}" required> </div> <div class="form-row"> <label for="dailyScore">平时成绩</label> <input type="number" id="dailyScore" name="dailyScore" min="0" max="100" required> </div> <div class="form-row"> <label for="finalScore">期末成绩</label> <input type="number" id="finalScore" name="finalScore" min="0" max="100" required> </div> <div class="form-row"> <input type="checkbox" id="retake" name="retake" value="是"> <label for="retake">重修标记</label> </div> <input type="submit" value="提交登记"> <input type="reset" value="清空"> </form> <h3>成绩统计表</h3> <table class="data-table"> <caption>学期成绩汇总</caption> <thead> <tr> <th rowspan="2">序号</th> <th rowspan="2">学号</th> <th rowspan="2">姓名</th> <th colspan="2">成绩</th> <th rowspan="2">总分</th> <th rowspan="2">等级</th> </tr> <tr> <th>平时</th> <th>期末</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>2023001</td> <td>学生甲</td> <td>85</td> <td>90</td> <td>175</td> <td>优秀</td> </tr> <tr> <td>2</td> <td>2023002</td> <td>学生乙</td> <td>70</td> <td>66</td> <td>136</td> <td>及格</td> </tr> <tr> <td>3</td> <td>2023003</td> <td>学生丙</td> <td>92</td> <td>88</td> <td>180</td> <td>优秀</td> </tr> </tbody> <tfoot> <tr> <td colspan="3">平均分</td> <td>82.3</td> <td>81.3</td> <td>163.7</td> <td>—</td> </tr> </tfoot> </table> </td> </tr> <tr> <td colspan="2" class="page-footer">前端课程作业 · 表格布局演示</td> </tr> </table> </body> </html>4.4 案例B关键实现点:跨行表头、汇总行与页面框架
案例B的表头是整个代码里最容易写错的部分。第一行表头写了序号、学号、姓名、成绩、总分、等级,其中序号等前三项和后两项一共五个单元格都加了rowspan="2",成绩列加的是colspan="2"。第二行只有两个th:平时和期末。两个表头行拼在一起才组成完整的7列表头,这就是双行表头的标准写法。
tfoot里的平均分行同样用到了表格的布局逻辑。colspan="3"让“平均分”这个说明文字横跨序号、学号、姓名三列,后面再写平时平均、期末平均、总分平均各占一列,最后一列等级不需要统计,用横杠占位。这样底部一行7格,和上方的表格结构保持了一致。
外层表格则是“表格布局页面”的体现。第一行colspan="2"放标题栏,第二行左侧td固定宽度160px放导航,右侧td放内容和成绩表,第三行再一个colspan="2"放页脚。整个页面不需要写float或flex,靠表格的自然排列就能铺满,这就是老式页面布局的核心原理。如果你交作业时能把这个表格布局的思路写进说明里,老师一眼就能看出你吃透了知识点。
5. 作业实战中的高频问题与自查清单
5.1 label点了没反应、表单提交后页面空白
llabel点了没反应,十有八九是for和id没对上。检查方法很简单:在浏览器里按F12打开开发者工具,查看这个label的for属性值,再对比对应input的id值,必须完全一致才算关联成功。有些同学在input上写的是name,以为for填name就行,这是最常见的错误。
表单提交后页面空白,通常是因为action="#"且没有写method。表单默认的method是GET,提交后地址栏会多出一串参数,看起来像页面“摔了”,其实只是表单把数据拼到了URL里。如果你想让提交后页面规规矩矩地保持在原位置,可以写成action="#" method="post",这样地址栏不会出现参数,页面原地刷新。
5.2 表格错位:合并单元格后列对不上
表格错位几乎都是合并单元格后“格子守恒定律”被打破了。要么colspan多写一列,要么rowspan少跨一行,导致下一行的单元格数量跟总列数对不上。
排查时不要盯着DOM看,用最笨的办法:把每一行单独列出来,数一下这一行的colspan累加值。比如一个7列表格,某一行只有一个<td colspan="2">加五个普通<td>,那就是2+5=7,正确;如果只有2+4=6,差一列,那就要检查是不是某个td漏写了,或者某个colspan少写了1。这个检查逻辑对双层表头尤其有效。
另外,rowspan会导致被跨掉的下一行“少”一列,这是正常现象。比如案例B第一行表头有五个rowspan="2"的单元格,第二行就只有两个th,而不是七个。如果你在第二行也写了七个th,表格结构反而会多出来五列,直接错位。
5.3 表格嵌套表格导致页面布局失控
表格布局页面的代码里经常出现“表格套表单表单里再套表格”的情况,层级一深,宽度就容易崩。最典型的症状是:某个单元格里嵌了一个宽表格,把父级单元格撑得特别宽,整个页面框架被挤变形。
解决办法是给外层表格设置固定或最大宽度,比如案例B里的.page-table { width: 900px; },同时给嵌套表格设置width: 100%,让它按父容器的宽度自适应,而不是按自己的内容撑开。还有一点,table默认是“内容多宽就多宽”,画表格前尽量在样式里统一给table声明宽度,避免出现“内容越长页面越宽”的连锁反应。
5.4 交作业前必过的自查清单
每次作业交出去之前,我都会按下面这个清单过一遍,能挡掉绝大部分低级错误:
- 每个
input都有对应的label,且for和id一致 - 同一组单选按钮的
name相同,且有默认checked - 每个
form里有submit按钮和reset按钮 - 表格有
thead、tbody,需要统计时有tfoot - 用了合并单元格后,每行
colspan累加值等于表格总列数 - 所有标签都闭合,没有遗漏
</td>或</tr> - 页面在浏览器里缩放宽度后没有明显横向滚动条
清单看起来琐碎,但都是真实批改作业时的高频扣分点。尤其是标签闭合这块,少一个</td>浏览器不会直接报错,而是默默把结构自动补齐,导致表格出现不明所以的空格或错位,这种问题最烦人,也最影响最终效果。
做这两个案例给我的整体感受是,HTML表单和表格的知识点并不难,但它是特别容易“想当然”的内容。控件、结构、合并规则这些细节,看文档时觉得都会,自己动手一写就漏洞百出。我自己批改类似的作业时,最常见的扣分点从来不是不会写,而是写了错、错了不知道怎么查。希望这篇拆解和排查清单,能让你在交作业之前把那些“想当然”的坑全部填平。最后一个小建议:代码一定不要复制粘贴完就交,把每个标签的作用在脑子里过一遍,再自己动手默写一个表格,比看十遍教程都有用。