📜 ⬆️ ⬇️

Implementing a component approach on the web: an overview of web components



Four of the five most requested Edge user-defined platform features on User Voice (Shadow DOM, Template, Custom Elements, HTML Imports) belong to a family of APIs called Web Components. In this article, we want to talk about web components and our view of them, some in-house kitchen, for those who are not familiar with them, as well as speculate on where all this may evolve in the future. This is a rather long story, so sit back, take a coffee (or not a caffeine drink) and start reading.

Content:


')

Component implementation: old design practice that has become new to the web


Modern web applications are as complex as any other software applications, and are often created by several people joining forces to create the final product. In such conditions, in order to increase efficiency, it is natural to look for the right ways to divide work into areas with minimal intersections between people and subsystems. The implementation of the component approach (as a whole) is how this problem is usually solved. Any component system must reduce the overall complexity through the provision of isolation , or natural barriers that hide the complexity of some systems from others. Good insulation also facilitates reuse and implementation of service paradigms.

Initially, the complexity of web applications was mainly regulated by the server by dividing the application into separate pages, which required the user to switch from one page to another in the browser accordingly. With the introduction of AJAX and related technologies, developers were able to abandon the need to make "transitions" between different pages of a web application. For typical scenarios such as reading mail or news, user expectations have changed. For example, after login to the mail, you can “use the mail application” from the same address (URL) and stay on this page for a whole day (the so-called Single-Page Applications , SPA). The logic of client-side web applications in such situations becomes much more complicated, sometimes it even becomes more complicated than on the server side. A possible resolution of this complexity may be a further division into components and isolation of logic within a single page or document.

The goal of web components is to reduce complexity by isolating related groups of HTML, CSS, and JavaScript code to perform common functionality within the context of a single page.

How to break into components?


Since web components must tie together HTML, CSS, and JavaScript, it is necessary to take into account the existing isolation models inherent in each of the technologies, as they affect the scripts and integrity of the web components. These independent insulation models include:



CSS Isolation


In today's platform, there is no perfect and natural way to split CSS into components (although tools like Sass can help a lot). The component model should offer a mechanism to isolate one CSS subset from another, so that the rules will not affect each other. In addition, component styles should apply only to the direct parts of the component and nothing else. Easier said than done!

Inside the style sheets, CSS rules are applied to the document using selectors. Selectors are always considered as potentially applicable to the whole document, therefore their scope is, in essence, global. Global application leads to real conflicts when several people working on a project mix their CSS files together. C intersections and repetitions of selectors can be dealt with in a precise order (for example, cascades, specificity, order of source) for resolving conflicts, however, such actions are quite likely - not at all what the developers wanted. There are many potential ways to solve this problem. A simple solution is to transfer elements and related styles that participate in the formation of a component from the main document to another document (shadow document) so that they will no longer “react” to other people's selectors. This leads to the second problem: now that we have separated them, how can a certain style cross the border (to control the outside of the component)? The obvious possible solution is to use JavaScript explicitly, but it looks like something awful: relying on JavaScript to transfer styles across the border, which seems more like a space in CSS.

To transfer styles across a component border in an efficient manner and at the same time protect the structure of a component (for example, to allow the freedom to change the structure without affecting styles), there are two general approaches that many prefer: “partial” styling using pseudo-elements and custom properties (previously known as “variable” CSS). For a while, the super-powerful cross-border selector '>>>' (defined in CSS Scoping ) was also considered, but today it is not universally accepted as a very good idea, as it easily breaks the isolation of components.

Partial stylization will allow the authors of the component to create their own pseudo-elements for stylization, thus exposing the outside world only a part of its internal structure. This is similar to the model that browsers use to place "parts" of native controls . For the integrity of this scenario, authors will also need some way to limit the set of styles that can apply to a pseudo-element. Additional research of this “partial model” based on pseudo-elements may lead to the appearance of convenient stylistic primitives, although the elaboration of details will still require effort. Further work on the partial model should also rationalize the styling of native controls in browsers (an area that clearly needs attention).

Custom properties will allow authors to describe the values ​​of the styles that they want to reuse in style sheets (defined as their own double-dash property names as a prefix). Custom properties are inherited through the document sub-tree, allowing selectors to redefine the value of the custom property for a particular sub-tree without affecting other sub-trees. Custom properties can also be inherited across component boundaries, providing an elegant component styling mechanism that avoids the disclosure of the internal structural nature of the component. Custom properties were evaluated when developing various component frameworks in Google and, according to reports, allow to cover most of the stylization needs.

Of all the approaches currently being considered for styling, the future “partial” model and the current specification of custom properties seem to have the greatest chance of implementation. We consider custom properties as a new key member of the web component specification.

Other approaches to isolating CSS styles


To complete the picture, the scope and isolation of CSS is not such a black and white area as it might seem above. In fact, several past and current approaches offer options for limiting the scope and isolation with varying applicability to web components.

CSS offers some limited forms of isolation of selectors in specific scenarios. For example, the @ ‍media rule groups a set of selectors together and applies them when conditions match the media context (for example, the size or resolution of the viewport, or the media type — print, etc.); The @ ‍page rule defines some styles that are applicable only in the context of printing; The @ ‍supports rule brings together selectors for use only when support for specific CSS functionality is implemented (a new form of determining the presence of functionality in CSS); the proposed @ ‍document rule groups selectors for use only when the document in which the styles are loaded meets the conditions.

CSS scopes (originally written as part of working on web components) offer a way to limit the applicability of CSS selectors within a single HTML document. The specification introduces the new @ ‍scope rule, which allows the selector to determine the root (s) of the application and further leads to the fact that applying all selectors within the @ ‍scope rule will work only in the subtree of this root (and not on the entire document). The specification allows you to specify the root of the domain declaratively in HTML (for example, the <style scoped> attribute is suggested, as long as it is implemented only in Firefox; this functionality was previously available as an experimental feature in Chrome, but was completely removed later). Some aspects of this functionality (for example,: scope, defined in Selectors L4 ) can also be applied to the relative evaluation of selectors in the new query API in the DOM specification .

It is important to note here that @ ‍scope establishes only one-directional isolation of boundaries: selectors contained within @ ‍scope are limited to this area, while any other selectors (outside @ scope) can quietly penetrate inside @ ‍scope (although they can be - in various ordered cascade styles). This is a somewhat unfortunate design, as it does not provide for limiting the scope and isolation from any styles that are not in the @ ‍scope subset - all CSS should still “fit well” to avoid styling inside another @ ‍scope rule. See also the @ ‍in-shafow-of draft from Taba , which is better aligned with the component insulation protection model.

Another suggestion of visibility limitations is containment in CSS . Holding the field of view is less about isolating styles and selectors and more about isolating “composition”. Inside the “contain” property, the behavior of some CSS features that have natural inheritance (in the sense of applicability from the parent to the child in the document, for example, counters) will be blocked. The main use of this for developers is to indicate that some elements imply strict “containment”, so a composition applicable to this element and its subtree will never affect the composition of other elements of the document. These promises of containment (indicated by the use of the "contain" property) allow browsers to optimize the composition and rendering so that the "new" composition of the held subtree will only require updating this subtree, and not the entire document.

As technology implementations for web components mature among browsers and find more and more public applications, additional styling patterns and problems may appear; we look forward to further investment and subsequent progress in the various proposals in CSS to improve the styling of web components.

Javascript and scopes


All JavaScript code that is included on the page has access to the same global object. Like other programming languages, JavaScript has scopes that provide some level of “privacy” for function code. These lexical scopes are used to isolate variables and functions from the rest of the global environment. The “modular template” in JavaScript, which is popular today (using lexical scopes), evolved from the need of many JavaScript frameworks to “coexist” in a single global environment without “stepping on the heels” of each other (depending on the order of loading).

JavaScript lexical visibility areas are a unidirectional isolation of borders: the code inside the region can have access to both the internal content and the content of any parent area up to the global one, while the code outside the area does not have access to its content. An important principle is that the unidirectional method of isolation gives preference to the code inside the region, that is, protects it. The code inside the lexical area has the ability to protect / hide itself from the rest of the environment (or not).

The contribution that the lexical scopes of JavaScript make to the implementation of a web component meets the requirement to have a way to “close” a component so that its contents can be reasonably private.

Isolation of a global object


For some code, it may not be desirable for it to have global access to the global environment, as described above. For example, an application developer may not trust some JavaScript code, although it provides significant value. A typical case is advertising and advertising frameworks. For security reasons, it is necessary that the untrusted code be executed in a separate clean script environment (with its own global object). To achieve this behavior today (without the inclusion of iframe elements in the game), developers can use workers . However, the disadvantage of this solution is that the workers do not have access to the elements, that is, the UI.

There are a number of considerations that need to be taken into account when designing components that support the isolation of a global object — especially if the isolation implies protected boundaries (more details below). Today, we expect that the isolated components will not be fully accessible until the basic set of web component specifications is fixed (that is, it is “postponed until the next version”). However, if we spend some time exploring how the isolated components may look, it can put the current work in the right direction. Some offers really worth paying attention to.

Isolating a global object is an important unimplemented script for web components. In the meantime, we are working on implementation, for example, we can rely on the most successful and widely used way of introducing componentuality to the web: the iframe element.

Element encapsulation (iframe)


Iframe elements and their close relatives: the object, frameset and imperative API windows.open () elements already provide the ability to work in an isolated subtree of elements. However, if components imply work within a single document, the iframe includes an entire HTML document within it; as if two separate web applications were co-located, just one inside the other. Each has a unique document address, global environment for scripts and CSS scope; each document is completely separate from the other.

Iframe is currently the most successful (and the only widely implemented) form of Web component authorization. Iframe allows you to interact with various web applications. For example, many sites use iframe precisely as a form of a component for all sorts of scenarios from advertising to user login. However, the iframe ran into a number of challenges and some ways to deal with these challenges appeared:


With good security policies and the ability to insert a frame seamlessly, using an iframe as a model for components seems like a very attractive solution. However, several properties that are desirable in the web components model are still missing:


This is not the first time.


We can not fail to note that in the past several technologies have already been proposed and even implemented in an attempt to improve the work of the iframe in HTML and the associated encapsulation capabilities. However, none of them got accustomed to a large extent in the modern web:


Modern web components


After the failure of the first two attempts, it was time to try to launch the game into components again, this time Google took up the business. Using the concepts described in XBL as a starting point, the monolithic component system was broken down into a collection of building blocks for components . These building blocks allowed web developers to experiment with individual useful features before the overall vision for the web components is fully defined. The component of the approach itself and the development of individual useful features allowed us to move closer to success. Almost everyone can find something useful in their web components for their application!

This new wave of web components has led to a set of concrete use cases explaining how existing embedded elements work within today's web platform. In theory, web components will allow developers to prototype new types of HTML elements with the same accuracy and characteristics as native elements (in practice, ensuring accessibility in HTML is especially difficult to achieve today).

It is clear that the full set of all technologies necessary to cover all scenarios for the use of web components will not be implemented immediately in browsers. Browser developers work together to align a basic set of technologies that can be consistently implemented before moving on to additional scenarios.

The first generation of web components includes:


Web components: the next generation


As we noted at the beginning of this article, building full-featured web components is a great adventure. Several ideas for developing and filling gaps in the current generation of opportunities have already begun to circulate among developers (this is not a complete list!):



, -, iframe . , iframe – -, , . «» iframe. , <iframe seamless> .

- – . . @msedgedev .

Source: https://habr.com/ru/post/264791/


All Articles