📜 ⬆️ ⬇️

CSS is not black magic

All web programmers have to write CSS from time to time. When confronted with it for the first time, you will most likely find that understanding CSS is nonsense. And the truth is - they added borders here, they changed the color there ... JavaScript - this is a really complicated thing. CSS is a toy compared to it.



However, as you improve on web development, a frivolous attitude to CSS will be a thing of the past. Faced with something indescribably strange, you realize that you simply can’t imagine how CSS works, what is being done in its depths. Something similar was with me. The first couple of years after my studies, I was engaged in JavaScript-development of a full cycle, occasionally referring to CSS. I have always believed that my bread is JavaScript, I gave him all my time.

For example, participated in discussions on JavaScript Jabber . In the last year, I decided to focus on the frontend and only then I realized that I could not, for example, debug style sheets in the same way as JS code.
')
About CSS, they often joke, but few took it seriously enough and tried to understand it. Who, when confronted with a problem, thoughtfully engaged in the search for errors, given the way CSS handles browsers? Instead, we grab the code from the first answer to the Stack Overflow, do not disdain all sorts of hacks, or simply ignore the problems.

As a result, too often, developers simply shrug their shoulders when the browser creates incomprehensible things with styles. It’s time to think that CSS is like black magic. However, any programmer knows that a computer is a machine for parsing and executing human-written commands, and CSS, in this regard, is no different from our favorite JS. And if so - CSS is quite possible to learn and use it meaningfully and productively.

Knowledge of the internal mechanisms of the CSS is useful in different situations. For example - with serious debugging and optimizing the performance of web pages. Often, when they talk and write about CSS, they focus on solving common problems. I want to talk about how it all works.

DOM and CSSOM


For a start, it is important to understand that in browsers, among other subsystems, there is a JavaScript-engine and a rendering engine. We, in this case, are interested in the latter. For example, we discuss the details that relate to WebKit (Safari), Blink (Chrome), Gecko (Firefox), and Trident / EdgeHTML (IE / Edge).

The browser, in the course of displaying a web page on the screen, performs a specific sequence of actions leading to the construction of an object model document (DOM, Document Object Model) and a style sheet object model (CSSOM, CSS Object Model). This sequence of actions, simply, can be represented as follows:


After creating similar tree structures for CSS and HTML, the rendering engine generates, based on them, what is called a rendering tree. This is part of the document layout process.

The rendering tree is a model of the visual presentation of the document, which allows you to display the graphic elements of the document in the correct order. The rendering tree is constructed using the following algorithm:


CSSOM can have a major impact on the rendering tree, but not on the DOM tree.

Rendering


After the rendering tree and page layout have been created, the browser can proceed to displaying elements on the screen. This is what this process looks like.


Page rendering time depends on the characteristics of the rendering tree. In addition, the greater the width and height of the element - the longer the rendering time will be.

Adding various effects can increase the page rendering time. The output of graphic representations of elements is made in accordance with the context of the overlay, in the order in which they are located relative to each other. First, those elements that are located below are displayed, then those that are located above. Later, speaking about the z-index property, we will focus on this in more detail. For those who are well aware of visual information, here is a great demonstration of the process of forming a graphic representation of the page.

Speaking about the output of a graphical representation of pages in browsers, hardware acceleration of graphics is often mentioned. In such cases, they usually mean the acceleration of mixing layers. We are talking about the use of video card resources to prepare for the output of web pages.

Mixing layers using hardware acceleration can significantly increase the rendering speed compared to the traditional approach, which uses only the processor. In connection with all this, it is impossible not to recall the will-change CSS property, the skillful use of which allows you to speed up the output of pages. For example, when using CSS transformations, the will-change property allows the browser to be prompted that the DOM element will be transformed in the near future. It looks like will-change: transform . This allows the GPU to transfer some operations for drawing and flattening layers, which can significantly improve the performance of pages containing many animated elements. You can improve performance with will-change by using the will-change constructs will-change: scroll-position , will-change: contents , will-change: opacity , will-change: left, top .

It is important to understand that some properties can cause a change in the page layout, while changing others only redraws it. Of course, from the point of view of performance, it is better if you can do only by redrawing the page with a constant layout.

For example, changing the color of an element will leave the layout unchanged, resulting in only a redrawing of the element. But a change in the position of an element will lead to a change in the layout, and to a redrawing of the element itself, its child elements, and, possibly, adjacent elements. Adding a DOM node will also result in layout recalculation and page redrawing. Serious changes, such as increasing the font size of an HTML element, change the layout and redraw the entire rendering tree.

If you are like me, then you are probably more familiar with DOM than with CSSOM, so let's pay some attention to CSSOM. It is important to note that by default, CSS is considered as a rendering blocking resource. This means that the browser will not render until CSSOM is fully available.

In addition, we must understand that there is no full compliance between DOM and CSSOM. The differences in these structures are due to the presence in the DOM of invisible elements, scripts, meta tags, tags with proprietary information that is not displayed on the screen, and so on. All this is not taken into account when building CSSOM, since it does not affect the graphical representation of the page.

Another difference between DOM and CSSOM is that context-independent grammar is used in CSS analysis. In other words, in the rendering engine there is no code that would bring CSS to some acceptable form, as is done when parsing HTML to create a DOM.

When analyzing characters that form HTML elements, the browser is forced to take into account the surrounding characters, it needs more than just the language specification, since some elements in the markup may be missing, however, the engine, by all means, needs to be displayed page. Hence the need for more complex data processing algorithms.

Finishing the talk about rendering, we briefly consider the path of the web page from the set of bytes stored on the server to the data structures on the basis of which its graphical representation is formed.

The browser performs an HTTP request by requesting a page from the server. The web server sends the response. The browser converts the data received from the server into tokens, which are then converted into DOM and CSSOM tree nodes. After these trees are ready, the rendering tree is built, on the basis of which the page layout is formed, layer-by-layer rendering of elements and layer blending are performed. The result is a web page that we see on the screen.

Selector Specificity


Now that we’ve gotten a little understanding of how the browser works, take a look at some of the most common moments that developers are confused about. To begin, let's talk about the specificity of selectors.

Very simply, the specificity of the selectors means applying cascading CSS rules in the correct order. However, there are many ways to select a tag using a CSS selector, and the browser needs a way to decide which style to assign to a particular tag. Browsers make similar decisions, calculating the specificity value for each selector.

Calculating indicators of the specificity of selectors confuses many JavaScript developers, so let's look at this in more detail. We will use the following example. There is a div tag with the class container . This tag has another div , the id which is main . Inside main there is a tag p , which contains the tag a .

 <div class="container"> <div id="main">   <p>     <a href="">Hello!</a>   </p> </div> </div> 

Now, without looking back, try to analyze the CSS below and say what color the link text will be in the a tag.

 #main a { color: green; } pa { color: yellow; } .container #main a { color: pink; } div #main pa { color: orange; } a { color: red; } 

Maybe red? Or green? Not. The link will be pink with a specificity value of 1.1.1. Here are the remaining results:


To find these numbers you need to perform the following calculations:


For example, take a look at this selector:

 #header .navbar li a:visited 

The value of specificity for it will be 1,2,2. There is one ID, one class, one pseudo-class, and two element type selectors ( li and a ). This value can also be read as if there are no commas in it, instead of 1,2,2–122. Commas are only here to emphasize that we are confronted with not three-digit decimal number, but three numbers. This is especially important for theoretically possible results like 0.1,13. If you rewrite it in the form of 0113, it will be unclear how to return it to its original state.

Positioning elements


Now I would like to talk about positioning. Positioning elements and creating a page layout, as we have already seen, go hand in hand.

Layout design is a recursive process that can be invoked for the entire rendering tree as a result of a global change in styles, or only for a part of the tree, when the changes touch only certain elements that need to be redrawn. Here is one interesting observation that can be made by referring to the rendering tree and imagining that it uses absolute positioning. With this approach, the objects from which the page layout is built are not placed in the rendering tree in the same places as in the DOM tree.

Often people ask me about the advantages and disadvantages of using flexbox and float. Of course, flexbox is, in terms of usability, very well, being applied to the same element, the flexbox layout is rendered in about 3.5 ms, while rendering the float layout can take about 14 ms. Thus, in order to take into account small but important details, it makes sense for JS developers to maintain their knowledge in the field of CSS in the same good condition as the knowledge in the field of JavaScript.

Z-index property


And finally, I would like to talk about the z-index property. At first glance it seems that there’s nothing to talk about here. Each element in an HTML document may either be in front of or behind the others. In addition, it only works for positioned elements. If you set the z-index property for an element whose positioning is not explicitly specified, it will not change anything.

The key to finding and fixing z-index issues is to understand the concept of overlay contexts. Troubleshooting always begins with the root element of the overlay context. The overlay context is the concept of placing HTML elements in three-dimensional space, in particular along the Z axis, relative to the user in front of the monitor. In other words, it is a group of elements with a common parent, which together move along the Z axis, either closer to or further from the user.

Each overlay context has one HTML element as the root element. When the positioning and z-index properties are not used, the rules for interaction between elements are simple. The order of the overlay elements corresponds to the order of their appearance in HTML.

However, you can create new overlay contexts using properties that are different from the z-index , and here everything becomes more complicated. Among them is the opacity property, when this value is less than one, filter , when the value of this property is different from none , and mix-blend-mode , whose value is not normal . These properties actually create new overlay contexts. Just in case, I want to remind you that blend mode allows you to specify how the pixels on a certain layer interact with the visible pixels on the layers below this layer.

The transform property also triggers the creation of a new overlay context in cases where it is different from none . For example, scale(1) and translate3d(0,0,0) . Again, as a reminder, the scale property is used to resize an element, and translate3d allows the GPU to be used for CSS transitions, improving the quality of the animation.

Results


If for you this material has become the first step to a serious mastering of CSS, we hope you will very soon learn how to solve problems with styles yourself. And here you can find a list of additional materials that will help you deepen and expand your knowledge.

Dear readers! If you know CSS well, please tell us about how you dealt with it. Share your experience. We are sure it will be useful to many.

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


All Articles