The main driver of web growth at the turn of the millennium was content
consumption . Sites were created to provide their visitors with any useful information or entertainment content. But in recent years, the importance of web resources has increased dramatically, providing users with content
generation services (text and graphic editors, spreadsheets, instant messengers, etc.). This caused the transformation of sites into one-page applications and migration to the web of complex interfaces that were previously the prerogative of application programs.
In the process of these transformations and migrations, it turned out that the increase in the complexity of creating and maintaining a web interface is far ahead of its complexity. They tried (and still try) to solve the problem by dividing into modules, abstraction, and encapsulation. For this purpose, a large number of JavaScript frameworks (
Backbone
,
Ember
,
Angular
), HTML template engines (
Jade
,
Handlebars
), dependency management systems (
RequireJS
), etc. were created.
The most difficult from this point of view was CSS, where, by language design, any property declared in any connected CSS file or
style
tag may affect the display of any element of the DOM tree.
Task formalization.
Suppose for simplicity that the entire JavaScript code is enclosed in modules that know nothing about each other and encapsulate everything they need for their work. A module knows how to generate its HTML representation (let's call it a
block ) and where to insert it in the DOM tree. In this case, the blocks can be invested in each other. At the markup level, a block consists of a
root element and
child elements .
The task is that the display of elements of any block can be influenced only by
deliberate changes in the HTML representation and the corresponding CSS files and
style
tags.
')
Any unintentional change in the display of block elements will be called a
leakage of styles .
Style leaks can occur as a result of changes in the properties of elements of other blocks (
property leaks ), as well as changes in the DOM tree (
cascading leaks ).
Style leak sources
If we consider any block by itself, then the leakage of styles can be both from the outside and outside. Due to the fact that the leakage to the outside for one unit will be a leakage from the outside for another, when classifying leakages it can be limited to the case of leakage from the outside.
1. Inheritance of properties
If the CSS property of any element does not have an explicit value, the default value is used. If this value is
inherit
, then the property value is set equal to the value of the parent element property.
Thus, the root element of the current block can inherit the styles of its parent, which by definition belongs to another block.
For example,
.outer-block{ color: red; }
<div class="outer-block"> <div class="current-block"> - </div> </div>
look at jsfiddle.net2. Conformity of properties
If the CSS property of any element does not have an explicit value, the default value is used. If this property adjusts to the property of the parent element (for example, as the
width
and
height
properties with the default value
auto
) or mimics (for example, as the
background-color
property with the default value
transparent
), then the end user will get the impression that parent element styles leaked onto child element styles.
For example,
.outer-block{ background: red; }
<div class="outer-block"> <div class="current-block"> - </div> </div>
look at jsfiddle.netIt is worth noting that the very existence of style leaks through conformism can be questioned, since the styles of the parent element are not
formally applied to the child element, but
in practice this behavior can even be considered as desired. But if we proceed from a
formal point of view, we will have to admit that the conformity of styles definitely violates their encapsulation. As a
practical proof, the author suggests the inquisitive reader to use the
duck dough .
3. Cascade chaos
Applying styles to target elements of selectors occurs in three stages.
At the first stage,
all elements that match the target element selector are selected from the
entire DOM tree. For example, for the
.current-block h3
selector, in the first stage, all elements with the
h3
tag will be selected. There is no way to limit the selection space to any part of the DOM tree.
At the second stage, the selected elements are filtered for compliance with the selector by traversing the parent elements of the target element. When using a descendant combinator, the match search can go up to the root element of the DOM tree. When using a sister combinator
~
(general sibling combinator) - until the very first sister element.
For example,
.current-block h3 { background: blue; } .outer-block h3 { background: red; }
<div class="outer-block"> <h3> </h3> <div class="current-block"> <h3> - </h3> </div> </div>
look at jsfiddle.netThe only way to limit the search space is to use the child combinator
>
and the nearest sister combinator
+
(adjacent sibling combinator). To do this, you need to specify the exact path in the DOM tree from the target element to the root element of the block, which leads to an increase in the connectivity of CSS and HTML code.
At the third stage, style properties are assigned to the selected and filtered target elements. Moreover, if several selectors claim one and the same target element, each with its own property option, then the property value is determined based on the specificity of the selectors, and if it is equal, based on the order of the ads.
Thus, under certain conditions (the combinators used, the ratio of specificities, the order of declaration), the styles of the elements of the outer block can influence the styles of the elements of the nested block. This effect could have been avoided if the region of the DOM tree could be specified in which the target elements should be selected and filtered.
4. Positional conditionality
Block elements can change their display depending on the position of the block in the DOM tree when used in selectors of sister combinators (
+
and
~
) or pseudo-classes (
:first-child
, etc.).
For example,
.block { background: red; } .block + .block { background: blue; }
<div class="block"> <h3> , </h3> </div> <div class="block"> <h3> </h3> </div>
look at jsfiddle.netAs in the case of conformity of properties, it is worth noting that many developers find the positional causation to be very useful. The author of the article agrees with them until the conditionality goes beyond the boundaries of the block, since in this case there is a clear violation of the style encapsulation.
Obviously, perfect encapsulation of CSS styles should eliminate any potential for leaks.
The second part of the article ("Encapsulation of CSS styles - Part 2. Solutions") will be devoted to analyzing how current approaches (OOCSS, SMACSS, ACSS, BEM, CSS preprocessors) correspond to the ideal, as well as their classification.
I will be glad to helpful advice and constructive criticism.