Home  >  Article  >  Web Front-end  >  Decouple HTML, CSS and JS

Decouple HTML, CSS and JS

高洛峰
高洛峰Original
2017-02-06 15:43:41935browse

Currently on the Internet, any slightly complex website or application will contain a lot of HTML, CSS and JavaScript. As the use of the Internet evolves and our dependence on it increases, having a plan for organizing and maintaining your front-end code is an absolute must.

Some of today's large Internet companies, because more and more people will be exposed to an increasing number of front-end codes, they will try to maintain the modularity of the code. Changing part of the program's code in this way will not inadvertently affect the execution of subsequent unrelated parts too much.

Preventing unintended consequences is not an easy problem to solve, especially since HTML, CSS, and JavaScript are inherently interdependent. To make matters worse, when it comes to front-end code, some traditional computer science principles, such as separation of concerns, long used in server-side development, are rarely discussed.

In this article, I will talk about what I learned how to decouple my HTML, CSS and JavaScript code. From personal and other people's experience, the best way to do this is not obvious, is often unintuitive, and sometimes goes against many so-called best practices.


Goal

There will always be a coupling relationship between HTML, CSS and JavaScript. Regardless, these technologies are inherently designed to interact with one another. For example, a flash transition effect might be defined in a stylesheet with a class selector, but it is often initialized by HTML and triggered by user interaction, such as writing JavaScript. Since some coupling of front-end code is unavoidable, your goal should not be to simply eliminate the coupling, but to reduce unnecessary dependency couplings between codes. A backend developer should be able to make changes to markup in HTML templates without worrying about accidentally breaking CSS rules or some JavaScript functionality. As today's web teams grow larger and more specialized, this goal is greater than ever.


Anti-Pattern

Tight coupling of front-end code is not always obvious. The complication is that on the one hand it appears to be loosely coupled, but on the other hand it is tightly coupled. Below are all the anti-patterns I have done or seen many times and learned from my mistakes. For each pattern, I'll try to explain why coupling is so bad and point out how to avoid it.


Overly complex selectors

CSS Zen Garden showed the world that you could completely change the look of an entire website without changing a single HTML tag. This is typical of the Semantic Web movement, where one of the main principles is to avoid using presentational classes. At first glance, CSS Zen Garden might look like a good example of decoupling; after all, separating style from markup language is its whole point. However, if you do this, the problem arises. You will often need to have such a selector in your style sheet, as follows:

#sidebar section:first-child h3 + p { }

CSS In Zen Garden, although HTML is almost completely separated from CSS, However, CSS will be strongly coupled to HTML, which requires you to have a deep understanding of the structure of the markup language. This may not seem like a bad thing, especially if someone maintains the CSS and needs to maintain the HTML at the same time, but once you add a lot of people into it, the situation becomes unmanageable. If a developer adds a dc6dce4a544fdca2df29d5ac0ea9906b before the first 2f8332c8dcfd5c7dec030a070bf652c3 under certain circumstances, the above rule will not take effect, but he does not know why.


As long as your site’s markup rarely changes, CSS Zen Garden is a very good idea. But this is not necessarily the case with today's web applications. Compared with long and complicated CSS selectors, the best way is to add one or more class selectors to the root element of the visual component itself. For example, if the sidebar has submenus, you only need to add a submenu class selector for each submenu element instead of using this form:

ul.sidebar > li > ul {
  /* submenu styles */
}

The result of this method is that more elements are needed in the HTML class selectors, but in the long run this reduces coupling, makes code more reusable and maintainable, and also makes your markup self-documenting. Without class selectors in HTML, developers unfamiliar with CSS wouldn't know how changes to HTML affect other code. On the other hand, using class selectors in HTML makes it very clear which styles or features are being used.


The responsibilities of multiple class selectors

A class selector is often used as both a style and JavaScript hook. Although this may seem economical (because at least one class tag is reduced), in fact, it couples the performance and functionality of the element.

<button class="add-item">Add to Cart</button>

The above example describes an "Add to Cart" button with an add-item class style.

如果开发者想为此元素添加一个单击事件监听器,用已经存在的类选择器作为钩子非常的容易。我的意思是,既然已经存在了一个,为何要添加另一个呢? 但是想想看,有很多像这样的按钮,遍布了整个网站,都调用了相同的JavaScript功能。再想想看,如果市场团队想要其中一个和其它看起来完全不同但功能相同的按钮呢。也许这样就需要更多显著的色彩了。


问题就来了,因为监听单击事件的JavaScript代码希望add-item类选择器被使用到,但是你新的按钮又无法使用这个样式(或者它必须清除所有声明的,然后再重置新的样式)。还有,如果你测试的代码同时也希望使用add-item类选择器,那么你不得不要去更新那么代码用到的地方。更糟糕的是,如果这个”添加到购物车”功能不仅仅是当前应用用到的话,也就是说,把这份代码抽象出来作为一个独立的模块,那么即使一个简单的样式修改,可能会在完全不同的应用中引发问题。


使用javaScript钩子最好的(事实上也是比较鼓励的)做法是,如果你需要这么做,使用一种方式来避免样式和行为类选择器之间的耦合。

我的个人建议是让JavaScript钩子使用前缀,比如:js-*。这样的话,当开发者在HTML源代码中看到这样的类选择器,他就完全明白个中原因了。所以,上述的”添加到购物车”的例子可以重写成这样:

<button class="js-add-to-cart add-item">Add to Cart</button>

现在,如果需要一个看起来不同的按钮,你可以很简单地修改下样式类选择器,而不管行为的类选择器。

<button class="js-add-to-cart add-item-special">Add to Cart</button>

JavaScript更多的样式操作

JavaScript能用类选择器去DOM中查找元素,同样,它也能通过增加或移除类选择器来改变元素的样式。但如果这些类选择器和当初加载页面时不同的话也会有问题。当JavaScript代码使用太多的组成样式操作时,那些CSS开发者就会轻易去改变样式表,却不知道破坏了关键功能。也并不是说,JavaScript不应该在用户交互之后改变可视化组件的外观,而是如果这么做,就应该使用一种一致的接口,应该使用和默认样式不一致的类选择器。


和js-*前缀的类选择器类似,我推荐使用is-*前缀的类选择器来定义那些要改变可视化组件的状态,这样的CSS规则可以像这样:

.pop-up.is-visible { }

注意到状态类选择器(is-visible)是连接在组件类选择器(pop-up)后,这很重要。因为状态规则是描述一个的状态,不应该单独列出。如此不同就可以用来区分更多和默认组件样式不同的状态样式。

另外,可以让我们可以编写测试场景来保证像is-*这样的前缀约定是否遵从。一种测试这些规则的方式是使用CSSLint和HTML Inspector。

更多关于特定状态类选择可以查阅Jonathan Snnok编写的非常优秀的SMACSS书籍。


JavaScript”选择器”

jQuery和新的API,像document.querySelectorAll,让用户非常简单地通过一种他们已经非常熟悉的语言–CSS选择器来查找DOM中的元素。虽然如此强大,但同样有CSS选择器已经存在的相同的问题。JavaScript选择器不应过度依赖于DOM结构。这样的选择器非常慢,并且需要更深入认识HTML知识。

就第一个例子来讲,负责HTML模板的开发者应该能在标记上做基本的改动,而不需担心破坏基本的功能。如果有个功能会被破坏,那么它就应该在标记上显而易见。

我已经提及到应该用js-*前缀的类选择器来表示JavaScript钩子。另外针对消除样式和功能类选择器之间的二义性,需要在标记中表达出来。当某人编写HTML看到js-*前缀的类选择器时,他就会明白这是别有用途的。但如果JavaScript代码使用特定的标记结构查找元素时,正在触发的功能在标记上就不那么明显了。

为了避免使用冗长而又复杂的选择器遍历DOM,坚持使用单一的类或者ID选择器。 考虑以下代码:

var saveBtn = document.querySelector("#modal div:last-child > button:last-child")

这么长的选择器是可以节省你在HTML中添加一个类选择器,但同样让你的代码对于标记更改非常容易受到影响。如果设计者突然决定要把保持按钮放在左边,而让取消按钮放在右边,这样的选择器就不再匹配了。


一个更好的方式(使用上述的前缀方法)是仅仅使用类选择器。

var saveBtn = document.querySelector(".js-save-btn")

现在标记可以更改它想改的,并且只要类选择还是在正确的元素上,一切都会很正常。


类选择器就是你的契约

Using appropriate class selectors and predictable class name conventions can reduce coupling between almost every kind of HTML, CSS, and JavaScript. At first, using many class selectors in markup may seem like a sign of strong coupling, since you need to know the names of many class selectors in order to render the HTML. But I find that using class selectors is very similar to the event or observer pattern in traditional programming design. In event-driven programming, instead of calling object B directly on object A, object A simply publishes a specific event in the provided environment, and object B can then subscribe to that event. In this way, object B does not need to know anything about the interface of object A, but only needs to know what events to listen for. It stands to reason that the event system requires some form of coupling, because object B needs to know the event name to subscribe to, but compared with object A needing to know the public method of object B, this is already looser coupling.


HTML class selectors are all very similar. Unlike defining complex selectors in CSS files (just like the internal interface of HTML), it is possible to simply define the appearance of a visual component through a single class selector. The CSS file does not need to care whether the HTML uses class selectors or not. Likewise, JavaScript does not use complex DOM traversal functions that require a deeper understanding of HTML structure, but only listens for user interaction on elements with the same class name. Class selectors should be like the glue that holds HTML, CSS, and JavaScript together. I know from personal experience that they are also the easiest and best way to connect the three technologies without over-mixing them.


Future

The Web Hypertext Technology Working Group (WHATWG) is working on a specification for web components that will allow developers to bind HTML, CSS and JavaScript Determined together as a separate component or module, and interact with other page elements to encapsulate it. If this specification had been implemented in a majority of browsers, then many of the suggestions I provide in this article would become less important (because it would become clear who the code interacts with); but regardless, understanding these is more broadly principles and why they are needed remain important. Even though these practices will become less important in the era of web components, the theory still applies. Practices used in large teams and large applications still apply to writing small modules, but not vice versa.


Conclusion

The hallmark of maintainable HTML, CSS, and JavaScript is that every developer can write every part of the codebase easily and with confidence , without worrying that these modifications will inadvertently affect other unrelated parts. One of the best ways to prevent unintended consequences like this is to give it a predictable, human-like set of class selector names that convey its meaning and can be figured out by any developer who encounters it. The three technologies are combined together.

To avoid the above anti-patterns, please keep the following principles in mind:

1. In CSS and JavaScript, give priority to explicit components and behavioral selectors, and Not complex CSS selectors.

2. Name components based on what they are, not where they are

3. Don’t use the same class selector for style and behavior

4. Distinguish between state style and default style

Using class selectors in HTML often requires a lot of class selectors that need to be displayed, but what is achieved is predictability and maintainability, which is worthy of recognition. After all, adding class selectors to HTML is fairly easy and requires little skill on the part of the developer. Excerpted from the words of Nicolas Gallagher:


When you're looking for a way to make HTML and CSS with less time spent writing and modifying CSS, this is what it involves You have to accept that if you want to change the style, you don't want to spend more time changing the class selector on the HTML element. This has some utility for both front-end and back-end developers, and anyone can rearrange pre-built LEGO bricks. Then no one will show off the magic of CSS.

For more articles related to decoupling HTML, CSS and JS, please pay attention to the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn