干净的代码:为什么 HTML/CSS 基础仍然很重要
已发表: 2022-03-11在我 15 年的 Web 开发经验中,我曾与各种公司合作过,从企业级到初创公司,一路上我与许多软件工程师同行。 我在项目中遇到的最常见和最重要的问题之一是未能编写干净且易于理解的代码。
即使是来自一流公司的最优秀的开发人员也并不总是遵循最佳实践并编写可以清理和优化的代码。
混乱和肮脏代码的后果
引用一篇讨论干净代码原则的旧但仍然相关的博客文章:
源代码类似于金融债务。 假设你想买房子住。大多数人没有足够的资金来买房,所以你选择抵押贷款。 但抵押贷款本身并不是一件好事。 这是一种责任。 你每个月都必须为你的债务支付利息……
在 Web 开发中也是如此。 该代码有持续的成本。 你必须理解它,你必须维护它,你必须随着时间的推移使其适应新的目标。 您拥有的代码越多,这些持续成本就会越大。 拥有尽可能少的源代码,同时仍然能够实现我们的业务目标,这符合我们的最大利益。
但我们不要停留在抽象上。 本文将介绍基本的干净代码原则、用于组织代码的不同技术,以及如何使其更易于维护、可扩展和更易于调试。
高质量的代码从基本的代码样式开始,扩展到使用 HTML/CSS 编写具有许多可重用块的大型应用程序时的最佳实践,我们还将讨论命名约定以创建更大的隐式可读性以及第三方框架及其最佳实践。
当你读完这篇文章时,你应该对质量代码的基础知识以及如何使你的 HTML 和 CSS 代码更容易维护和扩展有了很好的理解。
代码样式要点
让我们从良好的 HTML 和 CSS 代码的基础开始:W3C 有效性、命名约定、文件结构等。
从第一天起就注意结构。
如果您要开发一个大型应用程序,那么您需要注意文件结构。 它可以,或者更确切地说,应该是这样的:
使用验证器检查您的代码。
尝试始终使用 HTML 和 CSS 验证器。
错误代码:
<figure> <div> <img src="demo.jpg" alt=""> <figcaption> <h2>Hello world</h2> </figcaption> </div> </figure> <picture> <source src="demo.webp" type="image/webp"> <img src="demo.jpg" alt=""> </picture> <details> <header> <summary>Expand details</summary> </header> <p>All content goes here</p> </details>
p { font: 400 inherit/1.125 serif; }
好代码:
<figure> <img src="demo.jpg" alt=""> <!-- figcaption should be child of element figure element, not div --> <figcaption> <h2>Hello world</h2> </figcaption> </figure> <picture> <!-- source should have srcset attribute --> <source type="image/webp"> <img src="demo.jpg" alt=""> </picture> <details> <!-- summary is not allowed as child of header --> <summary>Expand details</summary> <p>All content goes here</p> </details>
p { font-weight: 400; font-size: inherit; line-height: 1.125; font-family: serif; }
使用<img>
标记上的替代文本来保证干净代码原则的有效性。
该属性对 SEO、搜索引擎、网络爬虫、屏幕阅读器等起着至关重要的作用。
错误代码:
<img src="demo.jpg">
好代码:
<img src="demo.jpg" alt="This is placeholder of the image">
使用 kebab-case(脊椎病例)。
对于名称,请尝试使用kebab-case
( spinal-case
) 而不要使用camelCase
或under_score
。 仅在使用 BEM 时使用under_score
,但如果您使用 Bootstrap,最好保持一致并使用-
作为分隔符。
错误代码:
<section class="section_featured_Listing"> <h1 class="largeTitle">H1 title</h1> </section>
好代码:
<section class="section-featured-listing"> <h1 class="large-title">H1 title</h1> </section>
kebab kebab-case
比camelCase
和under_score
更具可读性。
使用任何人都可以理解的有意义的名称,并保持简短。
类的名称应该类似于.noun-adjective
。
尝试使用类的通用名称,而不是编写特定于内容的名称。 它使代码更具可读性
错误代码:
<div class="team-wrapper"> <button class="large-button-green"></button> <p class="greenText-john-smith-description"></p> <div class="white-bg"></div> </div>
好代码:
<div class="section-team"> <button class="btn-lg btn-success"></button> <p class="text-success"></p> <div class="bg-white"></div> </div>
不要在 HTML5 中为样式表和脚本编写类型属性。
HTML5不需要它们,但 HTML4/XHTML 中的 W3C 标准要求它们。
错误代码:
<link type="text/css" rel="stylesheet" href="../styles.css"> <script type="text/javascript" src="..//main.js"></script>
好代码:
<link rel="stylesheet" href="styles.css"> <script src="app.js"></script>
必要时使用特定的类。
保持 CSS 选择器更具体,并选择您需要的元素; 如果没有必要,尽量不要提及他们的父母。 它将允许代码更快地呈现并消除将来的任何管理障碍
错误代码:
section aside h1 span { margin-left: 25%; }
好代码:
.left-offset { margin-left: 25%; }
虽然将类应用到目标元素可能会在 HTML 中创建更多代码,但它将允许代码更快地呈现并消除任何管理障碍。
如果您想为同一个块提供另一种样式,请向父元素添加一个类。
如果您需要使用相同的块但具有不同的样式,请尽量保持 HTML 不变。 只需将一个类添加到父元素并将所有新样式应用到 CSS 中该类的子元素。
错误代码:
<article> <h1>Same section with another styles</h1> <p>Lorem ipsum dolor sit amet, lorem sit eget proin id ipsum. </p> … </article> <article class=”another-article”> <h1 class=”other-styling-title”>Same section with another styles</h1> <p>Lorem ipsum dolor sit amet, lorem sit eget proin id ipsum. </p> … </article>
article { padding: 10px 15px; h1 { font-size: 32px; color: #ff0000; } } .another-article { padding-bottom: 30px; border-bottom: 4px solid #ccc; } h1.other-styling-title { font-size: 20px; }
好代码:
<article> <h1>Same section with another styles</h1> <p>Lorem ipsum dolor sit amet, lorem sit eget proin id ipsum. </p> … </article> <article class=”other-styling”> <h1>Same section with another styles</h1> <p>Lorem ipsum dolor sit amet, lorem sit eget proin id ipsum. </p> … </article>
article { padding: 10px 15px; h1 { font-size: 32px; color: #ff0000; } &.other-styling { padding-bottom: 30px; border-bottom: 4px solid #ccc; /* you will have less classes */ h1 { font-size: 20px; } } }
从零值中删除单位。
添加单位是不必要的,并且不会提供额外的价值。 0px、0em、0% 或任何其他零值之间没有区别。 单位并不重要,因为值仍然为零。
错误代码:
div { margin: 20px 0px; letter-spacing: 0%; padding: 0px 5px; }
好代码:
div { margin: 20px 0; letter-spacing: 0; padding: 0 5px; }
如果可以添加hr
标签,请不要在 CSS 中编写border-bottom
。
使用hr
标签而不是编写新的选择器并在 CSS 中添加边框样式。 它使代码更加基于标记,这就是我们的目标。
错误代码:
<p class="border-bottom">I want this section to have a border.</p> <p>Lorem ipsum</p>
.border-bottom { border-bottom: 1px solid #000; }
好代码:
<p>I want this section to have a border.</p> <hr> <p>Lorem ipsum</p> // If necessary change hr variable in bootstrap
使用 A > B 选择器。
使用A > B
选择器非常有帮助,它仅将规则应用于直接子项(ren),在这种情况下,您不必重置不需要该样式的所有其他子项的样式。 例如,它在编码嵌套菜单时非常有用。 您无需重新定义子菜单样式。
错误代码:
<ul> <li>List 1</li> <li>List 2</li> <li>List 3 <ul> <li>Submenu 1</li> <li>Submenu 2</li> </ul> </li> </ul>
ul li { list-style-type: none; } li ul li { /* redefine to default value */ list-style-type: disc; }
好代码:
<ul> <li>List 1</li> <li>List 2</li> <li>List 3 <ul> <li>Submenu 1</li> <li>Submenu 2</li> </ul> </li> </ul>
ul > li { list-style-type: none; }
如何编写干净的 HTML
继续讨论 HTML,首要任务是确保一个健壮且易于维护的前端。
尝试拥有一个尽可能基于标记的前端。
使您的前端代码基于标记,而不是编写过多的 CSS。
这将有助于搜索引擎并使您的代码更具可读性,从而可能提高搜索排名和用户体验。
错误代码:
<div class="main-content"> <p class="content-title">Main text title</p> <img src="http://via.placeholder.com/150x150" alt="example"> <p class="image-description">Here is image description</p> </div>
好代码:
<main> <h1>Main text title</h1> <figure> <img src="http://via.placeholder.com/150x150" alt="example"> <figcaption> Here is image description </figcaption> </figure> </main>
避免在 HTML 中使用不必要的包装器。
尽量不要在 HTML 中使用不必要的包装元素。 拥有大量的<div>
和<span>
元素已成为过去。 保持细化和线性使您能够实现最少的代码(见下一点)。
错误代码:
<section class=”container”> <div class=”row”> <div class=”col-xs-12”> <div class=”inner-wrapper”> <span>Unnecessary br tags</span> </div> </div> </div> </section>
好代码:
<section class=”container”> <p>Unnecessary br tags</p> </section>
使用原子类进行样式设置。
不要使用任何自定义颜色或字体大小(如果颜色或字体大小不在框架中,只需添加您的原子类)。 原子类是简单的、单一用途的样式单元。 很像内联样式,原子样式只应用一个样式声明。
错误代码:
<h1>Without using atomic class</h1> <p>Paragraph without atomic class</p> <section> <h1> Another h1 text</h1> <p>Paragraph inside div without class</p> </section>
h1 { color: red; } section > h1 { color: blue; }
好代码:
<h1 class="text-red">Without using atomic class</h1> <p>Paragraph without atomic class</p> <section> <h1 class="text-blue"> Another h1 text</h1> <p>Paragraph inside div without class</p> </section>
.text-red { color: red; } .text-blue { color: blue; }
尽量保持细化和原子类,并在需要时使用它们。 因此,您的前端将变得更加基于标记。
利用语义元素。
使用语义可以提供更好的结构并使代码和内容更易于阅读。
错误代码:
<span class="heading"><strong>Welcome</strong></span> <span>This is unnecessary br tag.</span>
好代码:
<h1>Welcome</h1> <p>This is unnecessary br tag.</p>
使用 HTML5 标签。
新标签为您提供更多表达自由并标准化常见元素,从而改进文档的自动化处理。 这是所有元素的可靠列表。 我发现很多开发人员总是使用很多<div>
和<span>
,但首先请在此处检查哪些标签在逻辑上适合您的上下文:
错误代码:
<div class="article-blue"> <div class="article-title-red">HTML 4 title</div> <div class="content"> Semantics <span class="boldtext">are</span> important. </div> </div>
好代码:
<article> <h1>HTML5 title</h1> <p> Semantics <strong>are</strong> important. </p> </article>
底线:学习和使用 HTML5 中的新元素。 这是非常值得的!
CSS:清洁代码和预处理器
当谈到 CSS 时,很难不从一些非原创但时髦的建议开始:
使用 CSS 预处理器。
Sass 是世界上最成熟、最稳定、最强大的专业级 CSS 扩展语言。
Sass 有两种可用的语法。 第一个,称为 SCSS (Sassy CSS),在本参考资料中使用,是 CSS 语法的扩展。 第二种和更旧的语法,称为缩进语法(或有时简称为“Sass”),提供了一种更简洁的 CSS 编写方式。
分组选择器:在 SASS 中使用 @extend。
通过对选择器进行分组,或在 SASS 中使用@extend
,您应该有助于保持代码干燥(不要重复自己)。
错误代码:
p { font-size: 22px; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } h1 { font-size: 41px; color: #000; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
好代码:

.font-smoothing { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } p { font-size: 22px; @extend .font-smoothing; } h1 { font-size: 22px; @extend .font-smoothing; }
在 CSS 中使用 rem 单位而不是像素。
将 REM 用于大小和间距,例如它根据根<html>
元素的font-size
制作的字体大小。 它们还允许您通过更改根字体大小(例如在某个媒体查询/屏幕大小)来快速缩放整个项目。
您将为响应式视图编写更少的代码:
错误代码:
p { font-size: 22px; padding: 10px; } @media (max-width: 767px) { p { font-size: 16px; padding: 5px; } }
好代码:
html { font-size: 14px; } @media (max-width: 767px) { html { font-size: 12px; } } p { font-size: 1.6rem; padding: 1rem; }
尽量避免在 CSS 中使用固定的高度或宽度。
尽量避免在 CSS 中使用固定的高度或宽度。 高度可以通过内部内容+填充来生成,宽度可以由网格系统定义(必要时使用嵌套网格)。
错误代码:
<footer class="text-center"> <h2>Let's Get In Touch!</h2> <hr> <p>Ready to start your next project with us?</p> </footer>
#footer { height: 130px; }
好代码:
<footer class="text-center"> <h2>Let's Get In Touch!</h2> <hr> <p>Ready to start your next project with us?</p> </footer>
#footer { padding-top: 23px; padding-bottom: 47px; }
确保在 SCSS 中只使用一次父项。
当您使用 CSS 预处理器并计划为任何部分编写样式时,请确保在 CSS 中仅使用一次父项,并将所有子元素和媒体查询包含在其括号内。 这将允许您在将来进行更改时轻松地在一个地方查找和修改主要父元素。
错误代码:
.section-parent-class { position: relative; h2 { color: #ff0; } header { margin: 2rem 1rem; } } @media (max-width: 767px) { .section-parent-class { footer { padding: .5rem; } } }
好代码:
.section-parent-class { position: relative; h2 { color: #ff0; } header { margin: 2rem 1rem; } footer { @media (max-width: 767px) { padding: .5rem; } } }
在编写 CSS 规则之前考虑哪些元素会受到影响。
在编写任何 CSS 规则之前,请始终考虑哪些元素会受到影响。 如果您的更改不常见,那么以仅影响某个元素而不影响其他元素的方式编写您的规则。
错误代码:
/* Commonly used class */ .title { color: #008000; }
好代码:
/* Specify it not to affect other titles */ .section-blog .title { color: #008000; }
尝试在编写新的 CSS 规则和变量之前查找现有的 CSS 规则和变量。
始终在自定义 CSS 和框架中寻找适合所需样式的现有规则。 只有当没有足够的东西时,才继续写一个新的。
这在使用大型应用程序时尤其重要。
错误代码:
.jumbotron { margin-bottom: 20px; }
好代码:
// change $jumbotron-padding from _variables.scss .jumbotron { margin-bottom: $jumbotron-padding; }
使用特定规则。
如果背景有一个属性,我们指定那个属性,但是如果它有不同的背景属性,我们可以给它一个声明。
错误代码:
.selector { background: #fff; }
好代码:
.selector { /* This way background image will not be overwritten if there is any */ background-color: #fff; }
使用速记属性和值。
尽量使用更多的速记属性和值。 使用速记属性,您可以编写简洁且通常更具可读性的样式表,从而节省宝贵的时间和精力。
错误代码:
img { margin-top: 5px; margin-right: 10px; margin-bottom: 25px; margin-left: 10px; } button { padding: 0 0 0 20px; }
好代码:
img { /* Shorthand style */ margin: 5px 10px 25px; } button { /* Don't play with shorthand too much */ padding-left: 20px; }
使用em
而不是px
作为行高。
使用em
和px
单位为我们的设计提供了灵活性,并且能够向上和向下缩放元素,而不是被固定尺寸所束缚。 我们可以利用这种灵活性使我们的设计在开发过程中更容易调整和响应更快,并允许浏览器用户控制网站的整体规模以获得最大的可读性。
错误代码:
p { font-size: 12px; line-height: 24px; }
好代码:
p { font-size: 12px; line-height: 2em; /* or just line-height: 2; */ }
尽可能使用 Bootstrap 类。
虽然这条规则通常适用于 UI 框架,但我以 Bootstrap 为例,因为它是世界上最流行的前端组件库。
Bootstrap 允许你使用很多现成的类,让你的工作更轻松。 尝试尽可能多地使用 Bootstrap 类,以制作更多基于 HTML 的标记。
错误代码:
<section class="without-bootstrap"> <div class="first-column">Lorem ipsum dolor sit amet, ut ius delenit facilisis</div> <div class="second-column">Lorem ipsum dolor sit amet, ut ius delenit facilisis</div> </section>
.first-column, .second-column { width: 25%; float: left; padding-left: 15px; padding-right: 15px; } ...
好代码:
<section class="row"> <div class="col-md-6">Lorem ipsum dolor sit amet, ut ius delenit facilisis</div> <div class="col-md-6">Lorem ipsum dolor sit amet, ut ius delenit facilisis</div> </section>
正确自定义您的框架。
Bootstrap 依赖于 variables.scss 文件,它允许您轻松配置和自定义前端,而无需编写任何代码。 否则,如果您要自己手动编写所有自定义项,最好不要使用框架。
一些开发人员避免更改 variables.scss,认为他们仍然可以轻松地将 Bootstrap 升级到新版本,但这可能是一项乏味的任务。 即使是很小的更新也需要开发人员阅读更改日志,检查所有标记和 CSS,然后手动迁移到新版本。
错误代码:
navbar { padding: 20px 10px; } .carousel-indicators { li { width: 6px; height: 6px; margin-right: 3px; margin-left: 3px; } }
好代码:
$navbar-padding-y: ($spacer / 2) !default; $navbar-padding-x: $spacer !default; $carousel-indicator-width: 30px !default; $carousel-indicator-height: 3px !default; $carousel-indicator-spacer: 3px !default;
不要覆盖.container
宽度。
尽量不要覆盖.container
的宽度。 尝试改用网格系统,或者只是更改_variables.scss
中的容器宽度。 如果您需要减小它的宽度,只需使用 max-width 而不是宽度。 在这种情况下,来自 Bootstrap 的.container
将在响应式视图中保持不变。
错误代码:
.container { @media (min-width: $screen-lg-min) { width: 1300px; } }
好代码:
// change $container-lg from _variables.scss .container { @media (min-width: $screen-lg-min) { width: $container-lg; } }
使用 Bootstrap 4 类并少写 CSS。
开始使用 Bootstrap 4,即使它处于测试阶段。 它包括许多新的类,可以帮助您更快地创建布局,尤其是 Flexbox 和 spacers。
错误代码:
<div class="flex-ex"> <div>Flex item 1</div> <div>Flex item 2</div> <div>Flex item 3</div> </div> <div class="flex-ex flex-reverse"> <div>Flex item 1</div> <div>Flex item 2</div> <div>Flex item 3</div> </div>
.flex-ex { display: flex; > div { padding: 2px; } &.flex-reverse { flex-direction: row-reverse; } li { list-style: none; padding: .5rem; } }
好代码:
<ul class="list-unstyled list-inline d-flex flex-row"> <li class="p-2">Flex item 1</li> <li class="p-2">Flex item 2</li> <li class="p-2">Flex item 3</li> </ul> <ul class="list-unstyled list-inline d-flex flex-row-reverse"> <li class="p-2">Flex item 1</li> <li class="p-2">Flex item 2</li> <li class="p-2">Flex item 3</li> </ul>
现在我们可以将类分配给一个元素以删除所有边框或某些边框。
错误代码:
<div class="border-example2 py-5"> <span class="border0"></span> <span class="border-top0"></span> <span class="border-right0"></span> <span class="border-bottom0"></span> <span class="border-left0"></span> </div>
border-example2 { > span { width: 100px; height: 100px; display: inline-block; margin: .50rem; background-color: #e1e1e1; border: 1px solid; &.border0 { border: none; } &.border-top0 { border-top: none; } &.border-right0 { border-right: none; } &.border-bottom0 { border-bottom: none; } &.border-left0 { border-left: none; } } }
好代码:
<div class="border-example py-5"> <span class="d-inline-block m-2 border-0"></span> <span class="d-inline-block m-2 border-top-0"></span> <span class="d-inline-block m-2 border-right-0"></span> <span class="d-inline-block m-2 border-bottom-0"></span> <span class="d-inline-block m-2 border-left-0"></span> </div>
.border-example { > span { width: 100px; height: 100px; background-color: #e1e1e1; border: 1px solid; } }
如果.col-md-X
和.col-lg-X
对 X 具有相同的值,则使用.col-sm-X
。
如果.col-sm-X
具有相同的值,则不要写.col-md-X
和.col-lg-X
。例如,不需要写.col-lg-10
因为当我们写.col-md-10
,我们会自动在其中包含.col-lg-10
。
错误代码:
<ul class="press-list list-inline row"> <li class="col-lg-4 col-md-4 col-sm-4 col-xs-6"><a href="#"><img class="img-fluid" src="assets/images/press/press-1.png" alt=""></a></li> <li class="col-lg-4 col-md-4 col-sm-4 col-xs-6"><a href="#"><img class="img-fluid" src="assets/images/press/press-2.png" alt=""></a></li> </ul>
好代码:
<ul class="press-list list-inline row"> <li class="col-md-4 col-xs-6"><a href="#"><img class="img-fluid" src="assets/images/press/press-1.png" alt=""></a></li> <li class="col-md-4 col-xs-6"><a href="#"><img class="img-fluid" src="assets/images/press/press-2.png" alt=""></a></li> </ul>
不要使用.col-xs-12
。
不要使用.col-xs-12
,因为如果没有分配.col-xs-X
,则默认为.col-xs-12
。
错误代码:
<section> <div class="container"> <div class="row"> <div class="col-lg-12 text-center"> <h2>Services</h2> <h3 class="text-muted">Lorem ipsum dolor sit amet consectetur.</h3> </div> </div> <div class="row text-center"> <div class="col-md-6 col-xs-12"> <h4>E-Commerce</h4> <p class="text-muted">Lorem ipsum dolor sit amet, consectetur adipisicing.</p> </div> </div> </div> </section>
好代码:
<section class="text-center"> <div class="container"> <h2>Services</h2> <h3 class="text-muted">Lorem ipsum dolor sit amet consectetur.</h3> <div class="row"> <div class="col-md-6"> <h4>E-Commerce</h4> <p class="text-muted">Lorem ipsum dolor sit amet, consectetur adipisicing.</p> </div> </div> </div> </section>
不要使用reset.css
; 改用normalize.css
。
如果您使用的是 Bootstrap,那么normalize.css
已经包含在其中,无需包含两次。
遵循指南,即使它们不是最佳实践。
为了保持一致性,最好始终遵循您开始使用的规则和指南(无论它们是关于命名、代码样式还是文件结构)
包起来
我希望你已经能够带走一些有用的东西,并且你会更多地考虑使用最佳实践编写最少的 HTML 和 CSS 代码。
对于大公司来说,当代码混乱时,维护大型应用程序是相当困难的。 当然,大公司有钱为优质买单。 如果您遵循干净的编码原则,您将提高找到一份好工作的机会。 还值得提出自由职业者方面的问题:处理多个项目和客户的专业人士必须提供干净的代码,这些代码可以立即传递给其他开发人员。
我希望在未来的文章中扩展到更高级的主题,因为我打算讨论自动化编码过程,使用 Gulp/Grunt 任务、Linter、编辑器插件、生成代码的工具、代替你编写代码的 AI 工具,以及其他相关话题。
我希望这是一次有趣且内容丰富的阅读。 祝你编码工作好运。
进一步阅读 Toptal 工程博客:
- 如何在 CSS 中处理 SVG 动画