查看原文
其他

【第1220期】关于 HTML 语义和前端架构

2018-03-20 飘飘 前端早读课

前言

搞前端,有一股子往框架里钻的姿势,或者直接利用UI框架直接开发,但还会单纯的写写页面吗?今日早读文章由@飘飘翻译授权分享。

正文从这开始~

一系列我喜欢的想法、经历和想法, 以及我在过去的一年里一直在尝试的想法。 它涵盖了 HTML语义、组件和前端架构、类命名模式和 HTTP压缩的方法。

关于语义

语义是研究符号和符号之间,以及它们所代表事物之间的关系。 在语言学中, 主要是研究语言中的符号所表达的含义(如单词、短语或声音)。 在web前端开发的背景下, 语义主要涉及 HTML 元素、属性和属性值(包括 Microdata 扩展)的意义。 这些约定好的语义, 通常以正式的规范, 可以用来帮助程序(以及随后的人类)更好地理解网站上各个方面的信息。 然而, 即使在规范化之后, 元素、属性和属性值的语义也会受到开发人员的共同选择的和实现的影响。 这可能导致后期对正式约定的语义进行修改(这是一个 HTML 设计原则)。

区分不同类型的 HTML 语义

编写具有”语义HTML”原则是现代专业前端开发的基础之一。 大部分语义都与现有或预期内容的性质有关(例如 h1元素、 lang 属性、类型属性的电子邮件值、 Microdata)。

然而, 并不是所有的语义都需要以内容为基础。 类名不能是”非语义”的。 不管使用的是什么名字: 它们都需要有意义, 有目的。 类名语义不同于 HTML 元素,我们可以利用HTML元素、特定的HTML属性,如 Microdata 等约定的全局语义。 它们的目的不会和 包含在类属性等属性值中的”local”网站 / 应用程序特定语义的产生混淆。

尽管关于类的 HTML5规范部分再次假定的”最佳实践”。

鼓励作者使用[类属性]值来描述内容性质, 而不是描述内容所需表现形式的值。

没有固有的理由这样做。 事实上, 在大型网站或应用程序上工作时, 这通常是一个障碍。

  • 内容层语义已经服务于被HTML 元素和其他属性

  • 类名对机器或访问者提供很少或根本就没有的有用语义信息, 除非它是一小组商定的(机器可读)名称的一部分—— Microformats

  • 类名的主要目的是成为 CSS 和 JavaScript 的一个钩子。 如果你不需要在你的web文档中添加行为和表现, 那么你可能不需要在 HTML 中添加类

  • 类名应该向开发人员传达有用的信息。 当你阅读 DOM 代码片段时, 理解特定的类名会有所帮助, 尤其是在多人开发团队中, 前端开发者不是唯一开发 HTML 组件的。

以下是一个非常简单的例子:

<div class="news">
   
<h2>News</h2>
   [news content]
</div>

类名”news”并没有告诉你任何信息,从内容本身来看也不是很明显。 它不提供关于组件的架构结构的信息, 也不能使用不是”news”的内容。 将类名语义与实际的内容紧密联系在一起, 已经降低了架构扩展的能力, 或者被其他开发人员使用的易用性。

内容独立的类名

另一种方法是从设计中重复结构和功能模式衍生出类名语义。 最可重用的组件是那些与内容无关的类名。

我们不用担心层与层之间的连接清晰明确, 而应该担心类名严格地反映特定的内容。 这样做并不是意味使用类名”没有语义”, 只是意味着它们的语义不是从内容中派生出来的。 如果有助于创建更健壮、灵活和可重用的组件,不介意使用包含额外的 HTML 元素, 这样做并不意味着 HTML 是”非语义的”, 它只是意味着你使用的元素超出了标记内容所需的最低限度。

前端架构

组件 / 模板 / 面向对象架构的目的是能够开发数量有限的可重用组件, 这些组件可以包含多种不同的内容类型。 在大型应用程序中, 类名语义的重要之处在于, 它们由实用主义的衍生并更好的服务于它们的主要目的——为开发人员提供有意义的、灵活的和可重用的表象 / 行为钩子。

可重用组件和组合组件

一般来说, 可扩展的 HTML / css 必须依赖于 HTML 中的类来创建可重用的组件。 一个灵活和可重用的组件既不依赖于现存的DOM 树中某部分, 也不需要使用特定的元素类型。 它应该能够适应不同的容器, 并且很容易样式化。 如果有必要, 可以使用额外的 HTML 元素(超出仅仅需要标记内容的元素) , 并且可以用来使组件更加健壮。 一个很好的例子就是 Nicole Sullivan 所说的media object。

可以很容易地组合起来的组件受益于选择器类型,避免使用类型选择器。 下面的示例降低了 btn 组件与 uilist 组件的组合。 问题在于.btn 的优先级低于.Uilist a的 (覆盖重复的样式属性) , 而 uilist 组件需要作为子节点的锚。

.btn { /* styles */ }
.uilist { /* styles */ }
.uilist a { /* styles */ }
<nav class="uilist">
   
<a href="#">Home</a>
   
<a href="#">About</a>
   
<a class="btn" href="#">Login</a>
</nav>

一种改进的方式是,将其他组件与uilist结合的方法是用类来对子DOM元素添加样式。

尽管这有助于减少规则的特殊性, 但主要的好处是它可以让您选择将结构样式应用于任何类型的子节点。

.btn { /* styles */ }
.uilist { /* styles */ }
.uilist-item { /* styles */ }
<nav class="uilist">
   
<a class="uilist-item" href="#">Home</a>
   
<a class="uilist-item" href="#">About</a>
   
<span class="uilist-item">
       
<a class="btn" href="#">Login</a>
   
</span>
</nav>

javascript特定类

使用某种形式的JavaScript特定类可以降低因组件主题或结构变化而破坏任何应用的 JavaScript 的风险。 我发现一个有用的方法是使用只用于 JavaScript的某些类如 hooks-js-*-,并且不要将任何样式关联起。

<a href="/login" class="btn btn-primary js-login"></a>

这样, 您就可以减少改变组件的结构或主题会无意中影响到任何所需的 JavaScript 行为和复杂的功能。

组件修饰符

组件通常具有基本组件略有不同的表示形式, 例如, 不同颜色的背景或边框。 有两种主要模式用于创建这些组件变量。 我要把它们称为”单类”和”多类”模式。

“单一类”模式

.btn, .btn-primary { /* button template styles */ }
.btn-primary { /* styles specific to save button */ }
<button class="btn">Default</button>
<button class="btn-primary">Login</button>

“多类”模式

.btn { /* button template styles */ }
.btn-primary { /* styles specific to primary button */ }
<button class="btn">Default</button>
<button class="btn btn-primary">Login</button>

如果您使用预处理器, 您可能使用 Sass 的@extend 功能来减少使用”单级”模式所涉及的一些维护工作。 然而, 即使在预处理器的帮助下, 我偏好使用”多类”模式, 在 HTML 中添加修饰符类。

我发现它是一个更可伸缩的模式。 例如, 使用基本的 btn 组件, 再添加5种按钮和3个额外大小。 使用”多类”模式, 你最终会得到9个可以混合和匹配的类。 使用”单一类”模式, 你最终会得到24个类。

如果绝对必要的话, 对组件进行上下文调整也更容易。 您可能需要对另一个组件中出现的任何 btn 进行小调整。

/* "multi-class" adjustment */
.thing .btn { /* adjustments */ }
/* "single-class" adjustment */
.thing .btn,
.thing .btn-primary,
.thing .btn-danger,
.thing .btn-etc { /* adjustments */ }

“多类”模式意味着您只需要一个单独的组件内部选择器来针对组件中的任何类型的 btn 风格元素。 “单个类”模式意味着您可能需要对任何可能的按钮类型进行解释, 并在创建新的按钮变体时调整选择器。

结构化的类名

在创建基于它们的组件和”主题”时, 一些类被用作组件边界, 有些用作组件修饰符, 另一些则用于将 DOM 集合中的节点关联到一个更大的抽象表示组件。

很难推断 btn (组件)、 btn-primary (修饰符)、 btn-group (组件)和 btn-group-item (组件子对象)之间的关系, 因为名称不能清楚地表明类的目的。 没有一个统一的模式。

在2011年初, 我开始尝试命名模式, 帮助我更快地理解 DOM 片段中节点之间的表现关系, 而不是试图通过在 HTML、 CSS 和 JS 文件之间来回切换来拼凑网站的架构。 Gist 中的符号主要受到 BEM 系统命名方法的影响, 但是我发现这种方法更容易被扫描。

自从我第一次写这篇文章以来, 其他几个团队和框架也采用了这种方法。 Montagejs 将符号改成了一种不同的风格, 我更喜欢并且目前在 SUIT 框架中使用:

/* Utility */
.u-utilityName {}
/* Component */
.ComponentName {}
/* Component modifier */
.ComponentName--modifierName {}
/* Component descendant */
.ComponentName-descendant {}
/* Component descendant modifier */
.ComponentName-descendant--modifierName {}
/* Component state (scoped to component) */
.ComponentName.is-stateOfComponent {}

这只是一个我现在觉得有用的命名模式。 它可以采取任何形式。 但好处在于消除只依赖(单个)连字符、下划线或驼峰情况的类名的模糊性。

有关原始文件大小及 HTTP压缩

与任何关于模块化 / 可伸缩 CSS 的讨论更多关注的是对文件大小和”bloat”。 妮可 · 沙利文的演讲经常提到像 Facebook 这样的公司在采用这种方法时所经历的文件大小的节省(以及维护的改进)。 此外, 我想与大家分享一下我的奇闻轶事: HTTP压缩对处理器前输出的影响, 以及 HTML 类的广泛使用。

当 Bootstrap 第一次出现时, 我重新编写了编译的 CSS, 以更好地反映我将如何手工编写它并比较文件大小。 在将这两个文件缩小后, 手工制作的 CSS 比预处理器输出小10% 左右。 但是, 当这两个文件也被 gzipped, 预处理器输出大约比手工制作的 CSS 小5% 。

这突出了比较 HTTP压缩之后文件大小的重要性, 因为小型化的文件大小并不能说明整个故事。 这表明, 有经验的 CSS 开发者在使用预处理器的时候不需要过度关注编译的 CSS 中某种程度的重复, 因为在 HTTP压缩之后, 它可以很好地适应更小的文件大小。 通过预处理器获得更多可维护的”CSS”代码的好处, 应该能够消除人们对于原始 CSS 和小型化 CSS 的美观和尺寸的担忧。

在另一个实验中, 我从一个 live 站点中提取的60KB 的 HTML 文件中删除了每一个类属性(已经由许多可重用组件组成)。 这样做可以将文件大小缩小到25KB。 当原始文件和剥离文件被 gzipped, 它们的大小分别为7.6 KB 和6KB, 差异为1.6 KB。 自由主义阶级使用的实际文件大小后果很少值得强调。

我是如何学会不再担心

多年来, 许多熟练开发者的经验, 已导致大型网站和应用程序的开发方式发生了转变。 尽管如此, 对于那些对”语义 HTML”(semantic HTML)意味着使用内容衍生的类名(即便如此, 也只是作为最后的手段) , 它通常要求你在敏锐地意识到这种方法不切实际的性质之前, 通常需要你对一个大型应用程序进行研究。 你必须准备好抛弃旧想法, 寻找替代方案, 甚至重新审视你之前可能摒弃的方式。

一旦你开始写大型的网站和应用程序, 你和其他人不仅必须维护, 而且必须积极地迭代, 你很快就会意识到, 尽管你尽了最大的努力, 你的代码开始变得越来越难以维护。 很值得花时间去探索一些人的工作, 他们已经提出了他们自己的方法来解决这些问题: Nicole 的博客和面向对象的 CSS 项目, Jonathan Snook 的 Scalable 模块化架构 CSS, 以及 Yandex 开发的 Block Element Modifier 方法。

当你选择用一种方式来编写 HTML 和 CSS 来减少你花在编写和编辑 CSS 上的时间时, 你必须花更多的时间来改变 HTML 类型, 如果你想改变他们的风格。 对于前端和后端开发人员来说, 这都是相当实用的——任何人都可以重新安排预制的”乐高积木”; 事实证明, 没有人能够使用 CSS-alchemy。

最后,为你推荐:

【第1195期】现代CSS进化史

【第1183期】这些 CSS 命名规范,将省下你大把调试时间

关于本文

译者:@飘飘

作者:@Nicolas Gallagher

原文:http://nicolasgallagher.com/about-html-semantics-front-end-architecture/

【图书】前端架构设计


【活动】3月31日,中国第四届CSS大会相约厦门

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存