About semantics
Semantics studies the relationship between signs and symbols, and the meanings they represent. In linguistics, it is the study of the meaning of symbols (such as words, phrases, or sounds) in language. In the field of front-end development, semantics mainly involves the agreed meanings of HTML elements, attributes, and attribute values (including extensions like Microdata). These formal convention semantics, commonly used in specifications, can help programs (and later people involved in development) better understand all aspects of a website. However, even if the semantics of these elements, attributes, and attribute values are formalized, they are still subject to developer adaptation and collective choices. This makes it possible that the formal contract semantics may be modified in the future (and this is one of the HTML design principles).
Distinguish different types of HTML semantics
Following the principle of writing "semantic HTML" is one of the foundations of modern professional front-end development. Most of the semantics are related to the current or expected nature of the content (eg: h1 element, lang attribute, email value of type attribute, Microdata).
However, not all semantics need to be content-oriented. Class names cannot be "semantic". No matter what the names are, they must have meaning and purpose. The semantics of class names can be different from those of HTML elements. We can use the "global" semantics of HTML elements, certain HTML attributes, Microdata, etc., and then use the "local" specific semantics of the website or application to differentiate. These specific semantics are usually included in attribute values, such as class attributes. .
Although this supposed "best practice" is reiterated in the class attribute section of the HTML5 specification...
...developers are encouraged to use the class attribute value to describe the actual content, rather than the description What is expected to be displayed.
…There is no inherent reason why we must do this. In fact, when this approach is used on large websites or applications, it can often become a hindrance.
HTML elements and other attributes already provide content-level semantics
For machines or visitors, class names can reveal very little or even no useful semantic information. Unless it is a small part of the name that has been agreed upon (also machine-readable) - Mircoformats
The main purpose of the class name is to become a hook for CSS and JavaScript. If you don't need to add presentation and behavior to your pages, then you probably don't need to add class names to your HTML. Class names should convey useful information to developers. When you read a DOM fragment, it will help to understand the specific purpose of a certain class name. Especially in a multi-person development team, front-end developers are not the only ones who deal with HTML components.
<p class="news"> <h2>News</h2> [news content] </p>
Content-independent class names
Front-end architecture
Reusable and composable components
避免用类型选择器支持class,可以让组件更容易合并。下面这个例子中,btn组件与uilist组件不易于合并。问题在于.btn的权重比.uilist a要小(这将覆盖任何共享属性)。而且ulist组件需要锚点作为子节点。
.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组件与其它组件轻松组合的方法是,uilist的子级DOM元素用class来添加样式。尽管这会降低权重,但是它的主要好处在于,它为你提供了处理子节点的任何结构样式的选择权。
.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的钩子使用一种特定的类——js-*——不要在这个类名上添加任何描述。
<a href="/login" class="btn btn-primary js-login"></a>
在你修改组件的结构或样式的时候,可能会不经意间对那些必要的JavaScript行为和复杂的功能造成影响,用这种方法的话,可以降低这种可能性。
组件修改器
组件常常会有一些变体,它们与基本组件只有细微的差别。比如,不同的背景色或者边框。主要有两种创建这些组件变体的模式。我将它们称为“单类名”模式和“多类名”模式。
单类名模式
.btn, .btn-primary { /* 按钮模板样式 */ } .btn-primary { /* 主按钮的特殊样式 */ } <button class="btn">Default</button> <button class="btn-primary">Login</button>
多类名模式
.btn { /* 按钮模板样式 */ } .btn-primary { /* 主按钮的特殊样式 */ } <button class="btn">Default</button> <button class="btn btn-primary">Login</button>
如果你使用预处理程序,你可以用Sass的@extend功能,以减少一些在使用“单类名”模式时所涉及的维护工作。然而,即使有预处理程序的帮忙,我依然倾向于使用“多类名”模式,并在HTML中修改类名。
我发现这是一种更具扩展性的模式。比如,要实现一个基本的btn组件,并增加5种类型的按钮与3种额外的尺寸。用“多类名”模式的话只要9个class就可以搞定,用“单类名”模式则需要24个class。
如果需要的话,它也更容易让上下文环境适应组件。你可能想对出现在其它组件中的任一btn做一些细节调整。
/* “多类名”样式调整 */ .thing .btn { /* 相应的样式调整 */ } /* “单类名”样式调整 */ .thing .btn, .thing .btn-primary, .thing .btn-danger, .thing .btn-etc { /* 相应的样式调整 */ }
“多类名”模式意味着,你只需要用一个单独的组件内部选择器,便可以改变所有类型的btn元素的样式。“单类名”模式意味着,你必须顾及所有可能的按钮类型,并在创造一个新的按钮变体时调整这个选择器。
结构化的类名
当创建一个组件时——并为之添加了“主题”——其中一些class被用来区分各个组件,一些class被当做组件的修改器,其它的class则被用来关联DOM节点,它们一起被包含在一个较大的抽象组件中。
很难去判断btn(组件)、btn-primary(修改器)、brn-group(组件)和btn-group-item(组件子对象)之间的关系,这是因为这些名字不能清晰地表现class的目的。没有一致的模式。
在过去的一年中,我一直在尝试命名模式,目的是能帮助我快速理解在一个DOM片段中节点的表象之间的关系,而不用为此来回切换HTML、CSS与JS文件拼凑网站的架构。这种模式主要受到BEM系统的命名方法的影响,但被改编成一种我认为更容易浏览的形式。
t-template-name t-template-name--modifier-name t-template-name__sub-object t-template-name__sub-object--modifier-name</p> <p>component-name component-name--modifier-name component-name__sub-object component-name__sub-object--modifier-name</p> <p>is-state-type</p> <p>js-action-name js-component-type
我将一些结构当做抽象的“模板”来处理,其它的则视为更清晰的组件(通常建立在“模板”上)。但是这种区分并非总是必要的。
这仅仅是我目前发现的一种有用的命名模式。命名模式可以采用任何形式。但这种命名模式的好处在于消除了模糊的类名,只依赖(单)连接符,或者下划线,或者是驼峰格式。
原始文件大小和HTTP压缩的注意事项
任何关于模块化与可扩展的CSS的讨论都会谈及对文件大小与“膨胀”的担心。Nicole Sullivan的言论中经常会提到文件大小的存储(以及维护改进),并提到了像Facebook这样的公司采用这种方法的经历。进一步的,我想我会分享我在预处理输出时的HTTP压缩效果,以及大量使用HTML类的一些事情。
当Twitter Bootstrap刚刚问世的时候,我重写了已编译的CSS,以便更好地与手动操作的文件比较大小。在最小化所有的文件之后,手动操作的CSS文件比预处理程序输出的小10%。但是当所有的文件都通过gzip压缩后,预处理程序输出的CSS文件比手动操作的小了5%。
这强调了比较HTTP压缩后文件大小的重要性,因为减少的文件大小并不能说明全部问题。它暗示了有经验的CSS开发者在用预处理程序时不必太过关注编译后的CSS中一定程度的重复,因为它将在HTTP压缩后变得更小。通过预处理程序处理更易于维护的CSS代码所带来的好处,要胜过关注原始CSS和压缩后输出的CSS的美观或文件大小。
In another experiment, I scraped a 60KB HTML file from the Internet (composed of many reusable components) and deleted each of its class attributes. After this processing, the file size is reduced to 25KB. When both the original file and the extracted file are compressed by gzip, their sizes become 7.6KB and 6KB respectively - a difference of only 1.6KB. The actual file size consequences of liberal use of classes are no longer worth stressing.
For more articles on the semantics of HTML and related front-end frameworks, please pay attention to the PHP Chinese website!