<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andrew S.</title>
    <description>The latest articles on DEV Community by Andrew S. (@betelgeuseas).</description>
    <link>https://dev.to/betelgeuseas</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1094529%2Fc5d4ab70-4bf0-4d3f-afed-2eff8c3b5312.png</url>
      <title>DEV Community: Andrew S.</title>
      <link>https://dev.to/betelgeuseas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/betelgeuseas"/>
    <language>en</language>
    <item>
      <title>Optimizing Web Application Performance</title>
      <dc:creator>Andrew S.</dc:creator>
      <pubDate>Mon, 14 Jul 2025 20:06:52 +0000</pubDate>
      <link>https://dev.to/betelgeuseas/optimizing-web-application-performance-92d</link>
      <guid>https://dev.to/betelgeuseas/optimizing-web-application-performance-92d</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;In today's fast-paced digital world, web application performance plays a crucial role in delivering a seamless user experience. Slow loading times, lagging interactions, and unresponsive interfaces can drive users away and negatively impact your business. To make your web application work at its best, it's important to optimise its performance. In this article, we'll go over various tips and techniques to help you optimise your web application for better performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Minimize HTTP Requests
&lt;/h3&gt;

&lt;p&gt;Every time a web page loads, it makes several HTTP requests to retrieve resources such as HTML, CSS, JavaScript, images, and other resources. These requests can cause delays in page loading. You can minimise the number of HTTP requests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Combine multiple CSS files into a single file, just as you would with JavaScript files.&lt;/li&gt;
&lt;li&gt;Use &lt;em&gt;CSS sprites&lt;/em&gt; to combine multiple small images into one.&lt;/li&gt;
&lt;li&gt;Use &lt;em&gt;font icons&lt;/em&gt; instead of uploading separate image files for icons.&lt;/li&gt;
&lt;li&gt;Use &lt;em&gt;lazy loading&lt;/em&gt; methods to load resources only when they are needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, consider using browser caching by setting appropriate cache headers to reduce the number of HTTP requests made by returning visitors.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Optimize CSS and JavaScript
&lt;/h3&gt;

&lt;p&gt;CSS and JavaScript can have a significant impact on the performance of web applications. By optimising and minifying these files, you can reduce load times and improve performance. Here are some tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minimise your CSS and JavaScript files by removing unnecessary comments, whitespace, and line breaks.&lt;/li&gt;
&lt;li&gt;Combine multiple CSS and JavaScript files into one file each.&lt;/li&gt;
&lt;li&gt;Place the CSS files in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section and the JavaScript files just before the closing of the &lt;code&gt;&amp;lt;/body&amp;gt;&lt;/code&gt; tag.&lt;/li&gt;
&lt;li&gt;Consider using CSS preprocessors such as &lt;strong&gt;Sass&lt;/strong&gt; or &lt;strong&gt;LESS&lt;/strong&gt; to make your CSS more efficient and maintainable.&lt;/li&gt;
&lt;li&gt;Consider using JavaScript bundlers such as &lt;strong&gt;Webpack&lt;/strong&gt; or &lt;strong&gt;Rollup&lt;/strong&gt; to eliminate unused code and reduce file size.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Compress and Optimize Images
&lt;/h3&gt;

&lt;p&gt;Images can take up a significant portion of the total page size. Large image files can slow down loading times. Optimise images for the web:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compress images with tools like &lt;strong&gt;PNGGauntlet&lt;/strong&gt;, &lt;strong&gt;TinyPNG&lt;/strong&gt;, or &lt;strong&gt;JPEGmini&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Resize images to the appropriate dimensions for your web page.&lt;/li&gt;
&lt;li&gt;Use modern image formats such as &lt;strong&gt;WebP&lt;/strong&gt;, which provide better compression and quality than &lt;strong&gt;JPEG&lt;/strong&gt; and &lt;strong&gt;PNG&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Lazy loading&lt;/em&gt; of images that are not initially visible.&lt;/li&gt;
&lt;li&gt;Use &lt;em&gt;responsive images&lt;/em&gt; to display different sizes depending on the resolution of the device.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Reduce Server Response Time
&lt;/h3&gt;

&lt;p&gt;The time it takes for the server to respond to requests can have a significant impact on the performance of web applications. Reduce server response time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Optimise database queries by adding the right indexes, reducing unnecessary joins, and caching frequently accessed data.&lt;/li&gt;
&lt;li&gt;Use a content delivery network (&lt;strong&gt;CDN&lt;/strong&gt;) to cache and serve static content from servers closer to the user's location.&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;HTTP/2&lt;/strong&gt;, which allows the server to handle multiple requests simultaneously and reduces the need for multiple connections.&lt;/li&gt;
&lt;li&gt;Implement server-side &lt;em&gt;caching mechanisms&lt;/em&gt;, such as reverse proxies or in-memory caches, to store frequently accessed data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Optimize Database Queries
&lt;/h3&gt;

&lt;p&gt;Inefficient database queries can slow down your web application. Optimise database queries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Analyse slow queries and optimise them by adding appropriate indexes, rewriting queries, or denormalising data where necessary.&lt;/li&gt;
&lt;li&gt;Minimise the use of &lt;code&gt;OR&lt;/code&gt; conditions and use appropriate indexes for columns used in &lt;code&gt;WHERE&lt;/code&gt;, &lt;code&gt;JOIN&lt;/code&gt;, and &lt;code&gt;ORDER BY&lt;/code&gt; clauses.&lt;/li&gt;
&lt;li&gt;Cache frequently accessed data in memory using tools such as &lt;strong&gt;Redis&lt;/strong&gt; or &lt;strong&gt;Memcached&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Eliminate Render-Blocking Resources
&lt;/h3&gt;

&lt;p&gt;Render-blocking resources, such as external CSS and JavaScript, can delay the rendering of a web page. Remove the render-blocking resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load critical CSS inline or use methods such as server-side rendering.&lt;/li&gt;
&lt;li&gt;Use script tags with async or defer attributes for non-critical JavaScript files so that rendering continues without waiting for the script to load.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  7. Optimize Web Fonts
&lt;/h3&gt;

&lt;p&gt;If web fonts are not optimised properly, they can slow down loading times. Optimise web fonts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use subsets of fonts to include only the characters you need and reduce file size.&lt;/li&gt;
&lt;li&gt;If possible, use system or stock fonts to avoid downloading custom web fonts.&lt;/li&gt;
&lt;li&gt;Preload web fonts to reduce rendering latency.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  8. Enable GZIP Compression
&lt;/h3&gt;

&lt;p&gt;Enabling &lt;strong&gt;GZIP&lt;/strong&gt; compression can significantly reduce the size of the response and speed up page load times. Most modern web servers support &lt;strong&gt;GZIP&lt;/strong&gt; compression. Enable it by adding the appropriate configuration on your server.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Implement Caching Mechanisms
&lt;/h3&gt;

&lt;p&gt;Caching plays a crucial role in reducing the load on your web application and improving performance. Implement caching mechanisms on both the client and server sides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement browser caching by setting appropriate cache headers for static files.&lt;/li&gt;
&lt;li&gt;Use HTTP cache headers such as &lt;code&gt;Cache-Control&lt;/code&gt; and &lt;code&gt;ETag&lt;/code&gt; to control server-side caching.&lt;/li&gt;
&lt;li&gt;Use content delivery networks (&lt;strong&gt;CDNs&lt;/strong&gt;) that automatically cache static files to reduce server load.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  10. Optimize Your Code
&lt;/h3&gt;

&lt;p&gt;Efficient code execution is key to performance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use async or defer attributes to load JavaScript files asynchronously, preventing them from blocking the rendering of the page.&lt;/li&gt;
&lt;li&gt;Combine multiple CSS and JavaScript files into one to reduce the number of HTTP requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  11. Use Lazy Loading
&lt;/h3&gt;

&lt;p&gt;Lazy loading delays the loading of off-screen images and other elements until they are needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement &lt;em&gt;lazy loading&lt;/em&gt; for images and videos to improve initial load times.&lt;/li&gt;
&lt;li&gt;Use &lt;em&gt;lazy loading&lt;/em&gt; for additional content that appears as users scroll down the page.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  12. Database Optimization
&lt;/h3&gt;

&lt;p&gt;For dynamic websites, optimizing the database can lead to significant performance gains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure that your database tables are properly indexed to speed up queries.&lt;/li&gt;
&lt;li&gt;Regularly clean up unnecessary data and optimize database tables.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  13. Monitor and Optimize Performance Regularly
&lt;/h3&gt;

&lt;p&gt;Performance optimisation is an ongoing process. Regularly monitor your web application's performance and collect metrics using tools like &lt;strong&gt;Google Analytics&lt;/strong&gt;, &lt;strong&gt;New Relic&lt;/strong&gt;, or &lt;strong&gt;Pingdom&lt;/strong&gt;. Use these metrics to identify bottlenecks and areas for improvement. Continuously optimise your web app to ensure a fast and seamless user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Optimising web application performance is crucial to delivering a seamless user experience and maximising conversions. By following the tips and techniques discussed in this article, you can significantly improve the performance of your web application. Don't forget to regularly monitor and optimise performance to stay one step ahead. Implement these strategies and your users will thank you with increased engagement and loyalty.&lt;/p&gt;

&lt;h2&gt;
  
  
  Support ❤️
&lt;/h2&gt;

&lt;p&gt;It took a lot of time and effort to create this material. If you found this article useful or interesting, please support my work with a small donation. It will help me to continue sharing my knowledge and ideas.&lt;/p&gt;

&lt;p&gt;Make a contribution or Subscription to the author's content: &lt;a href="http://buymeacoffee.com/betelgeuseo" rel="noopener noreferrer"&gt;Buy me a Coffee&lt;/a&gt;, &lt;a href="https://patreon.com/betelgeuseo" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;, &lt;a href="https://www.paypal.com/donate/?hosted_button_id=327N24D6QDLVC" rel="noopener noreferrer"&gt;PayPal&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>performance</category>
    </item>
    <item>
      <title>Ways to Generate Pages: CSR, SSR, SSG, ISR</title>
      <dc:creator>Andrew S.</dc:creator>
      <pubDate>Sun, 13 Jul 2025 14:53:27 +0000</pubDate>
      <link>https://dev.to/betelgeuseas/ways-to-generate-pages-csr-ssr-ssg-isr-3n3e</link>
      <guid>https://dev.to/betelgeuseas/ways-to-generate-pages-csr-ssr-ssg-isr-3n3e</guid>
      <description>&lt;p&gt;Along with &lt;strong&gt;SPA&lt;/strong&gt;, several interesting concepts have emerged that may seem complicated and, at the very least, incomprehensible. What is the difference between client-side, server-side, static and incremental website generation? What is it anyway and how does it relate to &lt;strong&gt;Search Engine Optimisation (SEO)&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;I suggest that you familiarise yourself with the following concepts and consider their advantages and disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Client-Side Rendering (&lt;strong&gt;CSR&lt;/strong&gt;);&lt;/li&gt;
&lt;li&gt;Server-Side Rendering (&lt;strong&gt;SSR&lt;/strong&gt;);&lt;/li&gt;
&lt;li&gt;Static Site Generation (&lt;strong&gt;SSG&lt;/strong&gt;);&lt;/li&gt;
&lt;li&gt;Incremental Static Regeneration (&lt;strong&gt;ISR&lt;/strong&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This material will be useful for Front-end developers of any level, because we will consider the concept, pros and cons of each approach, as well as the tools that can be used to implement them. I will use the &lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;React&lt;/a&gt; stack as a basis.&lt;/p&gt;

&lt;h2&gt;
  
  
  History
&lt;/h2&gt;

&lt;p&gt;Before there was React or Angular, all websites were "&lt;em&gt;multi-page&lt;/em&gt;" applications. We would open a website address in a browser, send a request to the server, where some conditional PHP would generate a whole page for us (all HTML, CSS, and a bit of JS) and return it to the client. When we clicked on a link to another page, sent the same request again, the server generated a new page and returned it. The browser deleted the old one and rendered the new one, with a kind of ‘blip’ when switching between pages. This approach is called &lt;strong&gt;Multi Page Application (MPA)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;From an &lt;strong&gt;SEO&lt;/strong&gt; perspective, this is the perfect approach. We have a full page with all the necessary information, and any search bot can read it immediately, our sites are at the top of search results, and our clients (the owners of these sites) are happy.&lt;/p&gt;

&lt;p&gt;From the point of view of website users, it's not so perfect. Every time we open a new page, we wait for all the resources to load again and for the page to render. Of course, most of the resources are already cached, but we still wait for the page to be fully rendered. Well, no one has cancelled the transition blinks.&lt;/p&gt;

&lt;p&gt;This approach was revolutionised by the emergence of frameworks that allowed to implement the so-called &lt;strong&gt;Single Page Application (SPA)&lt;/strong&gt;. The idea is that we load CSS, JS, and an almost empty HTML page once, and then JS builds everything in the client browser. When switching between pages, JS rebuilds only the part that has changed, and, if necessary, makes an &lt;strong&gt;AJAX&lt;/strong&gt; request to the server to get the necessary data. We got rid of the blinks!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnem2d48uc17pgu5w0w7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnem2d48uc17pgu5w0w7.png" alt="MPA vs. SPA" width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Customers are satisfied - we download the resources once and all pages are displayed smoothly in the browser. The user experience is similar to that of native mobile applications.&lt;/p&gt;

&lt;p&gt;If all the resources have already been downloaded, why not store them on your phone and use them even when you don't have internet access? &lt;strong&gt;&lt;a href="https://web.dev/explore/progressive-web-apps" rel="noopener noreferrer"&gt;Progressive Web Apps&lt;/a&gt;&lt;/strong&gt; will help you with this. Not all applications need to constantly download up-to-date information from the server, there are various games or static applications. And even if you do need to download information, such as articles, you can download them in advance and save them along with your files.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;&lt;a href="https://developer.chrome.com/docs/workbox/service-worker-overview/" rel="noopener noreferrer"&gt;Service Worker&lt;/a&gt;&lt;/strong&gt; will help you implement this mechanism. And, as a bonus, by manually saving the application to your phone (and you can do it), it works without displaying browser navigation, just like a regular application installed from the App Store or Google Play.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SEO&lt;/strong&gt; suffers. Search bots load the page, but there's nothing there, it's empty. They didn't know how to execute JS, so they couldn't get the same page as users. In addition, the URL did not change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;// An example of a page seen by a search bot.

&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"X-UA-Compatible"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"ie=edge"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;SPA Aplication&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/assets/favicon.ico"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"styles.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"main.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Over time, the URL began to change when navigating between pages. At first, it was hash navigation (using the &lt;code&gt;#&lt;/code&gt; symbol, JS allowed you to change the hash in the address), then a full-fledged address change using the &lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/History_API" rel="noopener noreferrer"&gt;History API&lt;/a&gt;&lt;/strong&gt;. Some search bots started to execute JS, but it was not a solution. Rendering a full page is a long and expensive process. Each bot has a so-called ‘budget’ - a limit on time, resources, and the number of pages it can crawl. Just imagine how many pages Google indexes every day - a huge amount of work.&lt;/p&gt;

&lt;p&gt;The solution to the &lt;strong&gt;SEO&lt;/strong&gt; problem is server-side rendering. It's time to take a closer look at it, but first, let's close the issue with client-side page generation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Client-Side Rendering (CSR)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fesr8ajtxtvocsr9mpw7x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fesr8ajtxtvocsr9mpw7x.png" alt="CSR" width="800" height="614"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The approach is quite simple. The created application consists of several files: a stylesheet, scripts, and a conditionally empty HTML page where the styles and scripts are connected. In the &lt;code&gt;index.html&lt;/code&gt; file, there is only one &lt;code&gt;div&lt;/code&gt; with &lt;code&gt;id="root"&lt;/code&gt;, where the entire page is built. When you navigate between pages, the URL in the browser changes and data is pulled from the server, if necessary. The implementation is simple, the server load is minimal, because you do not need to render the page for each request, but only return static files. If you need data, you can create a separate &lt;em&gt;RESTful&lt;/em&gt; server that will return data in &lt;strong&gt;JSON&lt;/strong&gt; format.&lt;/p&gt;

&lt;p&gt;As a bonus, it is easy to scale, and the data can be used by different clients (web pages, mobile applications, other servers). In addition, you can save money on hosting. You don't need a lot of resources to return a few files.&lt;/p&gt;

&lt;p&gt;Of course, this approach suffers from &lt;strong&gt;SEO&lt;/strong&gt;. Additionally, you may face problems when trying to share such pages on social media, because they also need to download the page, render it, and find the necessary data. And let's not forget about users: if they have old, weak phones, the page will take forever to render.&lt;/p&gt;

&lt;p&gt;✅ Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ease of implementation;&lt;/li&gt;
&lt;li&gt;Less server load;&lt;/li&gt;
&lt;li&gt;Relevance of information;&lt;/li&gt;
&lt;li&gt;Do without a server;&lt;/li&gt;
&lt;li&gt;Ease of scaling;&lt;/li&gt;
&lt;li&gt;Cheaper hosting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❌ Disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SEO suffers;&lt;/li&gt;
&lt;li&gt;social media crawlers and share issues;&lt;/li&gt;
&lt;li&gt;more load on customers' devices;&lt;/li&gt;
&lt;li&gt;JS file size at first download.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚙️ Instruments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://create-react-app.dev/" rel="noopener noreferrer"&gt;Create React App&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;React&lt;/a&gt; and manual configuration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Server-Side Rendering (SSR)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdmkuwhk7isarlqw6roq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdmkuwhk7isarlqw6roq.png" alt="SSR" width="800" height="787"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main feature of this approach is that the entire page is rendered on the server at the first request, and then, for example, React is initialised in the browser, and then the application works like a regular &lt;strong&gt;SPA&lt;/strong&gt;, making &lt;strong&gt;AJAX&lt;/strong&gt; requests to the server if necessary. The data loaded is always up-to-date, because every time the page reloads, a request to the server is made. From the &lt;strong&gt;SEO&lt;/strong&gt; point of view, everything is also perfect: a full-fledged page is returned. Users are also satisfied - they work with a regular SPA and do not see any difference.&lt;/p&gt;

&lt;p&gt;Although there is a need to maintain a powerful server that will handle all requests, there is an advantage. You can set up caching for the most popular requests, which will speed up page loading and display.&lt;/p&gt;

&lt;p&gt;There are some difficulties with this approach. If you implement server-side rendering yourself using NodeJS, you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run, for example, React on the server to return the generated component. React comes with a function called &lt;code&gt;ReactDOMServer.renderToString()&lt;/code&gt; that does this;&lt;/li&gt;
&lt;li&gt;Pass the correct URL of the page, the server is not a browser. Let's use a static router - &lt;code&gt;&amp;lt;StaticRouter location={req.originalUrl }&amp;gt;&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Get the data in advance and render the application using it;&lt;/li&gt;
&lt;li&gt;After the page loads, run React so that we can navigate between pages, just like with client-side rendering. To do this, we use the &lt;code&gt;ReactDOM.hydrate()&lt;/code&gt; function (&lt;code&gt;ReactDOM.hydrateRoot()&lt;/code&gt; for the newer version of React). Unlike &lt;code&gt;ReactDOM.render()&lt;/code&gt;, it doesn't hydrate the entire contents of the container, but only tries to add React event listeners to the pre-generated HTML.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Perfect implementation of &lt;strong&gt;SEO&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;Relevance of information;&lt;/li&gt;
&lt;li&gt;Speed of loading and displaying content (&lt;a href="https://developer.chrome.com/docs/lighthouse/performance/interactive" rel="noopener noreferrer"&gt;Time to Interactive&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;Server cache settings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❌ Disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complexity of implementation;&lt;/li&gt;
&lt;li&gt;Server load;&lt;/li&gt;
&lt;li&gt;Increase in the size of files downloaded from the server;&lt;/li&gt;
&lt;li&gt;Longer response from the server (&lt;a href="https://developer.chrome.com/docs/lighthouse/performance/server-response-time" rel="noopener noreferrer"&gt;TTFB&lt;/a&gt; - Time to first byte).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚙️ Instruments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;NodeJS&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;NextJS&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://remix.run/" rel="noopener noreferrer"&gt;Remix&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Static Site Generation (SSG)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzyxmo7u7q1kt39igojs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzyxmo7u7q1kt39igojs.png" alt="SSG" width="800" height="807"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do we need to generate a whole page on the server every time if the data is not updated that often? For various landing pages, business card sites, blogs, simple online stores where information is updated very rarely, server-side rendering support can be costly and redundant.&lt;/p&gt;

&lt;p&gt;This is where SSG comes in. Why do you need to generate for each request if you can generate all the pages once when building the application? We simply put all HTML (CSS and JS) files in a folder, place them on a simple file server or even in a &lt;strong&gt;&lt;a href="https://uk.wikipedia.org/wiki/Content_delivery_network" rel="noopener noreferrer"&gt;CDN&lt;/a&gt;&lt;/strong&gt; and return them with each request. There is no server to process requests or generate pages. We get the maximum download speed and security. A safe server is a server that doesn't exist.&lt;/p&gt;

&lt;p&gt;From the &lt;strong&gt;SEO&lt;/strong&gt; point of view, this is an ideal option. For the user, the page is displayed even faster than with &lt;strong&gt;SSR&lt;/strong&gt;, we don't wait for data on the server, so &lt;strong&gt;TTFB&lt;/strong&gt; is smaller. For users, everything remains the same, because after the page loads, React is initialised again and the application works like a regular &lt;strong&gt;SPA&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;From the SEO point of view, this is an ideal option. For the user, the page is displayed even faster than with SSR, we don't wait for data on the server, so TTFB is smaller. For users, everything remains the same, because after the page loads, React is initialised again and the application works like a regular SPA.&lt;/p&gt;

&lt;p&gt;You may also wonder: what about user interaction with the site? What if you need to send a form or collect information? No one forbids you to launch a separate RESTful server that will be responsible for processing various requests from customers. You can also pay attention to Serverless or "&lt;em&gt;cloud functions&lt;/em&gt;", I recommend taking a look at &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt; or &lt;a href="https://cloud.google.com/functions" rel="noopener noreferrer"&gt;GCP Cloud&lt;/a&gt; functions.&lt;/p&gt;

&lt;p&gt;✅ Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Perfect &lt;strong&gt;SEO&lt;/strong&gt; implementation;&lt;/li&gt;
&lt;li&gt;Loading and display speed;&lt;/li&gt;
&lt;li&gt;Reliability and security (no server);&lt;/li&gt;
&lt;li&gt;Cheap hosting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❌ Disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When updating content, you need to reassemble the project;&lt;/li&gt;
&lt;li&gt;Time to generate a large number of pages, for example, for 100,000 products.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚙️ Instruments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.gatsbyjs.com/" rel="noopener noreferrer"&gt;GatsbyJS&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;NextJS&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Incremental Static Regeneration (ISR)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqp41ia7s42xirwv9lnr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqp41ia7s42xirwv9lnr.png" alt="ISR" width="800" height="1195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This method combines the advantages of the previous two. You don't always need to generate a page for every request, and pre-generated pages are not a solution if the content is updated from time to time.&lt;/p&gt;

&lt;p&gt;The solution is to split pages. Those that are updated more frequently will be rendered with &lt;strong&gt;SSR&lt;/strong&gt;, while those that are rarely updated will be generated with &lt;strong&gt;SSG&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;✅ Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Perfect &lt;strong&gt;SEO&lt;/strong&gt; implementation;&lt;/li&gt;
&lt;li&gt;Loading and display speed;&lt;/li&gt;
&lt;li&gt;Can be used for some pages;&lt;/li&gt;
&lt;li&gt;Relative relevance of information.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❌ Disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The complexity of implementation;&lt;/li&gt;
&lt;li&gt;Requires a server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚙️ Instruments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;NextJS&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Support ❤️
&lt;/h2&gt;

&lt;p&gt;It took a lot of time and effort to create this material. If you found this article useful or interesting, please support my work with a small donation. It will help me to continue sharing my knowledge and ideas.&lt;/p&gt;

&lt;p&gt;Make a contribution or Subscription to the author's content: &lt;a href="http://buymeacoffee.com/betelgeuseo" rel="noopener noreferrer"&gt;Buy me a Coffee&lt;/a&gt;, &lt;a href="https://patreon.com/betelgeuseo" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;, &lt;a href="https://www.paypal.com/donate/?hosted_button_id=327N24D6QDLVC" rel="noopener noreferrer"&gt;PayPal&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>The Rendering Engine</title>
      <dc:creator>Andrew S.</dc:creator>
      <pubDate>Thu, 10 Jul 2025 17:02:21 +0000</pubDate>
      <link>https://dev.to/betelgeuseas/the-rendering-engine-7d</link>
      <guid>https://dev.to/betelgeuseas/the-rendering-engine-7d</guid>
      <description>&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;When you're building web apps, however, you don't just write isolated JavaScript code that runs on its own. The JavaScript you write is interacting with the environment. Understanding this environment, how it works and what it is composed of will allow you to build better apps and be well-prepared for potential issues that might arise once your apps are released into the wild.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F964u0l8nu5v5ggmdbacs.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F964u0l8nu5v5ggmdbacs.webp" alt="browser architecture" width="695" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, let's see what the browser main components are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User interface:&lt;/strong&gt; this includes the address bar, the back and forward buttons, bookmarking menu, etc. In essence, this is every part of the browser display except for the window where you see the web page itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser engine:&lt;/strong&gt; it handles the interactions between the user interface and the rendering engine&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rendering engine:&lt;/strong&gt; it's responsible for displaying the web page. The rendering engine parses the HTML and the CSS and displays the parsed content on the screen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Networking:&lt;/strong&gt; these are network calls such as XHR requests, made by using different implementations for the different platforms, which are behind a platform-independent interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI backend:&lt;/strong&gt; it's used for drawing the core widgets such as checkboxes and windows. This backend exposes a generic interface that is not platform-specific. It uses operating system UI methods underneath.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript engine:&lt;/strong&gt; basically, this is where the JavaScript gets executed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data persistence:&lt;/strong&gt; your app might need to store all data locally. The supported types of storage mechanisms include &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage" rel="noopener noreferrer"&gt;localStorage&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API" rel="noopener noreferrer"&gt;indexDB&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Web_SQL_Database" rel="noopener noreferrer"&gt;WebSQL&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/FileSystem" rel="noopener noreferrer"&gt;FileSystem&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post, we're going to focus on the rendering engine, since it's handling the parsing and the visualization of the HTML and the CSS, which is something that most JavaScript apps are constantly interacting with.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overview of the rendering engine
&lt;/h3&gt;

&lt;p&gt;The main responsibility of the rendering engine is to display the requested page on the browser screen.&lt;/p&gt;

&lt;p&gt;Rendering engines can display HTML and XML documents and images. If you're using additional plugins, the engines can also display different types of documents such as PDF.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rendering engines
&lt;/h3&gt;

&lt;p&gt;Similar to the JavaScript engines, different browsers use different rendering engines as well. These are some of the popular ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gecko — Firefox&lt;/li&gt;
&lt;li&gt;WebKit — Safari&lt;/li&gt;
&lt;li&gt;Blink — Chrome, Opera (from version 15 onwards)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The process of rendering
&lt;/h3&gt;

&lt;p&gt;The rendering engine receives the contents of the requested document from the networking layer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd9inmtf18wjndywfqr32.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd9inmtf18wjndywfqr32.png" alt="rendering-process" width="800" height="110"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Constructing the DOM tree
&lt;/h3&gt;

&lt;p&gt;The first step of the rendering engine is parsing the HTML document and converting the parsed elements to actual &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction" rel="noopener noreferrer"&gt;DOM&lt;/a&gt; nodes in a &lt;strong&gt;DOM tree&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Imagine you have the following textual input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/css"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"theme.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt; Hello, &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt; friend! &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt; 
      &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"smiley.gif"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Smiley face"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"42"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"42"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The DOM tree for this HTML will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fupd6fmjmxbdet70eh7bu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fupd6fmjmxbdet70eh7bu.png" alt="constructing-dom" width="700" height="636"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basically, each element is represented as the parent node to all of the elements, which are directly contained inside of it. And this is applied recursively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Constructing the CSSOM tree
&lt;/h3&gt;

&lt;p&gt;CSSOM refers to the CSS Object Model. While the browser was constructing the DOM of the page, it encountered a &lt;code&gt;link&lt;/code&gt; tag in the &lt;code&gt;head&lt;/code&gt; section which was referencing the external &lt;code&gt;theme.css&lt;/code&gt; CSS style sheet. Anticipating that it might need that resource to render the page, it immediately dispatched a request for it. Let's imagine that the &lt;code&gt;theme.css&lt;/code&gt; file has the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nl"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As with the HTML, the engine needs to convert the CSS into something that the browser can work with — the CSSOM. Here is how the CSSOM tree will look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft7p1acqazi9oq7j1ik4e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft7p1acqazi9oq7j1ik4e.png" alt="constructing-cssom" width="700" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do you wonder why does the CSSOM have a tree structure? When computing the final set of styles for any object on the page, the browser starts with the most general rule applicable to that node (for example, if it is a child of a body element, then all body styles apply) and then recursively refines the computed styles by applying more specific rules.&lt;/p&gt;

&lt;p&gt;Let's work with the specific example that we gave. Any text contained within a &lt;code&gt;span&lt;/code&gt; tag that is placed within the &lt;code&gt;body&lt;/code&gt; element, has a font size of 16 pixels and has a red color. Those styles are inherited from the &lt;code&gt;body&lt;/code&gt; element. If a &lt;code&gt;span&lt;/code&gt; element is a child of a &lt;code&gt;p&lt;/code&gt; element, then its contents are not displayed due to the more specific styles that are being applied to it.&lt;/p&gt;

&lt;p&gt;Also, note that the above tree is not the complete CSSOM tree and only shows the styles we decided to override in our style sheet. Every browser provides a default set of styles also known as &lt;strong&gt;"user agent styles"&lt;/strong&gt; — that's what we see when we don't explicitly provide any. Our styles simply override these defaults.&lt;/p&gt;

&lt;h3&gt;
  
  
  Constructing the render tree
&lt;/h3&gt;

&lt;p&gt;The visual instructions in the HTML, combined with the styling data from the CSSOM tree, are being used to create a &lt;strong&gt;render tree&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What is a render tree you may ask? This is a tree of the visual elements constructed in the order in which they will be displayed on the screen. It is the visual representation of the HTML along with the corresponding CSS. The purpose of this tree is to enable painting the contents in their correct order.&lt;/p&gt;

&lt;p&gt;Each node in the render tree is known as a renderer or a render object in Webkit.&lt;/p&gt;

&lt;p&gt;This is how the renderer tree of the above DOM and CSSOM trees will look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttf37lmy2o3u4ii81p4h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttf37lmy2o3u4ii81p4h.png" alt="constructing-render-tree" width="700" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To construct the render tree, the browser does roughly the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Starting at the root of the DOM tree, it traverses each visible node. Some nodes are not visible (for example, script tags, meta tags, and so on), and are omitted since they are not reflected in the rendered output. Some nodes are hidden via CSS and are also omitted from the render tree. For example, the span node — in the example above it's not present in the render tree because we have an explicit rule that sets the &lt;code&gt;display: none&lt;/code&gt; property on it.&lt;/li&gt;
&lt;li&gt;For each visible node, the browser finds the appropriate matching CSSOM rules and applies them.&lt;/li&gt;
&lt;li&gt;It emits visible nodes with content and their computed styles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's just look at some of the core things for this class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RenderObject&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;CachedImageClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Repaint the entire object.  Called when, e.g., the color of a border changes, or when a border&lt;/span&gt;
  &lt;span class="c1"&gt;// style changes.&lt;/span&gt;

  &lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;node&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;RenderStyle&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// the computed style&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;RenderStyle&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;style&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each renderer represents a rectangular area usually corresponding to a node's CSS box. It includes geometric info such as width, height, and position.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layout of the render tree
&lt;/h3&gt;

&lt;p&gt;When the renderer is created and added to the tree, it does not have a position and size. Calculating these values is called layout.&lt;/p&gt;

&lt;p&gt;HTML uses a flow-based layout model, meaning that most of the time it can compute the geometry in a single pass. The coordinate system is relative to the root renderer. Top and left coordinates are used.&lt;/p&gt;

&lt;p&gt;Layout is a recursive process — it begins at the root renderer, which corresponds to the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element of the HTML document. Layout continues recursively through a part or the entire renderer hierarchy, computing geometric info for each renderer that requires it.&lt;/p&gt;

&lt;p&gt;The position of the root renderer is &lt;code&gt;0,0&lt;/code&gt; and its dimensions have the size of the visible part of the browser window (a.k.a. the viewport).&lt;/p&gt;

&lt;p&gt;Starting the layout process means giving each node the exact coordinates where it should appear on the screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Painting the render tree
&lt;/h3&gt;

&lt;p&gt;In this stage, the renderer tree is traversed and the renderer's &lt;code&gt;paint()&lt;/code&gt; method is called to display the content on the screen.&lt;/p&gt;

&lt;p&gt;Painting can be global or incremental (similar to layout):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Global&lt;/strong&gt; — the entire tree gets repainted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incremental&lt;/strong&gt; — only some of the renderers change in a way that does not affect the entire tree. The renderer invalidates its rectangle on the screen. This causes the OS to see it as a region that needs repainting and to generate a &lt;code&gt;paint&lt;/code&gt; event. The OS does it in a smart way by merging several regions into one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In general, it's important to understand that painting is a gradual process. For better UX, the rendering engine will try to display the contents on the screen as soon as possible. It will not wait until all the HTML is parsed to start building and laying out the render tree. Parts of the content will be parsed and displayed, while the process continues with the rest of the content items that keep coming from the network.&lt;/p&gt;

&lt;h3&gt;
  
  
  Order of processing scripts and style sheets
&lt;/h3&gt;

&lt;p&gt;Scripts are parsed and executed immediately when the parser reaches a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag. The parsing of the document halts until the script has been executed. This means that the process is synchronous.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the script is external then it first has to be fetched from the network (also synchronously). All the parsing stops until the fetch completes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;HTML5 adds an option to mark the script as asynchronous so that it gets parsed and executed by a different thread.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimizing the rendering performance
&lt;/h3&gt;

&lt;p&gt;If you'd like to optimize your app, there are five major areas that you need to focus on. These are the areas over which you have control:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript&lt;/strong&gt; — in previous posts we covered the topic of writing optimized code that doesn't block the UI, is memory efficient, etc. When it comes to rendering, we need to think about the way your JavaScript code will interact with the DOM elements on the page. JavaScript can create lots of changes in the UI, especially in SPAs. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Style calculations&lt;/strong&gt; — this is the process of determining which CSS rule applies to which element based on matching selectors. Once the rules are defined, they are applied and the final styles for each element are calculated. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layout&lt;/strong&gt; — once the browser knows which rules apply to an element, it can begin to calculate how much space the latter takes up and where it is located on the browser screen. The web's layout model defines that one element can affect others. For example, the width of the  can affect the width of its children and so on. This all means that the layout process is computationally intensive. The drawing is done in multiple layers. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paint&lt;/strong&gt; — this is where the actual pixels are being filled. The process includes drawing out text, colors, images, borders, shadows, etc. — every visual part of each element. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compositing&lt;/strong&gt; — since the page parts were drawn into potentially multiple layers they need to be drawn onto the screen in the correct order so that the page renders properly. This is very important, especially for overlapping elements.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Optimizing your JavaScript
&lt;/h3&gt;

&lt;p&gt;JavaScript often triggers visual changes in the browser. All the more so when building an SPA.&lt;/p&gt;

&lt;p&gt;Here are a few tips on which parts of your JavaScript you can optimize to improve rendering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid &lt;code&gt;setTimeout&lt;/code&gt; or &lt;code&gt;setInterval&lt;/code&gt; for visual updates. These will invoke the &lt;code&gt;callback&lt;/code&gt; at some point in the frame, possible right at the end. What we want to do is trigger the visual change right at the start of the frame not to miss it.&lt;/li&gt;
&lt;li&gt;Move long-running JavaScript computations to Web Workers.&lt;/li&gt;
&lt;li&gt;Use micro-tasks to introduce DOM changes over several frames. This is in case the tasks need access to the DOM, which is not accessible by Web Workers. This basically means that you'd break up a big task into smaller ones and run them inside &lt;code&gt;requestAnimationFrame&lt;/code&gt;, &lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;setInterval&lt;/code&gt; depending on the nature of the task.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Optimize your CSS
&lt;/h3&gt;

&lt;p&gt;Modifying the DOM through adding and removing elements, changing attributes, etc. will make the browser recalculate element styles and, in many cases, the layout of the entire page or at least parts of it.&lt;/p&gt;

&lt;p&gt;To optimize the rendering, consider the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduce the complexity of your selectors. Selector complexity can take more than 50% of the time needed to calculate the styles for an element, compared to the rest of the work which is constructing the style itself.&lt;/li&gt;
&lt;li&gt;Reduce the number of elements on which style calculation must happen. In essence, make style changes to a few elements directly rather than invalidating the page as a whole.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Optimize the layout
&lt;/h3&gt;

&lt;p&gt;Layout re-calculations can be very heavy for the browser. Consider the following optimizations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduce the number of layouts whenever possible. When you change styles the browser checks to see if any of the changes require the layout to be re-calculated. Changes to properties such as width, height, left, top, and in general, properties related to geometry, require layout. So, avoid changing them as much as possible.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;flexbox&lt;/code&gt; over older layout models whenever possible. It works faster and can create a huge performance advantage for your app.&lt;/li&gt;
&lt;li&gt;Avoid forced synchronous layouts. The thing to keep in mind is that while JavaScript runs, all the old layout values from the previous frame are known and available for you to query. If you access &lt;code&gt;box.offsetHeight&lt;/code&gt; it won't be an issue. If you, however, change the styles of the box before it's accessed (e.g. by dynamically adding some CSS class to the element), the browser will have to first apply the style change and then run the layout. This can be very time-consuming and resource-intensive, so avoid it whenever possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Optimize the paint
&lt;/h3&gt;

&lt;p&gt;This often is the longest-running of all the tasks so it's important to avoid it as much as possible. Here is what we can do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Changing any property other than transforms or opacity triggers a paint. Use it sparingly.&lt;/li&gt;
&lt;li&gt;If you trigger a layout, you will also trigger a paint, since changing the geometry results in a visual change of the element.&lt;/li&gt;
&lt;li&gt;Reduce paint areas through layer promotion and orchestration of animations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Support ❤️
&lt;/h2&gt;

&lt;p&gt;It took a lot of time and effort to create this material. If you found this article useful or interesting, please support my work with a small donation. It will help me to continue sharing my knowledge and ideas.&lt;/p&gt;

&lt;p&gt;Make a contribution or Subscription to the author's content: &lt;a href="http://buymeacoffee.com/betelgeuseo" rel="noopener noreferrer"&gt;Buy me a Coffee&lt;/a&gt;, &lt;a href="https://patreon.com/betelgeuseo" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;, &lt;a href="https://www.paypal.com/donate/?hosted_button_id=327N24D6QDLVC" rel="noopener noreferrer"&gt;PayPal&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>browser</category>
      <category>html</category>
    </item>
    <item>
      <title>Ways to Avoid Cross-Browser Compatibility Issues</title>
      <dc:creator>Andrew S.</dc:creator>
      <pubDate>Wed, 09 Jul 2025 19:44:26 +0000</pubDate>
      <link>https://dev.to/betelgeuseas/ways-to-avoid-cross-browser-compatibility-issues-36ec</link>
      <guid>https://dev.to/betelgeuseas/ways-to-avoid-cross-browser-compatibility-issues-36ec</guid>
      <description>&lt;h2&gt;
  
  
  Common Browser Compatibility Issues
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. DOCTYPE Error
&lt;/h3&gt;

&lt;p&gt;Imagine writing the entire code and missing out on the most basic line! Yes, it can lead to a faulty rendering. Several browsers with outdated versions such as the Internet Explorer 8.0 and earlier often check for the Doctype.&lt;/p&gt;

&lt;p&gt;In case it is missing, the site will be not be rendered as per expectations. To understand why the doctype is checked, we would have to understand the two modes in which a browser operates.&lt;/p&gt;

&lt;p&gt;The first mode is called the Strict Mode. In this mode, the browser works with stricter code error checks and making sure that the code adheres to the W3C specifications. The second mode is called the Quirks Mode. The quirks mode was created with an intention of providing backward compatibility to older browser version and they do not perform strict error checking.&lt;/p&gt;

&lt;p&gt;When there is a missing “Doctype” tag in the webpage, the browser tends to go into the quirks mode. At the same time, if there is a browser which doesn’t support HTML5, it will not understand which version to look for. This would lead to some of the tags to become unresponsive and the webpage will not look as intended.&lt;/p&gt;

&lt;p&gt;The solution to this problem is a simple one line code at the very beginning of the code. It looks like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;!DOCTYPE html&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will ensure a perfectly rendered site in every browser available.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Browser Detection
&lt;/h3&gt;

&lt;p&gt;Unlike any other product, browsers are being loaded with technology to optimize output. This means less consumption, more output. But, due to these advancements, even javascript has a lot to offer to browsers. So, at times, when an old browser is being used chances are the javascript fails to detect the browser.&lt;/p&gt;

&lt;p&gt;This is a common cross-browser compatibility issue which is faced due to obsolete java scripts. But, tackling this cross-browser issue is easy. You can remove the browser detection. Instead use Modernizer, a collection of ‘superfast tests’ which list all the features of a browser, hence giving you a seamless experience. Using this the developer can direct the site to focus on features rather than browsers.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. HTML/ CSS Validation
&lt;/h3&gt;

&lt;p&gt;Another major cross-browser compatibility issue faced by developers is the validation of HTML and CSS codes. This is mainly because different browsers read code differently. And not only read but also handle them differently.&lt;/p&gt;

&lt;p&gt;There are times when developers are stuck with an error as small as missing out on closing a tag. While some browsers might autocorrect, others might not display the feature it signifies. For example, missing out on might cause an error on Internet Explorer and not on chrome.&lt;/p&gt;

&lt;p&gt;It is a very common cross-browser compatibility issue and has a simple solution. One can use code &lt;a href="https://validator.w3.org/" rel="noopener noreferrer"&gt;validating tools for HTML&lt;/a&gt; and CSS depending on their requirements. These validators are powered by W3C.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. CSS Resets
&lt;/h3&gt;

&lt;p&gt;Browsers by default have a design layout (CSS style) which is applied to the website. For any website to implement its own layout, the default has to be overridden. Until implemented, websites will be rendered differently on different browsers.&lt;/p&gt;

&lt;p&gt;To overcome this cross-browser issue, the websites rendered are ‘reset’ to the same basics. For this, developers use CSS reset style sheets. Addition of the style sheet ensures avoidance of any layout design issue.&lt;/p&gt;

&lt;p&gt;Some common reset style sheets used include HTML5Reset, &lt;a href="https://meyerweb.com/eric/tools/css/reset/" rel="noopener noreferrer"&gt;Eric Meyers CSS Reset&lt;/a&gt; and the Github based &lt;a href="https://github.com/necolas/normalize.css/blob/master/normalize.css" rel="noopener noreferrer"&gt;Normalize.css&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Layout Compatibility
&lt;/h3&gt;

&lt;p&gt;As previously mentioned, browsers have default layout styling. But, developers started using ‘Resets’ in CSS to remove the default design and apply their own.&lt;/p&gt;

&lt;p&gt;It has been one of the most common cross-cross-browser compatibility issues and has often been associated with one of the two reasons. It is either due to an irresponsive design on mobile devices or due to the difference in or lack of support for layouts by modern browsers.&lt;/p&gt;

&lt;p&gt;These issues are now easier to solve. A common solution is the use of floats which is supported by most browsers. But, a float is a floating image inside a text box and comes with limitations.&lt;/p&gt;

&lt;p&gt;For the modern-day layout, dedicated layout mechanisms such as CSS grids and Flexbox have been introduced. These are supported by most modern browsers and are effectively used by developers.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Vendor Specific functions
&lt;/h3&gt;

&lt;p&gt;The functions defined by the developer are, at times, contain functionality specific to browsers. While writing the CSS code, these browsers are denoted by specific codes.&lt;/p&gt;

&lt;p&gt;To ensure proper functionality and avoid this cross-browser issue, one needs to ensure the addition of the function without the prefix as well. This will ensure there is no error in other browsers.&lt;/p&gt;

&lt;p&gt;Common vendor prefixes include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mozilla Firefox (-moz)&lt;/li&gt;
&lt;li&gt;Internet Explorer (-ms)&lt;/li&gt;
&lt;li&gt;Opera (-o)&lt;/li&gt;
&lt;li&gt;Safari and Chrome (-webkit)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  7. Website Feature Functionality
&lt;/h3&gt;

&lt;p&gt;While technology keeps evolving and there are workarounds for the changes, a check on the features of the website should be on your checklist to avoid cross-browser compatibility issues.&lt;/p&gt;

&lt;p&gt;While cross-browser testing with tools is a part of the process, cross-checking the feature support with various browsers before putting it out in the market. Another important aspect is the use of &lt;a href="https://philipwalton.github.io/polyfill/" rel="noopener noreferrer"&gt;polyfills&lt;/a&gt; and feature detection. This is a preventive measure which can improve cross-browser compatibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Use Cross-Browser Friendly Libraries And Frameworks
&lt;/h3&gt;

&lt;p&gt;Most websites are comprised of various third-party libraries and frameworks. These tools help developers to bring in structure, scalability, and security to the web applications. Using the wrong alternatives to these libraries can lead to a variety of cross-browser issues that can range from the incorrect working of library features to the complete framework crash.&lt;/p&gt;

&lt;p&gt;To avoid such issues, it is highly recommended to use well known and trusted frameworks that are cross-browser friendly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Angular JS&lt;/strong&gt; and &lt;strong&gt;React JS&lt;/strong&gt; are some examples of cross-browser friendly web application development frameworks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bootstrap&lt;/strong&gt;, &lt;strong&gt;Animate&lt;/strong&gt; are examples of trusted CSS libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JQuery&lt;/strong&gt; is an example of a cross-browser friendly scripting library.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  9. Use Separate Stylesheets For Different Browsers
&lt;/h3&gt;

&lt;p&gt;Stylesheets tend to have the capability to quickly turn into a mess. As more and more styles come into the picture, they get bulky and unstructured. In addition to this, if all the styles that cater to different browsers come into the same stylesheet, it becomes a maintenance nightmare.&lt;/p&gt;

&lt;p&gt;To navigate from this difficulty, it is beneficial to keep the styles separate for each type of browser that the website supports. Once the separation is complete, it can be included within the same HTML page by using &lt;a href="https://www.quirksmode.org/css/condcom.html" rel="noopener noreferrer"&gt;conditional comments&lt;/a&gt; which help in invoking the right stylesheet for the right type of browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Browser-specific Features
&lt;/h3&gt;

&lt;p&gt;Browser-specific features in compatibility testing refer to functionalities or behaviors that are specific to a particular web browser.&lt;/p&gt;

&lt;p&gt;Different browsers use different rendering engines (e.g., Blink, Gecko, WebKit), and each has its way of interpreting and displaying web content, so it’s important to test how the website or application is rendered in each browser.&lt;/p&gt;

&lt;p&gt;Solution: Verify the website’s layout, design, and interactivity remains consistent across different browsers such as Chrome, Firefox, Safari, Internet Explorer, and Edge. Testing on both desktop and mobile versions of browsers may also be necessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  11. Media Formats and Codecs Issues
&lt;/h3&gt;

&lt;p&gt;Some browsers may support popular formats like MP4, WebM, or Ogg for video, while others may have limitations or require additional plugins. Different browsers and devices may support different codecs, and compatibility issues can arise if a specific codec is not supported.&lt;/p&gt;

&lt;p&gt;Solution: Compatibility testing verifies that the media files encoded with different codecs are played back correctly and consistently across the supported platforms. It also checks to handle different image formats, such as JPEG, PNG, GIF, or SVG.&lt;/p&gt;

&lt;h2&gt;
  
  
  Support ❤️
&lt;/h2&gt;

&lt;p&gt;It took a lot of time and effort to create this material. If you found this article useful or interesting, please support my work with a small donation. It will help me to continue sharing my knowledge and ideas.&lt;/p&gt;

&lt;p&gt;Make a contribution or Subscription to the author's content: &lt;a href="http://buymeacoffee.com/betelgeuseo" rel="noopener noreferrer"&gt;Buy me a Coffee&lt;/a&gt;, &lt;a href="https://patreon.com/betelgeuseo" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;, &lt;a href="https://www.paypal.com/donate/?hosted_button_id=327N24D6QDLVC" rel="noopener noreferrer"&gt;PayPal&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>frontend</category>
      <category>webdev</category>
      <category>browser</category>
    </item>
    <item>
      <title>What is Critical Rendering Path?</title>
      <dc:creator>Andrew S.</dc:creator>
      <pubDate>Wed, 09 Jul 2025 18:06:35 +0000</pubDate>
      <link>https://dev.to/betelgeuseas/what-is-critical-rendering-path-3k73</link>
      <guid>https://dev.to/betelgeuseas/what-is-critical-rendering-path-3k73</guid>
      <description>&lt;p&gt;Users predominantly care about a fast and smooth experience when using web applications. If they don’t get these two they won’t visit that website. Research also suggests that web page loading speed and experience are directly related to the customer conversion rate. The higher the page loading speed, the higher the customer conversion.&lt;/p&gt;

&lt;p&gt;In one research, Walmart found that for every 1-second improvement in page load time, conversions increased by 2%.&lt;/p&gt;

&lt;p&gt;To understand how webpage performance can be optimized, we must understand how a webpage is created on any browser. To understand this, we need to know What is Critical rendering path.&lt;/p&gt;

&lt;p&gt;So, What is the Critical Rendering Path or CRP?&lt;/p&gt;

&lt;p&gt;A critical rendering path is the step-by-step process carried out to convert HTML, CSS, and JS files into pixels on the screen.&lt;/p&gt;

&lt;p&gt;This process has five steps.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;DOM construction.&lt;/li&gt;
&lt;li&gt;CSSOM construction.&lt;/li&gt;
&lt;li&gt;Render Tree Creation.&lt;/li&gt;
&lt;li&gt;Layout Process.&lt;/li&gt;
&lt;li&gt;Painting.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  DOM construction
&lt;/h3&gt;

&lt;p&gt;When the user enters the URL in the address bar, the browser sends a request to the server for an HTML page. The server fulfills the request by sending back an HTML page in the response.&lt;/p&gt;

&lt;p&gt;The rendering engine uses the HTML parser to parse the HTML file. The HTML file data will be converted to tokens using the tokenization process.&lt;/p&gt;

&lt;p&gt;consider the below HTML file data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;'cl-head'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Heading &lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id =&lt;/span&gt;&lt;span class="s"&gt;"i-para"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; paragraph data &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tokenizer will convert data into tokens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;StartTag:html, StartTag:head EndTag:head, StartTag:body, StartTag:h1, Heading,
EndTag:h1, StartTag:p, paragraph data, EndTag:p, EndTag:body, EndTag:html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fozca7rc7t29iompw00i0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fozca7rc7t29iompw00i0.png" alt="dom-construction" width="720" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the tokenization process is over. Tokens created in the tokenization stage will used to create the DOM. Each token will be processed and a node will be created based on the occurrence. Each node will have respective data and attributes. This is how the DOM tree is created.&lt;/p&gt;

&lt;p&gt;One thing we need to notice, when we request data, the server sends it chunk by chunk, so the DOM will be constructed incrementally with available data.&lt;/p&gt;

&lt;h3&gt;
  
  
  CSSOM Construction
&lt;/h3&gt;

&lt;p&gt;While parsing HTML data, if the parser encounters the &lt;code&gt;link&lt;/code&gt; or &lt;code&gt;style&lt;/code&gt; tags, the browser will initiate the request for the CSS file, and if there are embedded styles within the &lt;code&gt;style&lt;/code&gt; tags, those will be available readily. These CSS data will be parsed using CSS parsers. This involves tokenizing the CSS, parsing it into a hierarchical structure of nodes with respective properties and values, and creating the CSS Object Model.&lt;/p&gt;

&lt;p&gt;CSSOM won’t be constructed incrementally, like how DOM is created.&lt;/p&gt;

&lt;p&gt;Let’s assume we created the CSSOM tree using partial CSS data, and it has a value of &lt;code&gt;.h1 { color: white, background: purple }&lt;/code&gt;. When we render it. It will have a &lt;code&gt;Purple&lt;/code&gt; background color.&lt;/p&gt;

&lt;p&gt;However, We have a &lt;code&gt;h1&lt;/code&gt; value in the CSS file which is not yet requested and it will override the initial value.&lt;/p&gt;

&lt;p&gt;If we render this partial CSSOM tree, the rendered page will have a purple background. This is not an expected style. Hence CSSOM tree will be rendered once all the CSS data is parsed&lt;/p&gt;

&lt;p&gt;Therefore, &lt;strong&gt;CSSOM&lt;/strong&gt; construction is &lt;strong&gt;RENDER BLOCKING&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One thing to note here, while HTML parsing, if the parser encounters style tags it will make a request and it won’t block the parsing. But what if it encounters &lt;code&gt;script&lt;/code&gt; a tag?&lt;/p&gt;

&lt;p&gt;When parser encounters &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag, the browser will request the JS file. The gotcha here is, that the model of the web is synchronous, whenever the parser encounters the script tag, The parsing will be stopped until the file is downloaded, compiled, and executed by the JS engine. This will create a blank screen on the window.&lt;/p&gt;

&lt;p&gt;So how do we handle it?&lt;/p&gt;

&lt;p&gt;We need to use &lt;code&gt;async&lt;/code&gt; or &lt;code&gt;differ&lt;/code&gt; attribute in the script tag. These kinds of operations will be executed asynchronously, so they will be parsed and executed in a separate thread.&lt;/p&gt;

&lt;p&gt;To handle such requests we have a Speculative Parser. This will only work for external resources that need to be parsed, such as scripts, images, or styles. BTW, it doesn’t modify the DOM tree.&lt;/p&gt;

&lt;h3&gt;
  
  
  Render Tree Construction
&lt;/h3&gt;

&lt;p&gt;Once the DOM and CSSOM are constructed, a new tree will be created by combining both Object Models, and it is called a Render Tree. The render tree will have all the node elements, except node value with &lt;code&gt;{display: none}&lt;/code&gt;. However, the node with the &lt;code&gt;{display: hide}&lt;/code&gt; value will be included.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwaxn4tmyg5hca7inxpf4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwaxn4tmyg5hca7inxpf4.png" alt="render-tree-construction" width="720" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Layout Process
&lt;/h3&gt;

&lt;p&gt;Once the render tree is ready, the Layout process will start. In the layout process, the render engine determines where and how each element of the render tree should be drawn. How much space should be consumed in a given real estate?&lt;/p&gt;

&lt;p&gt;The size of the real estate depends on the viewport of the device. If we don’t mention it will take 960px by default. If we want to change the size based on the device we should mention it in the header tag of the HTML as &lt;code&gt;&amp;lt;meta name="viewport" content="width=device-width"&amp;gt;&lt;/code&gt; This will help the render engine to consider the viewport of the device before calculating the size and location for each element.&lt;/p&gt;

&lt;p&gt;The layout performance depends on the complexity of the render tree structure and complexity. The more the number of nodes, the more it will take time to Layout the elements. It also depends on the changing dimensions and locations, hence avoiding scrolling or animation during this process will improve the layout performance. Also, by considering the batch update we can improve the performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Paint
&lt;/h3&gt;

&lt;p&gt;This is the last step of the Rendering Path. In this step, Pixels will be painted on the places determined during the layout process. It involves the conversion of boxes or shapes into pixels and this process is called rasterization.&lt;/p&gt;

&lt;p&gt;Often a painting is done on a single surface, however, the render engine does it on different layers. Later these layers will be combined and this process is called layer composition.&lt;/p&gt;

&lt;p&gt;The painting of the layers will happen on the CPU and these layers will be uploaded to the GPU to compose them into a single layer.&lt;/p&gt;

&lt;p&gt;When there are dynamic changes such as adding extra DOM, changing the position of an element, or changing the font size will cause relayout (reflow), repaint, and invalidation of the cache. Browsers normally try to do minimal possible action in response to changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgrc4su2mopt95drzity3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgrc4su2mopt95drzity3.png" alt="paint" width="720" height="94"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In all these stages there is a chance of introducing delay. Understanding each stage we can optimize the performance of the website.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Optimize the CRP?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Identify critical resources in the downloading process.&lt;/li&gt;
&lt;li&gt;Prioritize downloading critical assets over non-critical ones.&lt;/li&gt;
&lt;li&gt;Use techniques like async or defer tags for non-critical assets such as JS files or images.&lt;/li&gt;
&lt;li&gt;Decrease the size of critical assets to reduce the number of requests.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Support ❤️
&lt;/h2&gt;

&lt;p&gt;It took a lot of time and effort to create this material. If you found this article useful or interesting, please support my work with a small donation. It will help me to continue sharing my knowledge and ideas.&lt;/p&gt;

&lt;p&gt;Make a contribution or Subscription to the author's content: &lt;a href="http://buymeacoffee.com/betelgeuseo" rel="noopener noreferrer"&gt;Buy me a Coffee&lt;/a&gt;, &lt;a href="https://patreon.com/betelgeuseo" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;, &lt;a href="https://www.paypal.com/donate/?hosted_button_id=327N24D6QDLVC" rel="noopener noreferrer"&gt;PayPal&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>programming</category>
      <category>html</category>
    </item>
    <item>
      <title>How does Event Loop Work?</title>
      <dc:creator>Andrew S.</dc:creator>
      <pubDate>Wed, 09 Jul 2025 17:47:22 +0000</pubDate>
      <link>https://dev.to/betelgeuseas/how-does-event-loop-work-2mdg</link>
      <guid>https://dev.to/betelgeuseas/how-does-event-loop-work-2mdg</guid>
      <description>&lt;p&gt;JavaScript is required for every browser to function and manage its interactivity. The code is compiled and executed by the JavaScript Engine within the browser. JavaScript is a single-threaded language. It only handles one task at a time. If we assign another work, it won’t entertain until the current one is finished.&lt;/p&gt;

&lt;p&gt;Imagine, you have a task that takes around 1 minute to complete, JavaScript is true to its nature, it will not take another task until it finishes. In this case, the webpage will be stuck for a minute. And the user has to wait until it is completed. Imagine how frustrating it is to wait for a minute and stare at the blank screen.&lt;/p&gt;

&lt;p&gt;To overcome this, the browser provides some features, that the JavaScript engine doesn’t, those are Web APIs, such as setTimeout, DOM API, HTTP requests, and so on. Using these we can achieve asynchronous and non-blocking behaviour.&lt;/p&gt;

&lt;p&gt;Now the question is, how can we achieve this non-blocking behavior using provided Web APIs and others? Using Event Loop.&lt;/p&gt;

&lt;p&gt;Before we understand the Event Loop we will see how code is executed in the JavaScript Engine.&lt;/p&gt;

&lt;h3&gt;
  
  
  How code is executed in the JavaScript Engine?
&lt;/h3&gt;

&lt;p&gt;Whenever the browser receives the JavaScript file, it sends it to the JavaScript Engine. The code will be stored in the Memory Heap. As the code starts executing, line-by-line code is pushed into the Call Stack. The Call Stack executes the code and returns the value, once the value is returned, that line of code will be popped out.&lt;/p&gt;

&lt;p&gt;Let’s see an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;state 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;state 2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;state 3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the code executes, &lt;code&gt;foo()&lt;/code&gt; function will be pushed into the Call Stack and then it will be executed. &lt;code&gt;foo&lt;/code&gt; has 3 console statements. the first statement is pushed into the Call Stack, since it is straightforward, it will be executed and return the output “state 1” and it'll be popped out. The second statement will pushed into the stack, executed, and then popped out. similarly, the last statement will be pushed into the stack, executed, and popped out of the stack. Finally, function &lt;code&gt;foo&lt;/code&gt; will be popped out of the Call Stack.&lt;/p&gt;

&lt;p&gt;1/5 — Function foo is pushed to the CallStack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6trhhxov8ehp1uaqz4tq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6trhhxov8ehp1uaqz4tq.png" alt="call-stack-1" width="720" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2/5 — The first statement is pushed and executed. Once it prints the value, it will be popped out of the Call Stack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8tf2glgyynov2j0tci27.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8tf2glgyynov2j0tci27.png" alt="call-stack-2" width="800" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3/5 — The second statement will be pushed, and executed. Once it returns the value, it is popped out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2oub0os1z3sztv0nmks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx2oub0os1z3sztv0nmks.png" alt="call-stack-3" width="800" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4/5 — similarly the last statement.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm6vj12066sj0hh22veqm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm6vj12066sj0hh22veqm.png" alt="call-stack-4" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;5/5 — Finally, once all the lines of code are executed, function foo will be popped out of the Call Stack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fezamqzjjl29v1uhcz74x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fezamqzjjl29v1uhcz74x.png" alt="call-stack-5" width="720" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Event Loop — When code has &lt;code&gt;setTimeout&lt;/code&gt;.
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;state 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;state 2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;state 3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the JavaScript engine receives this code, the first statement will be pushed into the stack. Since it is a simple console function it will be executed and output will be returned. i.e. “state 1” and popped out of the Call Stack. Now, the second statement will be pushed into the Call Stack. This time, the setTimeout function is Web API, it will given to the Browser Engine to execute. so, this statement will be popped out. Next, 3rd statement will pushed into the Call Stack. it will be executed and popped out of the stack.&lt;/p&gt;

&lt;p&gt;We know, we have given one statement to the browser to execute. The browser runs the timers for 100 ms and then it will return the callback function. This callback function will not be directly moved to the Call Stack. Instead, it will be moved to the callback queue. The queue works on a first come first serve principle. The statements which are sent to the browser to execute will all be stored in the queue. Once the call stack is empty, The Event Loop takes the first statement from the queue stack and pushes it to the Call Stack.&lt;/p&gt;

&lt;p&gt;Call Stack executes the function, returns values, and then the function will be popped out. Now, Event Loop checks the Call Stack, If the Call Stack is empty, it will take the first item from the queue stack and pushed to the Call Stack. The Call Stack continues its work.&lt;/p&gt;

&lt;p&gt;1/4 — The first statement will be pushed to Call Stack and executed. Once the value is printed, it will be popped out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyupy8oxaixzbl1rtymhz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyupy8oxaixzbl1rtymhz.png" alt="call-stack-time-1" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2/4 — The second statement will be pushed, Since, it is part of the Web API, it will sent to Browser Engine to handle the execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft83x7j77ecbaasp3gqva.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft83x7j77ecbaasp3gqva.png" alt="call-stack-time-2" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3/4 — Now, the last statement will be pushed, executed and once the value is printed it will be popped out of the Call Stack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxyvaheexubn4t20zqpl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxyvaheexubn4t20zqpl.png" alt="call-stack-time-3" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4/4 — Event Loop checks the Call Stack, If the Call Stack is empty, it will take the first item from the queue and pushed to the Call Stack. The Call Stack continues its work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi7bgb4tc4qotw14acaku.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi7bgb4tc4qotw14acaku.png" alt="call-stack-time-4" width="800" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the output of the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;state 1
state 3
state 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  When code has &lt;code&gt;setTimeout&lt;/code&gt; and &lt;code&gt;Promise&lt;/code&gt; both.
&lt;/h3&gt;

&lt;p&gt;The Event Loop’s main function is to check whether the Call Stack is empty or not, If it is empty, push the first item from the queue to the Call Stack until the queue stack is empty.&lt;/p&gt;

&lt;p&gt;You might be saying this is for setTimeout, but what about for the Promises? Promises also take time to execute.&lt;/p&gt;

&lt;p&gt;Well, In this case, Event Loop works a little bit differently. But not completely different. It just sets different priorities for Promise kind of items.&lt;/p&gt;

&lt;p&gt;Let’s see the last example with the promise code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;state 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;state 2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;state 4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;state 5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;state 3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the first statement will be pushed to the Call Stack, executed, and popped out of the Call Stack. Now, the second statement will be pushed to the stack, since is setTimeout, It will be sent to the browser to handle by popping out of the Call Stack. Next, the 3rd statement will be pushed to the Call Stack, which is also web API, and it will be given to the browser to execute. The fourth statement is Promise, Promise is pushed to the stack. It will be sent to the browser engine to handle it by popping out of the Call Stack. Finally, the console statement is pushed, executed, and popped out of the stack.&lt;/p&gt;

&lt;p&gt;Now, in the event loop side, The setTimeout functions will be executed and both the callback functions will be pushed to the task queue. Promise will be executed, and it’s &lt;code&gt;.then()&lt;/code&gt; function will be pushed to another queue i.e. micro-task queue.&lt;/p&gt;

&lt;p&gt;In the Event Loop, we have a Macro-task queue/callback queue(The normal queue we use for the tasks) and a Micro-task queue. Micro-task queue has the highest priority, hence the items in the micros-task will be handled first and then the Macro-task. For every Macro-task queue item, all the items in the micro-task queue will handled. Hence, promise callback will addressed first.&lt;/p&gt;

&lt;p&gt;Once the Micro-task queue is empty, Event Loop checks whether the Call Stack is empty or not, if it is empty, it will push the items from the Macro-task queue and the Call Stack executes it and pops out of the Call Stack.&lt;/p&gt;

&lt;p&gt;Here is the output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;state 1
state 3
state 5
state 2
state 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;1/8— The first statement will be pushed to Call Stack and executed. Once the value is printed, it will be popped out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F471mserrxhl8852ioe2z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F471mserrxhl8852ioe2z.png" alt="call-stack-time-promise-1" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2/8 — The second statement will be pushed, Since, it is part of the Web API, it will sent to Browser Engine to handle the execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tdftpysysy6lc0t0pn9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tdftpysysy6lc0t0pn9.png" alt="call-stack-time-promise-2" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3/8— The third statement will be pushed, Since, it is also a part of the Web API, it will sent to Browser Engine to handle the execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2dyjfdqe8tn6br4u0nje.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2dyjfdqe8tn6br4u0nje.png" alt="call-stack-time-promise-3" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4/8— The fourth statement will be pushed, Since, it is also a part of the Web API, it will sent to Browser Engine to handle the execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffxojlmiqyak834mq9nq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffxojlmiqyak834mq9nq.png" alt="call-stack-time-promise-4" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;5/8— Now, the last statement will be pushed, executed and once the value is printed it will be popped out of the Call Stack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcknuq51kuwgc07vep6jo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcknuq51kuwgc07vep6jo.png" alt="call-stack-time-promise-5" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;6/8 — The setTimeout functions will be executed as per the delay provided, and the callback functions will be pushed to the task queue. Promise will be executed, and it’s &lt;code&gt;.then()&lt;/code&gt; function will be pushed to another queue i.e. micro-task queue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65pwwy8izbujjje486ky.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65pwwy8izbujjje486ky.png" alt="call-stack-time-promise-6" width="800" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;7/8 — Micro-task queue has the highest priority, hence, the items in the micros-task will be handled first. Event loop pushes the Micro-task queue item into the Call Stack. It will be executed and popped out of it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fio5xbnlosa2c5tv3aiu6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fio5xbnlosa2c5tv3aiu6.png" alt="call-stack-time-promise-7" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;8/8 — Once the Micro-task queue is empty, Event Loop picks functions from the Macro-task queue and pushed them to the Call Stack. The Call Stack executes functions and pops out of the it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3cee1tbir0yjagh2b95x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3cee1tbir0yjagh2b95x.png" alt="call-stack-time-promise-8" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Understand Event Loop in Layman terms?
&lt;/h3&gt;

&lt;p&gt;Imagine a big condiment shop with a nice setup of a front counter and kitchen at the backend to prepare items like sandwiches, omelets, Maggie, etc. All the items on the front counter are sold, such as Biscuits, snacks, tea, and other food items like sandwiches, omelets, and Maggie.&lt;/p&gt;

&lt;p&gt;It is a busy shop and orders are handled in a queue. The person sitting at the counter takes care of it and he will be very busy handling them.&lt;/p&gt;

&lt;p&gt;Whenever he receives an order, he checks, whether the order is delivered immediately or it takes time. If it is delivered immediately it will be served by him. For example, cigarettes or snacks.&lt;/p&gt;

&lt;p&gt;If he receives orders like, omelettes, Maggie, or Sandwiches, he knows that it will take time to prepare and deliver. So, he shouts at the kitchen and asks people in the kitchen to prepare. Since he is very busy, he can not track whether the order is ready or not. For that, he keeps an Assistant. His job is to check whether the person on the counter is done with his order handling or not. If he is done will all, then he gives a prepared order to him. He never disturbs him while he was handling the orders.&lt;/p&gt;

&lt;p&gt;This assistant has a queue system. Whenever the order is prepared from the kitchen, he keeps it in his queue and based on the order in which it is queued, he will give it to the person on the counter to complete the take order.&lt;/p&gt;

&lt;p&gt;If you could see the whole process.&lt;/p&gt;

&lt;p&gt;The person who is sitting on the counter and executing the order -&amp;gt; Call Stack.&lt;/p&gt;

&lt;p&gt;The kitchen in which items are prepared is -&amp;gt; WebAPIs&lt;/p&gt;

&lt;p&gt;The assistant who is helping the person on the counter is -&amp;gt; Event Loop.&lt;/p&gt;

&lt;p&gt;The queue he is managing to stack the order is -&amp;gt; callback queue&lt;/p&gt;

&lt;p&gt;The assistant can keep other sub-assistant a man and a woman.&lt;/p&gt;

&lt;p&gt;The assistant is a kind of womanizer, he always prefers orders that are on the woman’s side. And those will be delivered first. If a woman’s side orders are emptied, then man’s side orders will be served to the counter.&lt;/p&gt;

&lt;p&gt;Man sub-assistant is → Macro-task queue&lt;/p&gt;

&lt;p&gt;Women sub-assistant is -&amp;gt; Micro-task queue&lt;/p&gt;

&lt;h2&gt;
  
  
  Support ❤️
&lt;/h2&gt;

&lt;p&gt;It took a lot of time and effort to create this material. If you found this article useful or interesting, please support my work with a small donation. It will help me to continue sharing my knowledge and ideas.&lt;/p&gt;

&lt;p&gt;Make a contribution or Subscription to the author's content: &lt;a href="http://buymeacoffee.com/betelgeuseo" rel="noopener noreferrer"&gt;Buy me a Coffee&lt;/a&gt;, &lt;a href="https://patreon.com/betelgeuseo" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;, &lt;a href="https://www.paypal.com/donate/?hosted_button_id=327N24D6QDLVC" rel="noopener noreferrer"&gt;PayPal&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>programming</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How do Browsers Work?</title>
      <dc:creator>Andrew S.</dc:creator>
      <pubDate>Tue, 08 Jul 2025 19:13:41 +0000</pubDate>
      <link>https://dev.to/betelgeuseas/how-do-browsers-work-2bma</link>
      <guid>https://dev.to/betelgeuseas/how-do-browsers-work-2bma</guid>
      <description>&lt;p&gt;Browser is the way to connect to the internet and access information from around the world. Every day millions of web pages are visited. If you are a web developer, you must know how these browsers work. Because this will help you optimize performance and improve the user experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1pmgp0l5zlvsalyxer7k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1pmgp0l5zlvsalyxer7k.png" alt="Browser Work" width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Browser Overview
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Users request a web page by entering the URL in the address bar. If it is for the first time, the Browser sends the request to DNS (Domain Name Server) and gets the IP address of the place where the information is stored.&lt;/li&gt;
&lt;li&gt;Based on the IP address, It creates a secure TCP connection.&lt;/li&gt;
&lt;li&gt;The network layer sends the request to the Server to share the webpage resources.&lt;/li&gt;
&lt;li&gt;Server then verifies and analyses the request and sends the data (HTML, CSS, Javascript, Images, Fonts, etc.).&lt;/li&gt;
&lt;li&gt;The browser receives the data and using the Rendering Engine renders the web page content. If there is any script to be executed, the browser will use Javascript Engine to compile and execute.&lt;/li&gt;
&lt;li&gt;If any data needs to be persisted, that will be cached for further use (So that website performance can be increased by reducing the network calls). It could be for future Network requests or some data calculations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The browser has a high-level Infrastructure and it has the following components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;User Interface&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network Layer&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Browser Engine&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rendering Engine&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Javascript Engine&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Storage Layer&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fii6fu9n6q1es7brznep0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fii6fu9n6q1es7brznep0.png" alt="Browser Architecture" width="695" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Browser has 4 basic steps to work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Request&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Render&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Display&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Store&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Request
&lt;/h3&gt;

&lt;p&gt;Users request a web page by entering the URL in the address bar. The browser connects with the server and requests the page resource to display it on the screen.&lt;/p&gt;

&lt;p&gt;So how does this connection and communication work in the browser?&lt;/p&gt;

&lt;p&gt;This is handled by &lt;code&gt;Network Layer&lt;/code&gt;. This is how it works under the hood.&lt;/p&gt;

&lt;h4&gt;
  
  
  Network Layer
&lt;/h4&gt;

&lt;p&gt;When the browser receives a web page URL from the address bar, It checks if the requested page address is already there in the DNS cache, If not, Network Layer establishes the connection with DNS and requests for the IP address of the server.&lt;/p&gt;

&lt;p&gt;Network Layer uses this IP address to create the TCP connection with the Server.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the TCP connection is established over HTTPS, one more roundabout trip happens with the server to build the secure connection, i.e. TLS/SSL. Here server and client decide what kind of cipher will be used to encrypt the communication and the server will send the digital certificate to confirm it’s identity. Once it is verified by the client. Secure connection is established.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once, the secure connection is established. Network Layer sends the initial HTTPS &lt;code&gt;GET request&lt;/code&gt; on behalf of the browser. Most often, an HTML file of the webpage is requested. The server receives the request and it will respond with relevant headers and content of HTML.&lt;/p&gt;

&lt;h3&gt;
  
  
  Render
&lt;/h3&gt;

&lt;p&gt;The server sends the data. It will be processed using the Render Engine and displayed on the screen. To process this data and display it on the screen, the browser takes the help of &lt;code&gt;Render Engine&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Render Engine
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;Render Engine&lt;/code&gt; uses &lt;a href="https://medium.com/@ph_vinayak/what-is-the-critical-rendering-path-66c3a9bd9183" rel="noopener noreferrer"&gt;Critical Rendering Path&lt;/a&gt; to convert data into pixels on the screen.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The received HTML document will be parsed using an HTML parser. The parser converts content into tokens, using tokenization. These tokens will used to create the DOM tree. The DOM tree will have the nodes. These nodes contain the content and attributes of each element in the Document.&lt;/li&gt;
&lt;li&gt;Next up, style sheet data will be parsed by a CSS parser. The parser converts data into tokens, tokens into CSSOM tree. Though DOM Tree creation and CSSOM creation look similar, however, underneath both use different algorithms. CSSOM is a Tree of nodes with respective style data.&lt;/li&gt;
&lt;li&gt;By combining DOM and CSSOM a new tree called Render Tree is created. The Render tree will have all the elements except the element with &lt;code&gt;{display: none}&lt;/code&gt; property. It is a hierarchy of nodes, and each node has content, style properties, and attributes to render the elements on the screen.&lt;/li&gt;
&lt;li&gt;Based on the availability of Elements in the Render Tree, the Layout process starts. In this process dimensions and position of each element will be calculated to paint where each element should appear on the screen.&lt;/li&gt;
&lt;li&gt;After the Layout, the Painting process starts, In painting, Pixels are drawn based on the node information. This is done layer by layer. These layers will be composed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faofkl69vv5rjnpxh2i2x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faofkl69vv5rjnpxh2i2x.png" alt="Render Engine" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The rendering engine does this chunk by chuck. The moment it gets the data it will start the process of layout and painting. It will not wait until all the data is downloaded.&lt;/p&gt;

&lt;h4&gt;
  
  
  Javascript Engine
&lt;/h4&gt;

&lt;p&gt;While parsing HTML document data, we will come across some blocking (Javascript) and non-blocking resources (CSS, fonts, images).&lt;/p&gt;

&lt;p&gt;Non-blocking resources will be handled by parsers, whereas blocking resources, Javascript files, are compiled and executed by the &lt;code&gt;Javascript Engine&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Javascript Engine&lt;/code&gt; has two components, a Memory Head and a Call stack.&lt;/p&gt;

&lt;p&gt;Memory Heap is the place where all the javascript code is stored.&lt;/p&gt;

&lt;p&gt;The call stack is a stack data structure that keeps track of function calls and manages their execution order by &lt;strong&gt;Last In First Out&lt;/strong&gt; manner.&lt;/p&gt;

&lt;p&gt;Javascript is a single-threaded language, it executes one task at a time. If it gets multiple tasks, it won’t entertain until it finishes the existing task at hand.&lt;/p&gt;

&lt;p&gt;The Javascript engine has to handle multiple tasks like I/O events, data fetching, etc, in such scenarios the task will get stuck and users can see a blank screen or a jank effect on the screen. This blocking issue can be handled by running these tasks asynchronously.&lt;/p&gt;

&lt;p&gt;For that, the JS engine uses some browser-provided features like setTimeout, Fetch, DOM API, HTTP, etc., and executes tasks asynchronously using a process called Event Loop.&lt;/p&gt;

&lt;p&gt;Learn More about &lt;a href="https://medium.com/@ph_vinayak/how-does-event-loop-work-understand-through-analogy-bc19eef631a9" rel="noopener noreferrer"&gt;Event Loop Here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Display
&lt;/h3&gt;

&lt;h4&gt;
  
  
  User Interface:
&lt;/h4&gt;

&lt;p&gt;Basically, it is about how the &lt;code&gt;User Interface&lt;/code&gt; of any browser should look like. Such as the address bar, Forward/Backward buttons, Home Button, Bookmark menu, Input, etc. Over the period, after many iterations, the whole industry has come to a common design and specification. Along with these, we have a large viewport to display content fetched from the server.&lt;/p&gt;

&lt;h4&gt;
  
  
  Browser Engine:
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;Browser Engine&lt;/code&gt; takes care of most of the browser functionality either directly or indirectly.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It handles primitive functionalities like, forward, reload, backward, navigation, bookmarks, alerts, etc.&lt;/li&gt;
&lt;li&gt;Any kind of user interaction on the screen will be communicated to the &lt;code&gt;Render Engine&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It uses the &lt;code&gt;Network Layer&lt;/code&gt; to communicate with the server.&lt;/li&gt;
&lt;li&gt;It manages the browser extension, add-ons, tab handling, history management, etc.&lt;/li&gt;
&lt;li&gt;It handles browser security. It not only prevents malicious activity but also protects user privacy.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Storage
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Data Storage Layer&lt;/code&gt; is the persistence layer, which is used by the browser to save data locally. It could be used to cache data or persist the data or other usages.&lt;/p&gt;

&lt;p&gt;There different types of storage are there such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cookies&lt;/strong&gt; — This is key-value pair Javascript object data. It is stored in the browser memory. It has a max size of 5 MB. It will used during communication between Client and Server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local Storage&lt;/strong&gt; — Local storage is a key-value Javascript object. It has a maximum size of 50MB. It will be used to store the user data, state, auth tokens, etc. The stored data is not cleared, unless the user deletes it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session Storage&lt;/strong&gt; — Session storage data is a key-value pair javascript object and function. The data remains stored until the browser session is active. Once the browser is closed the stored data will be deleted. It has a max size of 5 MB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IndexedDB&lt;/strong&gt; — Used for storing large amounts of structured data in the browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FileSystem&lt;/strong&gt; — Provides access to a sandboxed file system within the browser for reading, writing, and manipulating files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service Workers&lt;/strong&gt; — Service Workers are often used to implement offline caching strategies. It is used for intercepting and caching network requests, enabling offline functionality and performance optimizations in web applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Support ❤️
&lt;/h2&gt;

&lt;p&gt;It took a lot of time and effort to create this material. If you found this article useful or interesting, please support my work with a small donation. It will help me to continue sharing my knowledge and ideas.&lt;/p&gt;

&lt;p&gt;Make a contribution or Subscription to the author's content: &lt;a href="http://buymeacoffee.com/betelgeuseo" rel="noopener noreferrer"&gt;Buy me a Coffee&lt;/a&gt;, &lt;a href="https://patreon.com/betelgeuseo" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;, &lt;a href="https://www.paypal.com/donate/?hosted_button_id=327N24D6QDLVC" rel="noopener noreferrer"&gt;PayPal&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Storage Engines</title>
      <dc:creator>Andrew S.</dc:creator>
      <pubDate>Sat, 05 Jul 2025 18:10:45 +0000</pubDate>
      <link>https://dev.to/betelgeuseas/storage-engines-2loi</link>
      <guid>https://dev.to/betelgeuseas/storage-engines-2loi</guid>
      <description>&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;Choosing the right storage mechanisms for local device storage is crucial when designing your web app. A good storage engine makes sure your information is saved reliably, reduces bandwidth, and improves responsiveness. The right storage caching strategy is a core building block for enabling offline mobile web experiences, which is something more and more users feel should be the case by default.&lt;/p&gt;

&lt;p&gt;In this chapter, we'll discuss the available storage APIs and services and will offer some guidelines on how to make the right choice when building your web app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Model
&lt;/h3&gt;

&lt;p&gt;The data storing model determines how data is organized internally. This impacts the entire design of your web app, defines the tradeoffs to making your web app efficient yet solve the problem it should solve. There is no "better" approach and no one-size-fits-all solution as with almost everything related to engineering. So, let's take a look at the data models that you could choose from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Structured:&lt;/strong&gt; Data stored in tables with predefined fields, as is typical of SQL based database management systems, lends itself well to flexible and dynamic queries. A prominent example of a structured datastore in the browser is IndexedDB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key/Value:&lt;/strong&gt; Key/Value datastores, and related NoSQL databases, offer the ability to store and retrieve unstructured data indexed by a unique key. Key/Value datastores are like hash tables in the sense that they allow constant-time access to indexed, opaque data. Good examples of key/value datastores are the Cache API in the browser and Apache Cassandra on the server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Byte Streams:&lt;/strong&gt; This simple model stores data as a variable in length, opaque string of bytes, leaving any form of internal organization to the application layer. This model is particularly good for file systems and other hierarchically organized blobs of data. Prominent examples of byte stream datastores include file systems and cloud storage services.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Persistence
&lt;/h3&gt;

&lt;p&gt;Storage methods for web apps can be analyzed with respect to the timeframe over which data is made persistent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Session Persistence:&lt;/strong&gt; Data in this category is persisted only as long as a single web session or browser tab remains active. An example of a storage mechanism with session persistence is the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage" rel="noopener noreferrer"&gt;Session Storage API&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Device Persistence:&lt;/strong&gt; Data in this category is persisted across sessions and browser tabs/windows, on a particular device. An example of a storage mechanism with device persistence is the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage" rel="noopener noreferrer"&gt;Cache API&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global Persistence:&lt;/strong&gt; Data in this category is persisted across sessions and devices. Therefore, it is the most robust form of data persistence. It cannot be stored on the device itself, however, which means that you need some sort of server-side storage. We won't discuss it here in detail as this post is focused on storing data on the device itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Data persistence in the browser
&lt;/h3&gt;

&lt;p&gt;Nowadays, there are quite a few browser APIs that allow you to store data. We'll go through some of them and create a comparison to make it easier for you to choose the right option.&lt;/p&gt;

&lt;p&gt;First, however, there are a few things that you should consider before choosing how to persist your data. Of course, the first thing you have to understand very well is the way your web app is going to be used and later maintained and enhanced. Even if you have the answers to these questions, you may end up with a few options to choose from. So, here is what you should look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Browser Support&lt;/strong&gt; — you should take into account the fact that standardized and well established APIs are preferable, because they tend to be longer lived and more widely supported. Those APIs also enjoy a broader documentation and richer community of developers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transactions&lt;/strong&gt; — sometimes, it is important for a collection of related storage operations to succeed or fail atomically. Databases have traditionally supported this feature using a transaction model, where related updates may be grouped into arbitrary units.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sync/Async&lt;/strong&gt; — Some storage APIs are synchronous in the sense that storage or retrieval requests block the currently active thread until the request is completed. Using a synchronous storage API can block the main thread and create a freezing experience for the UI of your web app. If possible, use async APIs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Comparison
&lt;/h3&gt;

&lt;p&gt;In this section, we take a look at the current APIs available for web developers and compare them across the dimensions described above.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;API&lt;/th&gt;
&lt;th&gt;Data Model&lt;/th&gt;
&lt;th&gt;Persistence&lt;/th&gt;
&lt;th&gt;Browser Support&lt;/th&gt;
&lt;th&gt;Transactions&lt;/th&gt;
&lt;th&gt;Sync/Async&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;File System&lt;/td&gt;
&lt;td&gt;Byte Stream&lt;/td&gt;
&lt;td&gt;Device&lt;/td&gt;
&lt;td&gt;52%&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Async&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local Storage&lt;/td&gt;
&lt;td&gt;Key/Value&lt;/td&gt;
&lt;td&gt;Device&lt;/td&gt;
&lt;td&gt;93%&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Sync&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  File System API
&lt;/h3&gt;

&lt;p&gt;With the FileSystem API, a web app can create, read, navigate, and write to a sandboxed section of the user's local file system.&lt;/p&gt;

&lt;p&gt;The API is broken up into various themes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reading and manipulating files: &lt;code&gt;File/Blob&lt;/code&gt;, &lt;code&gt;FileList&lt;/code&gt;, &lt;code&gt;FileReader&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Creating and writing: &lt;code&gt;Blob()&lt;/code&gt;, &lt;code&gt;FileWriter&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Directories and file system access: &lt;code&gt;DirectoryReader&lt;/code&gt;, &lt;code&gt;FileEntry/DirectoryEntry&lt;/code&gt;, &lt;code&gt;LocalFileSystem&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The File system API is a non-standard API. You shouldn't use it in production web apps since it will not work for every user. There may be large incompatibilities between implementations, and the behavior will probably change in the future.&lt;/p&gt;

&lt;p&gt;The File and Directory Entries API interface &lt;strong&gt;FileSystem&lt;/strong&gt; is used to represent a file system. These objects can be obtained from the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/FileSystemEntry/filesystem" rel="noopener noreferrer"&gt;filesystem&lt;/a&gt; property on any file system entry. Some browsers offer additional APIs to create and manage file systems.&lt;/p&gt;

&lt;p&gt;This interface will not grant you access to the users' filesystem. Instead, you will have a "virtual drive" within the browser sandbox. If you want to gain access to the users' filesystem, you need to invoke the user by eg. installing a Chrome extension.&lt;/p&gt;

&lt;h4&gt;
  
  
  Requesting a file system
&lt;/h4&gt;

&lt;p&gt;A web app can request access to a sandboxed file system by calling &lt;code&gt;window.requestFileSystem()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Note: The file system has been prefixed as of Google Chrome 12:&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requestFileSystem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requestFileSystem&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webkitRequestFileSystem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestFileSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;successCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opt_errorCallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;if you're calling requestFileSystem() for the first time, new storage is created for your app. It's important to remember that this file system is sandboxed, meaning one web app cannot access another app's files.&lt;/p&gt;

&lt;p&gt;After you get access to the file system, you can do most of the standard operations on files and directories.&lt;/p&gt;

&lt;p&gt;The FileSystem is quite a different storage option compared to the others as it aims to satisfy client-side storage use cases not well served by databases. Generally, these are applications that deal with large binary blobs and/or share data with applications outside of the context of the browser.&lt;/p&gt;

&lt;p&gt;These are good use-cases for the FileSystem API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Persistent uploader — when a file or directory is selected for upload, it copies the files into a local sandbox and uploads a chunk at a time.&lt;/li&gt;
&lt;li&gt;Video game, music, or other apps with lots of media assets&lt;/li&gt;
&lt;li&gt;Audio/Photo editor with offline access or local cache for speed -the data blobs are potentially quite large and are read-write.&lt;/li&gt;
&lt;li&gt;Offline video viewer — it needs to download large files for later viewing or efficient seek + streaming&lt;/li&gt;
&lt;li&gt;Offline Web Mail Client — downloads attachments and stores them locally.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Local Storage
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;localStorage&lt;/code&gt; API allows you to access a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Storage" rel="noopener noreferrer"&gt;Storage&lt;/a&gt; object for the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document" rel="noopener noreferrer"&gt;Document&lt;/a&gt;'s origin. The stored data is saved across browser sessions. localStorage is similar to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage" rel="noopener noreferrer"&gt;sessionStorage&lt;/a&gt;, except that while data stored in localStorage has no expiration time, data stored in sessionStorage gets cleared when the page session ends — that is, when the page is closed.&lt;/p&gt;

&lt;p&gt;Note that data stored in either localStorage or sessionStorage is specific to the origin of the page, which is a combination of the protocol, host and the port.&lt;/p&gt;

&lt;h3&gt;
  
  
  Session Storage
&lt;/h3&gt;

&lt;p&gt;The sessionStorage property allows you to access a session &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Storage" rel="noopener noreferrer"&gt;Storage&lt;/a&gt; object for the current origin. sessionStorage is similar to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage" rel="noopener noreferrer"&gt;localStorage&lt;/a&gt;, briefly explained above. The only difference is that while data stored in localStorage has no expiration set, data stored in sessionStorage gets cleared when the page session ends. A page session lasts for as long as the browser is open and survives over page reloads and restores. Opening a page in a new tab or window will cause a new session to be initiated, which differs from how session cookies work.&lt;/p&gt;

&lt;p&gt;Note that data stored in either sessionStorage or localStorage is specific to the origin of the page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cookies
&lt;/h3&gt;

&lt;p&gt;A cookie (web cookie, browser cookie) is a small piece of data that the user' server sends to the user's web browser. The browser may store it and send it back with the next request to the same server. Typically, it's used to tell if two requests came from the same browser — keeping a user logged-in, for example. It remembers stateful information for the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Overview#http_is_stateless_but_not_sessionless" rel="noopener noreferrer"&gt;stateless&lt;/a&gt; HTTP protocol.&lt;/p&gt;

&lt;p&gt;Cookies have three main use-cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Session management&lt;/strong&gt; — Logins, shopping carts, game scores, or anything else the server should remember&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personalization&lt;/strong&gt; — User preferences, themes, and other settings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tracking&lt;/strong&gt; — Recording and analyzing user behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cookies were once used for general client-side storage. While this was legitimate when they were the only way to store data on the client, nowadays it is recommended to choose modern storage APIs. Cookies gets sent with every request, so they can deteriorate performance (especially when on a mobile data connection).&lt;/p&gt;

&lt;p&gt;There are two types of cookies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Session cookies&lt;/strong&gt; — They are deleted when the client shuts down. Web browsers may use &lt;strong&gt;session restoring&lt;/strong&gt;, which makes most session cookies permanent, as if the browser was never closed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permanent cookies&lt;/strong&gt; — Instead of expiring when the client closes, &lt;em&gt;permanent cookies&lt;/em&gt; expire at a specific date (Expires) or after a specific time period (Max-Age).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that confidential or sensitive information should never be stored or transmitted with HTTP Cookies, as the entire mechanism is inherently insecure.&lt;/p&gt;

&lt;p&gt;And, as you might have guessed, cookies are widely supported among all browsers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache
&lt;/h3&gt;

&lt;p&gt;The Cache interface provides a storage mechanism for &lt;a href="https://fetch.spec.whatwg.org/#request" rel="noopener noreferrer"&gt;Request&lt;/a&gt; / &lt;a href="https://fetch.spec.whatwg.org/#response" rel="noopener noreferrer"&gt;Response&lt;/a&gt; object pairs that are cached. Note that the Cache interface is exposed to windowed scopes as well as workers. You don't have to use it in conjunction with service workers, even though it is defined in the service worker spec.&lt;/p&gt;

&lt;p&gt;An origin can have multiple, named Cache objects. You are responsible for implementing how your script (e.g. in a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker" rel="noopener noreferrer"&gt;ServiceWorker&lt;/a&gt;) handles Cache updates. Items in a Cache do not get updated unless explicitly requested; they don't expire unless deleted. Use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage/open" rel="noopener noreferrer"&gt;CacheStorage.open()&lt;/a&gt; to open a specific, named Cache object and then call any of the Cache methods to maintain the Cache.&lt;/p&gt;

&lt;p&gt;You are also responsible for periodically purging cache entries. Each browser has a hard limit on the amount of cache storage that a given origin can use. Cache quota usage estimates are available via the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/StorageManager/estimate" rel="noopener noreferrer"&gt;StorageEstimate&lt;/a&gt; API. The browser does its best to manage disk space, but it may delete the Cache storage for an origin. The browser will generally either delete all the data for an origin or none of it. Make sure to version caches by name and use the caches only from the version of the script that they can safely operate on. See &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers#deleting_old_caches" rel="noopener noreferrer"&gt;Deleting old caches&lt;/a&gt; for more information.&lt;/p&gt;

&lt;p&gt;The CacheStorage interface represents the storage for &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Cache" rel="noopener noreferrer"&gt;Cache&lt;/a&gt; objects.&lt;/p&gt;

&lt;p&gt;The interface:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provides a master directory of all the named caches that can be accessed by a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker" rel="noopener noreferrer"&gt;ServiceWorker&lt;/a&gt; or other type of worker or &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window" rel="noopener noreferrer"&gt;window&lt;/a&gt; scope (you're not limited to only using it with service workers, even though the &lt;a href="https://w3c.github.io/ServiceWorker/" rel="noopener noreferrer"&gt;Service Workers&lt;/a&gt; spec defines it)&lt;/li&gt;
&lt;li&gt;Maintains a mapping of string names to corresponding &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Cache" rel="noopener noreferrer"&gt;Cache&lt;/a&gt; objects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage/open" rel="noopener noreferrer"&gt;CacheStorage.open()&lt;/a&gt; to obtain a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Cache" rel="noopener noreferrer"&gt;Cache&lt;/a&gt; instance.&lt;/p&gt;

&lt;p&gt;Use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage/match" rel="noopener noreferrer"&gt;CacheStorage.match()&lt;/a&gt; to check if a given Request is a key in any of the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Cache" rel="noopener noreferrer"&gt;Cache&lt;/a&gt; objects that the CacheStorage object tracks.&lt;/p&gt;

&lt;p&gt;You can access CacheStorage through the global &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/caches" rel="noopener noreferrer"&gt;caches&lt;/a&gt; property.&lt;/p&gt;

&lt;h3&gt;
  
  
  IndexedDB
&lt;/h3&gt;

&lt;p&gt;IndexedDB is a way for you to persistently store data inside a user's browser. Because it lets you create web applications with rich query abilities regardless of network availability, these applications can work both online and offline. IndexedDB is useful for applications that store a large amount of data (for example, a catalog of DVDs in a lending library) and applications that don't need persistent internet connectivity to work (for example, mail clients, to-do lists, and notepads).&lt;/p&gt;

&lt;p&gt;In this article, it's the storage DB which we're going to discuss in a bit more detail because the rest of the storage APIs are quite well-known. Plus, IndexedDB is getting more and more popular with the increased complexity of web apps nowadays.&lt;/p&gt;

&lt;h4&gt;
  
  
  The internals of IndexedDB
&lt;/h4&gt;

&lt;p&gt;IndexedDB lets you store and retrieve objects that are stored with a "key." All changes that you make to the database happen within transactions. Like most web storage solutions, IndexedDB follows a &lt;a href="https://www.w3.org/Security/wiki/Same_Origin_Policy" rel="noopener noreferrer"&gt;same-origin policy&lt;/a&gt;. So while you can access stored data within a domain, you cannot access data across different domains.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/IndexedDB" rel="noopener noreferrer"&gt;IndexedDB&lt;/a&gt; is an asynchronous API that can be used in most contexts, including &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers" rel="noopener noreferrer"&gt;WebWorkers&lt;/a&gt;. It used to include a synchronous version too, for use in web workers, but this was removed from the spec due to lack of interest by the web community.&lt;/p&gt;

&lt;p&gt;IndexedDB used to have a competing spec called WebSQL Database, but it was deprecated by the W3C. While both IndexedDB and WebSQL are solutions for storage, they do not offer the same functionalities. WebSQL Database is a relational database access system, whereas IndexedDB is an indexed table system.&lt;/p&gt;

&lt;p&gt;Don't start working with IndexedDB, relying on your assumptions from other types of databases. Instead, you should read the docs carefully. Here are some of the essential concepts that you should have in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IndexedDB databases store key-value pairs&lt;/strong&gt; — the values can be complex structured objects, and keys can be properties of those objects. You can create indexes that use any property of the objects for quick searching, as well as for a sorted enumeration. Keys can also be binary objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IndexedDB is built on a transactional database model&lt;/strong&gt; — everything you do in IndexedDB always happens in the context of a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Basic_Terminology#gloss_transaction" rel="noopener noreferrer"&gt;transaction&lt;/a&gt;. Thus, you cannot execute commands or open cursors outside a transaction. Also, transactions auto-commit and cannot be committed manually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The IndexedDB API is mostly asynchronous&lt;/strong&gt; — the API doesn't give you data by returning values. Instead, you have to pass a callback function. You don't "store" a value into the database, or "retrieve" a value from the database through synchronous means. Instead, you "request" that a database operation happens. An event notifies you when the operation completes, and the type of event you get informs you if the operation succeeded or failed. It's not that different from the way that &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest" rel="noopener noreferrer"&gt;XMLHttpRequest&lt;/a&gt; (or tons of other JavaScript stuff) works.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IndexedDB uses a lot of requests&lt;/strong&gt; — requests are objects that receive the success or failure events that were mentioned previously. They have onsuccess and onerror properties, as well as readyState, result, and errorCode properties that tell you the status of the request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IndexedDB is object-oriented&lt;/strong&gt; — IndexedDB is not a relational database with tables representing collections of rows and columns. This fundamental difference affects the way you design and build your applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IndexedDB does not use Structured Query Language (SQL)&lt;/strong&gt; — it uses queries on an index that produces a cursor, which you use to iterate across the result set. If you are not familiar with NoSQL systems, read the &lt;a href="https://en.wikipedia.org/wiki/NoSQL" rel="noopener noreferrer"&gt;Wikipedia article on NoSQL&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The same-origin policy applies to IndexedDB&lt;/strong&gt; — an origin is the domain, the application layer protocol, and the port of a URL of the document where the script is being executed. Each origin has its own associated set of databases. Every database has a name that identifies it within an origin.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  IndexedDB limitations
&lt;/h4&gt;

&lt;p&gt;IndexedDB is designed to cover most cases that need client-side storage. It has not been designed, however, for a few cases such as the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Internationalized sorting&lt;/strong&gt; — not all languages sort strings the same way, therefore internationalized sorting is not supported. While the database can't store data in a specific internationalized order, you can sort the data that you've read out of the database yourself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synchronization&lt;/strong&gt; — the API is not designed to take care of synchronizing with a server-side database. You have to write code that synchronizes a client-side indexedDB database with a server-side database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full text searching&lt;/strong&gt; — the API does not have an equivalent of the LIKE operator in SQL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition, be aware that browsers can wipe out the database in the following conditions (ouch):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The user requests a wipeout&lt;/strong&gt; — Many browsers have settings that let users wipe all data stored for a given website, including cookies, bookmarks, stored passwords, and IndexedDB data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The browser is in private browsing mode&lt;/strong&gt; — Some browsers have "private browsing" (Firefox) or "incognito" (Chrome) modes. At the end of the session, the browser wipes out the database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The disk or quota limit has been reached&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The data is corrupt&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The exact circumstances and browser capabilities change over time, but the general philosophy of the browser vendors is to make the best effort to keep the data when possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing the right storage API
&lt;/h3&gt;

&lt;p&gt;As I mentioned already, it's better to choose APIs that are widely supported across as many browsers as possible and which offer asynchronous call models, to maximize UI responsiveness. These criteria lead naturally to the following technology choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For offline storage, use the &lt;a href="https://web.dev/articles/cache-api-quick-guide" rel="noopener noreferrer"&gt;Cache API&lt;/a&gt;. This API is available in any browser that supports &lt;a href="https://jakearchibald.github.io/isserviceworkerready/" rel="noopener noreferrer"&gt;Service Worker technology&lt;/a&gt; necessary for creating offline apps. The Cache API is ideal for storing resources associated with a known URL.&lt;/li&gt;
&lt;li&gt;For storing application state and user-generated content, use IndexedDB. This enables users to work offline in more browsers than just those that support the Cache API.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Support ❤️
&lt;/h2&gt;

&lt;p&gt;It took a lot of time and effort to create this material. If you found this article useful or interesting, please support my work with a small donation. It will help me to continue sharing my knowledge and ideas.&lt;/p&gt;

&lt;p&gt;Make a contribution or Subscription to the author's content: &lt;a href="http://buymeacoffee.com/betelgeuseo" rel="noopener noreferrer"&gt;Buy me a Coffee&lt;/a&gt;, &lt;a href="https://patreon.com/betelgeuseo" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;, &lt;a href="https://www.paypal.com/donate/?hosted_button_id=327N24D6QDLVC" rel="noopener noreferrer"&gt;PayPal&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>The Internals of Shadow DOM</title>
      <dc:creator>Andrew S.</dc:creator>
      <pubDate>Sat, 05 Jul 2025 18:06:21 +0000</pubDate>
      <link>https://dev.to/betelgeuseas/the-internals-of-shadow-dom-i9k</link>
      <guid>https://dev.to/betelgeuseas/the-internals-of-shadow-dom-i9k</guid>
      <description>&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;Web Components is a suite of different technologies that allows you to create reusable custom elements.Their functionality is encapsulated away from the rest of your code, and you can utilize them in your web apps.&lt;/p&gt;

&lt;p&gt;There are 4 Web Component standards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shadow DOM&lt;/li&gt;
&lt;li&gt;HTML Templates&lt;/li&gt;
&lt;li&gt;Custom elements&lt;/li&gt;
&lt;li&gt;HTML Imports&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, we'll focus on the &lt;strong&gt;Shadow DOM&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Shadow DOM is designed as a tool for building component-based apps. It offers solutions to common problems in web development you've probably experienced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Isolated DOM:&lt;/strong&gt; A component's DOM is self-contained (e.g. &lt;code&gt;document.querySelector()&lt;/code&gt; won't return nodes in the component's shadow DOM). This also simplifies the CSS selectors across your web app since DOM components are isolated, and it gives you the ability to use more generic id/class names without worrying about naming conflicts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scoped CSS:&lt;/strong&gt; CSS defined inside shadow DOM is scoped to it. Style rules don't leak out and page styles don't interfere with it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composition:&lt;/strong&gt; Design a declarative, markup-based API for your component.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Shadow DOM
&lt;/h3&gt;

&lt;p&gt;This article assumes that you're already familiar with the concept of the DOM and its APIs. If not, you can read a detailed article about it here — &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Shadow DOM is just a normal DOM except for two differences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How it's created/used in relation to the rest of the page compared to the wah you create and use DOM.&lt;/li&gt;
&lt;li&gt;How it behaves in relation to the rest of the page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In general, you create DOM nodes and append them as children to another element. In the case of shadow DOM, you create a scoped DOM tree that's attached to the element yet it's separate from its actual children. This scoped subtree is called a &lt;strong&gt;shadow tree&lt;/strong&gt;. The element it's attached to is its &lt;strong&gt;shadow host&lt;/strong&gt;. Anything you add to the shadow tree becomes local to the hosting element, including &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt;. This is how shadow DOM achieves CSS style scoping.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Shadow DOM
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;shadow root&lt;/strong&gt; is a document fragment that gets attached to a "host" element. The moment you attach a shadow root is when the element gains its shadow DOM. To create shadow DOM for an element, call &lt;code&gt;element.attachShadow()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;shadowRoot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;paragraphElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;paragraphElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Shadow DOM&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paragraphElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The specification defines a list of elements that can't host a shadow tree.&lt;/p&gt;

&lt;h3&gt;
  
  
  Composition in Shadow DOM
&lt;/h3&gt;

&lt;p&gt;Composition is one the most important features of Shadow DOM.&lt;/p&gt;

&lt;p&gt;When writing HTML, composition is the way you construct your web app. You combine and nest different building blocks (elements) such as &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; and others in order to build the UI you need for your web app. Some of these tags even work with each other.&lt;/p&gt;

&lt;p&gt;Composition defines why elements such as &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; and others are flexible and accept specific HTML elements as children in order to do something special with them.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; knows how to render &lt;code&gt;&amp;lt;option&amp;gt;&lt;/code&gt; elements into a dropdown widget with pre-defined items.&lt;/p&gt;

&lt;p&gt;Shadow DOM introduces the following features which can be used to achieve composition.&lt;/p&gt;

&lt;h3&gt;
  
  
  Light DOM
&lt;/h3&gt;

&lt;p&gt;This is the markup a user of your component writes. This DOM lives outside the component's shadow DOM. It is the element's actual children. Imagine that you've created a custom component called &lt;code&gt;&amp;lt;better-button&amp;gt;&lt;/code&gt; which extends the native HTML button and you want to add an image and some text inside it. This is how it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;extended-button&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- The image and span are extended-button's light DOM --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"boot.png"&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"image"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;Launch&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/extended-button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "extended-button" is the custom component that you have defined, while the HTML inside it is called Light DOM and is added by the user of your component.&lt;/p&gt;

&lt;p&gt;The Shadow DOM here is the component you have created ("extended-button"). Shadow DOM is local to the component and defines its internal structure, scoped CSS, and encapsulates your implementation details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flattened DOM tree
&lt;/h3&gt;

&lt;p&gt;The result of the browser distributing the light DOM, that's been created by the user into your shadow DOM and which has defined your custom component, renders the final product. The flattened tree is what you ultimately see in the DevTools and what's rendered on the page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;extended-button&amp;gt;&lt;/span&gt;
  #shadow-root
  &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"image"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"boot.png"&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"image"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;slot&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;Launch&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/extended-button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Templates
&lt;/h3&gt;

&lt;p&gt;When you have to repeatedly reuse the same markup structures on a web page, it's better to use some kind of a template rather than repeat the same structure over and over again. This was possible before, but it is made a lot easier by the HTML  element (which is well-supported in modern browsers). This element and its contents are not rendered in the DOM but it can still be referenced using JavaScript.&lt;/p&gt;

&lt;p&gt;Let's look at a quick trivial example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"my-paragraph"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt; Paragraph content. &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This won't appear in your page until you reference it with JavaScript, and then append it to the DOM using something like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-paragraph&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;templateContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;templateContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Templates are useful on their own but they work even better with custom elements. We'll define custom elements in another post of the series, for the time being you should know that the &lt;code&gt;customElement&lt;/code&gt; API in the browser allows you to define your own tags with custom rendering.&lt;/p&gt;

&lt;p&gt;Let's define a web component that uses our template as the content of its shadow DOM. We'll call it &lt;code&gt;&amp;lt;my-paragraph&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-paragraph&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-paragraph&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;templateContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shadowRoot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;templateContent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cloneNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key point to note here is that we appended a clone of the template content to the shadow root, that's been created using the &lt;code&gt;Node.cloneNode()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;And because we are appending its contents to a shadow DOM, we can include some styling information inside the template in a &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; element, which is then encapsulated inside the custom element. This wouldn't work if we just appended it to the standard DOM.&lt;/p&gt;

&lt;p&gt;For example, we can change our template to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"my-paragraph"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Paragraph content. &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the custom component we have defined with our template can be used like this: &lt;code&gt;&amp;lt;my-paragraph&amp;gt;&amp;lt;/my-paragraph&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Slots
&lt;/h3&gt;

&lt;p&gt;Templates have a few downsides, the main one being the static content which doesn't allow us to render our variables/data in order to make it work the way standard HTML templates you're used to do.&lt;/p&gt;

&lt;p&gt;This is where the &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; comes into the picture.&lt;/p&gt;

&lt;p&gt;You can think of slots as placeholders that allow you to put your own HTML in the template. This allows you to create generic HTML templates and then make them customizable by adding slots.&lt;/p&gt;

&lt;p&gt;Let's see how the above template will look like with a slot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"my-paragraph"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"my-text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Default text&lt;span class="nt"&gt;&amp;lt;/slot&amp;gt;&lt;/span&gt; 
  &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the slot's content isn't defined when the element is included in the markup, or if the browser doesn't support slots, &lt;code&gt;&amp;lt;my-paragraph&amp;gt;&lt;/code&gt; will just contain the fallback content "Default text".&lt;/p&gt;

&lt;p&gt;To define the slot's content, we should include an HTML structure inside the &lt;code&gt;&amp;lt;my-paragraph&amp;gt;&lt;/code&gt; element with a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#attr-slot" rel="noopener noreferrer"&gt;slot&lt;/a&gt; attribute whose value is equal to the name of the slot we want it to fill.&lt;/p&gt;

&lt;p&gt;As before, this can be anything you like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-paragraph&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"my-text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Let's have some different text!&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/my-paragraph&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Elements that can be inserted into slots are known as &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element" rel="noopener noreferrer"&gt;Slotable&lt;/a&gt;; when an element has been inserted into a slot, it is said to be &lt;em&gt;slotted&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Note that in the above example we have inserted a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; element which is the slotted element. It has an attribute &lt;code&gt;slot&lt;/code&gt; that's equal to "my-text" which is the same as the value of the &lt;code&gt;name&lt;/code&gt; attribute in the template's slot definition.&lt;/p&gt;

&lt;p&gt;After being rendered in the browser, the above code will create the following Flattened DOM tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-paragraph&amp;gt;&lt;/span&gt;
  #shadow-root
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"my-text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"my-text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Let's have some different text!&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/my-paragraph&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the &lt;code&gt;#shadow-root&lt;/code&gt; element — it's just an indicator that Shadow DOM exists.&lt;/p&gt;

&lt;h3&gt;
  
  
  Styling
&lt;/h3&gt;

&lt;p&gt;A component that uses shadow DOM can be styled by the main page, can define its own styles, or provide hooks in the form of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_cascading_variables/Using_CSS_custom_properties" rel="noopener noreferrer"&gt;CSS custom properties&lt;/a&gt; for users to override defaults.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component-defined styles
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Scoped CSS&lt;/strong&gt; is one of the greatest features of Shadow DOM:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSS selectors from the outer page don't apply inside your component.&lt;/li&gt;
&lt;li&gt;Styles defined inside your component don't impact the rest of the page. They're scoped to the host element.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CSS selectors used inside Shadow DOM apply locally to the component. In practice, this means we can use common id/class names again, without worrying about conflicts elsewhere on the page. Simple CSS selectors mean better performance.&lt;/p&gt;

&lt;p&gt;Let's take a look at the following #shadow-root that defines some styles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;#shadow-root
&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;#container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;#container-items&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"container-items"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the styles in the above example are local for the #shadow-root.&lt;/p&gt;

&lt;p&gt;You can also use the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; element to include stylesheets in the #shadow-root which are also local.&lt;/p&gt;

&lt;h3&gt;
  
  
  The :host pseudo-class
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;:host&lt;/code&gt; allows you to select and style the element hosting a shadow tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nd"&gt;:host&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* by default, custom elements are display: inline */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's one thing you should be careful with when it comes to &lt;code&gt;:host&lt;/code&gt; — rules in the parent page have higher priority than &lt;code&gt;:host&lt;/code&gt; rules defined in the element. This allows users to override your top-level styling from the outside. Also, &lt;code&gt;:host&lt;/code&gt; only works in the context of a shadow root, so you can't use it outside of a Shadow DOM.&lt;/p&gt;

&lt;p&gt;The functional form of &lt;code&gt;:host(&amp;lt;selector&amp;gt;)&lt;/code&gt; allows you to target the host if it matches a &lt;code&gt;&amp;lt;selector&amp;gt;&lt;/code&gt;. This is a great way for your component to encapsulate behavior that reacts to user interaction or state, and style internal nodes based on the host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nd"&gt;:host&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;:host&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;:host&lt;/span&gt;&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="nt"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;/* style when host has disabled attribute. */&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;pointer-events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;:host&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.pink&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;#tabs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;pink&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* color internal #tabs node when host has class="pink". */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Theming and element with the :host-context() pseudo-class
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;:host-context(&amp;lt;selector&amp;gt;)&lt;/code&gt; pseudo class matches the host element if the latter or any of its ancestors matches &lt;code&gt;&amp;lt;selector&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A common use for this is theming. For example, many people do theming by applying a class to &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"lightheme"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;custom-container&amp;gt;&lt;/span&gt;
  …
  &lt;span class="nt"&gt;&amp;lt;/custom-container&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;:host-context(.lightheme)&lt;/code&gt; would style &lt;code&gt;&amp;lt;fancy-tabs&amp;gt;&lt;/code&gt; when it's a descendant of &lt;code&gt;.lightheme&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:host-context&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.lightheme&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;:host-context()&lt;/code&gt; can be useful for theming but an even better approach is to &lt;a href="https://web.dev/articles/shadowdom-v1#stylehooks" rel="noopener noreferrer"&gt;create style hooks using CSS custom properties&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Styling the host element of a component from the outside
&lt;/h3&gt;

&lt;p&gt;You can style the host element of components from the outside by just using their tag name as selector like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;custom-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Outside styles have higher priority than styles defined in Shadow DOM.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, if the user writes the selector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;custom-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;500px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;, it will overwrite the component's rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:host&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Styling the component itself will only get you so far. But what happens if you want to style the internals of a component? For that, we need CSS custom properties.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating style hooks using CSS custom properties
&lt;/h3&gt;

&lt;p&gt;Users can tweak internal styles if the component's author provides styling hooks using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_cascading_variables/Using_CSS_custom_properties" rel="noopener noreferrer"&gt;CSS custom properties&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The idea is similar to &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; but applied to styles.&lt;/p&gt;

&lt;p&gt;Let's take a look at the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- main page --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;custom-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="err"&gt;-&lt;/span&gt; &lt;span class="py"&gt;custom-container-bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;custom-container&lt;/span&gt; &lt;span class="na"&gt;background&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;…&lt;span class="nt"&gt;&amp;lt;/custom-container&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside its Shadow DOM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:host&lt;/span&gt;&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="nt"&gt;background&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;-&lt;/span&gt; &lt;span class="n"&gt;custom-container-bg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;#CECECE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the component will use black as the background value since the user provided it. Otherwise, it would default to &lt;code&gt;#CECECE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As the component author, you're responsible for letting developers know about CSS custom properties they can use. Consider it part of your component's public interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  Slots JavaScript API
&lt;/h3&gt;

&lt;p&gt;The Shadow DOM API provides utilities for working with slots.&lt;/p&gt;

&lt;h3&gt;
  
  
  The slotchange event
&lt;/h3&gt;

&lt;p&gt;The slotchange event fires when a slot's distributed nodes change. For example, if the user adds/removes children from the light DOM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;slot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#some_slot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slotchange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Light DOM change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To monitor other types of changes to the light DOM, you can use a &lt;code&gt;MutationObserver&lt;/code&gt; in your element's constructor.&lt;/p&gt;

&lt;h3&gt;
  
  
  The assignedNodes() method
&lt;/h3&gt;

&lt;p&gt;It could be useful to know what elements are associated with a slot. Calling &lt;code&gt;slot.assignedNodes()&lt;/code&gt;, gives you which elements the slot is rendering. The &lt;code&gt;{flatten: true}&lt;/code&gt; option will also return a slot's fallback content (if no nodes are being distributed).&lt;/p&gt;

&lt;p&gt;Let's look at the following example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;slot name='slot1'&amp;gt;&amp;lt;p&amp;gt;Default content&amp;lt;/p&amp;gt;&amp;lt;/slot&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let's assume that this is in a component called &lt;code&gt;&amp;lt;my-container&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's take a look at the different usages of this component and what will be the result of calling &lt;code&gt;assignedNodes()&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;In the first case, we'll add our own content to the slot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-container&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"slot1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; container text &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/my-container&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling &lt;code&gt;assignedNodes()&lt;/code&gt; will result in &lt;code&gt;[&amp;lt;span slot="slot1"&amp;gt; container text &amp;lt;/span&amp;gt;]&lt;/code&gt;. Note that the result is an array of nodes.&lt;/p&gt;

&lt;p&gt;In the second case, we'll leave the content empty:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;my-container&amp;gt; &amp;lt;/my-container&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The result of calling &lt;code&gt;assignedNodes()&lt;/code&gt; will return an empty array &lt;code&gt;[]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you, however, pass the &lt;code&gt;{flatten: true}&lt;/code&gt; parameter for the same element, you will get the default content as a result: &lt;code&gt;[&amp;lt;p&amp;gt;Default content&amp;lt;/p&amp;gt;]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also, to reach an element inside a slot, you can call &lt;code&gt;assignedNodes()&lt;/code&gt; to see which of the component slots your element is assigned to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Event Model
&lt;/h3&gt;

&lt;p&gt;It's interesting to note what happens when an event that takes place within the Shadow DOM bubbles up.&lt;/p&gt;

&lt;p&gt;The target of the event is adjusted to maintain the encapsulation that is provided by the Shadow DOM. When an event is re-targeted, it looks like it's coming from the component itself, rather than the internal element in the Shadow DOM that is part of the component.&lt;/p&gt;

&lt;p&gt;Here is a list of events that propagate out of the Shadow DOM(there are some that don't):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Focus Events:&lt;/strong&gt; blur, focus, focusin, focusout&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mouse Events:&lt;/strong&gt; click, dblclick, mousedown, mouseenter, mousemove, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wheel Events:&lt;/strong&gt; wheel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input Events:&lt;/strong&gt; beforeinput, input&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keyboard Events:&lt;/strong&gt; keydown, keyup&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composition Events:&lt;/strong&gt; compositionstart, compositionupdate, compositionend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DragEvent:&lt;/strong&gt; dragstart, drag, dragend, drop, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Custom Events
&lt;/h3&gt;

&lt;p&gt;Custom events don't propagate outside of the Shadow DOM by default. If you want to dispatch a custom event and want it to propagate, you need to add &lt;code&gt;bubbles: true&lt;/code&gt; and &lt;code&gt;composed: true&lt;/code&gt; as an option.&lt;/p&gt;

&lt;p&gt;Let's see how dispatching such an event might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;containerchanged&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;bubbles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;composed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Browser support
&lt;/h3&gt;

&lt;p&gt;To detect whether Shadow DOM is a supported feature, check for the existence of attachShadow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supportsShadowDOMV1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Support ❤️
&lt;/h2&gt;

&lt;p&gt;It took a lot of time and effort to create this material. If you found this article useful or interesting, please support my work with a small donation. It will help me to continue sharing my knowledge and ideas.&lt;/p&gt;

&lt;p&gt;Make a contribution or Subscription to the author's content: &lt;a href="http://buymeacoffee.com/betelgeuseo" rel="noopener noreferrer"&gt;Buy me a Coffee&lt;/a&gt;, &lt;a href="https://patreon.com/betelgeuseo" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;, &lt;a href="https://www.paypal.com/donate/?hosted_button_id=327N24D6QDLVC" rel="noopener noreferrer"&gt;PayPal&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>WebSockets and HTTP/2 with SSE</title>
      <dc:creator>Andrew S.</dc:creator>
      <pubDate>Sat, 05 Jul 2025 17:59:51 +0000</pubDate>
      <link>https://dev.to/betelgeuseas/websockets-and-http2-with-sse-4hkl</link>
      <guid>https://dev.to/betelgeuseas/websockets-and-http2-with-sse-4hkl</guid>
      <description>&lt;h3&gt;
  
  
  Intro
&lt;/h3&gt;

&lt;p&gt;Nowadays complex web apps that feature rich, dynamic UIs are taken for granted. And it's not surprising — the internet has come a long way since its inception.&lt;/p&gt;

&lt;p&gt;Initially, the internet wasn't built to support such dynamic and complex web apps. It was conceived to be a collection of HTML pages, linking to one another to form the concept of "web" that contains information. Everything was largely built around the so-called request/response paradigm of HTTP. A client loads up a page and then nothing happens until the user clicks and navigates to the next page.&lt;/p&gt;

&lt;p&gt;Around 2005, AJAX was introduced and a lot of people started to explore the possibilities of making connections between a client and а server bidirectional. Still, all HTTP communication was steered by the client, which required user interaction or periodic polling to load new data from the server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making HTTP "bidirectional"
&lt;/h3&gt;

&lt;p&gt;Technologies that enable the server to send data to the client "proactively" have been around for quite some time. "&lt;a href="https://en.wikipedia.org/wiki/Push_technology" rel="noopener noreferrer"&gt;Push&lt;/a&gt;" and "&lt;a href="https://en.wikipedia.org/wiki/Comet_(programming)" rel="noopener noreferrer"&gt;Comet&lt;/a&gt;" to name a few.&lt;/p&gt;

&lt;p&gt;One of the most common hacks to create the illusion that the server is sending data to the client is called &lt;strong&gt;long polling&lt;/strong&gt;. With long polling, the client opens an HTTP connection to the server which keeps it open until a response is sent. Whenever the server has new data that has to be sent, it transmits it as a response.&lt;/p&gt;

&lt;p&gt;Let's see how a very simple long polling snippet might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ajax&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com/endpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Do something with `data`&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;

        &lt;span class="c1"&gt;// Setup the next poll recursively&lt;/span&gt;
        &lt;span class="nf"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;dataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is basically a self-executing function that runs the first time automatically. It sets up the ten (10) second interval and after each async Ajax call to the server, the callback calls &lt;code&gt;ajax&lt;/code&gt; again.&lt;/p&gt;

&lt;p&gt;Other techniques involve &lt;a href="https://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/Socket.html" rel="noopener noreferrer"&gt;Flash&lt;/a&gt; or XHR multipart request and the so-called &lt;a href="http://cometdaily.com/2007/12/27/a-standards-based-approach-to-comet-communication-with-rest/" rel="noopener noreferrer"&gt;htmlfiles&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All these workarounds share the same problem though: they carry the overhead of HTTP, which doesn't make them well-suited for low-latency applications. Think multiplayer first-person shooter games in the browser or any other online game with a realtime component.&lt;/p&gt;

&lt;h3&gt;
  
  
  The introduction of WebSockets
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" rel="noopener noreferrer"&gt;WebSocket&lt;/a&gt; specification defines an API establishing "socket" connections between a web browser and a server. In plain words: there is a persistent connection between the client and the server and both parties can start sending data at any time.&lt;/p&gt;

&lt;p&gt;The client establishes a WebSocket connection through a process known as the WebSocket handshake. This process starts with the client sending a regular HTTP request to the server. An &lt;code&gt;Upgrade&lt;/code&gt; header is included in this request which informs the server that the client wishes to establish a WebSocket connection.&lt;/p&gt;

&lt;p&gt;Let's see how opening a WebSocket connection looks like on the client side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create a new WebSocket with an encrypted connection.&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws://websocket.example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;WebSocket URLs use the &lt;code&gt;ws&lt;/code&gt; scheme. There is also &lt;code&gt;wss&lt;/code&gt; for secure WebSocket connections which is the equivalent of &lt;code&gt;HTTPS&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This scheme just starts the process of opening a WebSocket connection towards &lt;em&gt;websocket.example.com&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here is a simplified example of the initial request headers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET ws://websocket.example.com/ HTTP/1.1
Origin: http://example.com
Connection: Upgrade
Host: websocket.example.com
Upgrade: websocket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the server supports the WebSocket protocol, it will agree to the upgrade and will communicate this through the &lt;code&gt;Upgrade&lt;/code&gt; header in the response.&lt;/p&gt;

&lt;p&gt;Let's see how this can be implemented in Node.JS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// We'll be using the https://github.com/theturtle32/WebSocket-Node&lt;/span&gt;
&lt;span class="c1"&gt;// WebSocket implementation&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;WebSocketServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;websocket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// process HTTP request. &lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1337&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// create the server&lt;/span&gt;
&lt;span class="nx"&gt;wsServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocketServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;httpServer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// WebSocket server&lt;/span&gt;
&lt;span class="nx"&gt;wsServer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;request&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// This is the most important callback for us, we'll handle&lt;/span&gt;
  &lt;span class="c1"&gt;// all messages from users here.&lt;/span&gt;
  &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Process WebSocket message&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Connection closes&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the connection is established, the server replies by upgrading:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 101 Switching Protocols
Date: Wed, 25 Oct 2017 10:07:34 GMT
Connection: Upgrade
Upgrade: WebSocket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the connection has been established, the &lt;code&gt;open&lt;/code&gt; event will be fired on your WebSocket instance on the client side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws://websocket.example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Show a connected message when the WebSocket is opened.&lt;/span&gt;
&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onopen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WebSocket is connected.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that the handshake is complete the initial HTTP connection is replaced by a WebSocket connection that uses the same underlying TCP/IP connection. At this point, either party can start sending data.&lt;/p&gt;

&lt;p&gt;With WebSockets, you can transfer as much data as you like without incurring the overhead associated with traditional HTTP requests. Data is transferred through a WebSocket as messages, each of which consists of one or more &lt;em&gt;frames&lt;/em&gt; containing the data you are sending (the payload). In order to ensure the message can be properly reconstructed when it reaches the client each frame is prefixed with 4–12 bytes of data about the payload. Using this frame-based messaging system helps to reduce the amount of non-payload data that is transferred, leading to significant reductions in latency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; It's worth noting that the client will only be notified about a new message once all of the frames have been received and the original message payload has been reconstructed.&lt;/p&gt;

&lt;h3&gt;
  
  
  WebSocket URLs
&lt;/h3&gt;

&lt;p&gt;We briefly mentioned before that WebSockets introduce a new URL scheme. In reality, they introduce two new schemes: &lt;code&gt;ws://&lt;/code&gt; and &lt;code&gt;wss://&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;URLs have scheme-specific grammar. WebSocket URLs are special in that that they do not support anchors ( &lt;code&gt;#sample_anchor&lt;/code&gt; ).&lt;/p&gt;

&lt;p&gt;The same rules apply to WebSocket style URLs as to HTTP style URLs. &lt;code&gt;ws&lt;/code&gt; is unencrypted and has port 80 as default, while &lt;code&gt;wss&lt;/code&gt; requires TLS encryption and has port 443 as default.&lt;/p&gt;

&lt;h3&gt;
  
  
  Framing protocol
&lt;/h3&gt;

&lt;p&gt;Let's take a deeper look at the framing protocol. This is what the RFC provides us with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-------+-+-------------+-------------------------------+
     |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
     |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
     |N|V|V|V|       |S|             |   (if payload len==126/127)   |
     | |1|2|3|       |K|             |                               |
     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
     |     Extended payload length continued, if payload len == 127  |
     + - - - - - - - - - - - - - - - +-------------------------------+
     |                               |Masking-key, if MASK set to 1  |
     +-------------------------------+-------------------------------+
     | Masking-key (continued)       |          Payload Data         |
     +-------------------------------- - - - - - - - - - - - - - - - +
     :                     Payload Data continued ...                :
     + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
     |                     Payload Data continued ...                |
     +---------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As of the WebSocket version specified by the RFC, there's only a header in front of each packet. It's quite a complex header, however. Here are its building blocks explained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;fin&lt;/code&gt; (&lt;em&gt;1 bit&lt;/em&gt;): indicates if this frame is the final frame that makes up the message. Most of the time the message fits into a single frame and this bit will always be set. Experiments show that Firefox makes a second frame after 32K.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rsv1&lt;/code&gt;, &lt;code&gt;rsv2&lt;/code&gt;, &lt;code&gt;rsv3&lt;/code&gt; (&lt;em&gt;1 bit each&lt;/em&gt;): must be 0 unless an extension is negotiated that defines meanings for non-zero values. If a nonzero value is received and none of the negotiated extensions defines the meaning of such a nonzero value, the receiving endpoint must fail the connection.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;opcode&lt;/code&gt; (&lt;em&gt;4 bits&lt;/em&gt;): says what the frame represents. The following values are currently in use: &lt;code&gt;0x00&lt;/code&gt;: this frame continues the payload from the previous. &lt;code&gt;0x01&lt;/code&gt;: this frame includes text data. &lt;code&gt;0x02&lt;/code&gt;: this frame includes binary data. &lt;code&gt;0x08&lt;/code&gt;: this frame terminates the connection. &lt;code&gt;0x09&lt;/code&gt;: this frame is a ping. &lt;code&gt;0x0a&lt;/code&gt;: this frame is a pong. (As you can see, there are enough values unused; they've been reserved for future use).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mask&lt;/code&gt; (&lt;em&gt;1 bit&lt;/em&gt;): indicates if the connection is masked. As it stands right now, every message from a client to a server must be masked and the spec would want to terminate the connection if it's unmasked.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;payload_len&lt;/code&gt; (&lt;em&gt;7 bits&lt;/em&gt;): the length of the payload. WebSocket frames come in the following length brackets: 0–125 indicates the length of the payload. 126 means that the following two bytes indicate the length, 127 means the next 8 bytes indicate the length. So the length of the payload comes in ~7bit, 16bit, and 64bit brackets.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;masking-key&lt;/code&gt; (&lt;em&gt;32 bits&lt;/em&gt;): all frames sent from the client to the server are masked by a 32-bit value that is contained within the frame.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;payload&lt;/code&gt;: the actual data which most likely is masked. Its length is the length of the &lt;code&gt;payload_len&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why are WebSockets frame-based and not stream-based? I don't know and just like you, I'd love to learn more, so if you have an idea, feel free to add comments and resources in the responses below. Also, a good &lt;a href="https://news.ycombinator.com/item?id=3377406" rel="noopener noreferrer"&gt;discussion on the topic is available on HackerNews&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data on the frames
&lt;/h3&gt;

&lt;p&gt;As mentioned above, the data can be fragmented into multiple frames. The first frame that transmits the data has an opcode on it that indicates what sort of data is being transmitted. This is necessary because JavaScript has pretty much nonexistent support for binary data at the time the specification was started. &lt;code&gt;0x01&lt;/code&gt; indicates utf-8 encoded text data, &lt;code&gt;0x02&lt;/code&gt; is binary data. Most people will transmit JSON in which case you'd probably want to choose the text opcode. When you emit binary data it will be represented in a browser specific &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob" rel="noopener noreferrer"&gt;Blob&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The API for sending data through a WebSocket is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws://websocket.example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onopen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Some message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Sends data to server.&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the WebSocket is receiving data (on the client side), a &lt;code&gt;message&lt;/code&gt; event is fired. This event includes a property called &lt;code&gt;data&lt;/code&gt; that can be used to access the contents of the message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Handle messages sent by the server.&lt;/span&gt;
&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can easily explore the data in each of the frames in your WebSocket connection using the Network Tab inside Chrome DevTools:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mrsq3dy4a4y1z4um6jx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mrsq3dy4a4y1z4um6jx.png" alt=" " width="700" height="173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Fragmentation
&lt;/h3&gt;

&lt;p&gt;Payload data can be split up into multiple individual frames. The receiving end is supposed to buffer them up until the &lt;code&gt;fin&lt;/code&gt; bit is set. So you can transmit the string "Hello World" in 11 packages of 6 (header length) + 1 byte each. Fragmentation is not allowed for control packages. However, the specification wants you to be able to handle &lt;a href="https://en.wikipedia.org/wiki/Interleaving_%28data%29" rel="noopener noreferrer"&gt;interleaved&lt;/a&gt; control frames. That's in case TCP packages arrive in arbitrary order.&lt;/p&gt;

&lt;p&gt;The logic for joining frames is roughly the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;receive the first frame&lt;/li&gt;
&lt;li&gt;remember opcode&lt;/li&gt;
&lt;li&gt;concatenate frame payload together until the &lt;code&gt;fin&lt;/code&gt; bit is set&lt;/li&gt;
&lt;li&gt;assert that the opcode for each package is zero&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The primary purpose of fragmentation is to allow sending a message that is of unknown size when the message is started. With fragmentation, a server may choose a reasonable size buffer and, when the buffer is full, write a fragment to the network. A secondary use case for fragmentation is for multiplexing, where it is not desirable for a large message on one logical channel to take over the whole output channel, so the multiplexing needs to be free to split the message into smaller fragments to better share the output channel.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Hearbeating?
&lt;/h3&gt;

&lt;p&gt;At any point after the handshake, either the client or the server can choose to send a ping to the other party. When the ping is received, the recipient must send back a pong as soon as possible. That's a heartbeat. You can use it to make sure that the client is still connected.&lt;/p&gt;

&lt;p&gt;A ping or pong is just a regular frame, but it's a control frame. Pings have an opcode of &lt;code&gt;0x9&lt;/code&gt;, and pongs have an opcode of &lt;code&gt;0xA&lt;/code&gt;. When you get a ping, send back a pong with the exact same Payload Data as the ping (for pings and pongs, the max payload length is &lt;strong&gt;125&lt;/strong&gt;). You might also get a pong without ever sending a ping. Ignore it if it happens.&lt;/p&gt;

&lt;p&gt;Heartbeating can be very useful. There are services (like load balancers) that will terminate idle connections. Plus, it's not possible for the receiving side to see if the remote side has terminated. Only at the next send would you realize that something went wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling Errors
&lt;/h3&gt;

&lt;p&gt;You can handle any errors that occur by listening out for the &lt;code&gt;error&lt;/code&gt; event.&lt;/p&gt;

&lt;p&gt;It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws://websocket.example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Handle any error that occurs.&lt;/span&gt;
&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WebSocket Error: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Closing the Connection
&lt;/h3&gt;

&lt;p&gt;To close a connection either the client or server should send a control frame with data containing an opcode of &lt;code&gt;0x8&lt;/code&gt;. Upon receiving such a frame, the other peer sends a Close frame in response. The first peer then closes the connection. Any further data received after closing the connection is then discarded.&lt;/p&gt;

&lt;p&gt;This is how you initiate the closing of a WebSocket connection from the client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Close if the connection is open.&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readyState&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, in order to perform any clean up after the closing has completed, you can attach an event listener to the &lt;code&gt;close&lt;/code&gt; event:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Do necessary clean up.&lt;/span&gt;
&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onclose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Disconnected from WebSocket.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server has to listen on the &lt;code&gt;close&lt;/code&gt; event in order to process it if needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reasonCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// The connection is getting closed.&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How do WebSockets and HTTP/2 compare?
&lt;/h3&gt;

&lt;p&gt;While HTTP/2 has a lot to offer, it doesn't completely replace the need for existing push/streaming technologies.&lt;/p&gt;

&lt;p&gt;The first important thing to notice about HTTP/2 is that it's not a replacement for all of HTTP. The verbs, status codes and most of the headers will remain the same as today. HTTP/2 is about improving the efficiency of the way data is transferred on the wire.&lt;/p&gt;

&lt;p&gt;Now, if we compare HTTP/2 to WebSocket, we can see a lot of similarities:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmupze855wvxpcfg3f9wd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmupze855wvxpcfg3f9wd.png" alt=" " width="700" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we have seen above, HTTP/2 introduces &lt;a href="https://en.wikipedia.org/wiki/Push_technology?oldformat=true" rel="noopener noreferrer"&gt;Server Push&lt;/a&gt; which enables the server to proactively send resources to the client cache. It does not, however, allow for pushing data down to the client application itself. Server pushes are only processed by the browser and do not pop up in the application code, meaning there is no API for the application to get notifications for those events.&lt;/p&gt;

&lt;p&gt;This is where Server-Sent Events (SSE) become very useful. SSE is a mechanism that allows the server to asynchronously push the data to the client once the client-server connection is established. The server can then decide to send data whenever a new "chunk" of data is available. It can be considered as a one-way &lt;a href="https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern" rel="noopener noreferrer"&gt;publish-subscribe&lt;/a&gt; model. It also offers a standard JavaScript client API named EventSource implemented in most modern browsers as part of the HTML5 standard by &lt;a href="https://html.spec.whatwg.org/multipage/" rel="noopener noreferrer"&gt;W3C&lt;/a&gt;. Note that browsers that do not support &lt;a href="https://caniuse.com/eventsource" rel="noopener noreferrer"&gt;EventSource API&lt;/a&gt; can be easily polyfilled.&lt;/p&gt;

&lt;p&gt;Since SSE is based on HTTP, it has a natural fit with HTTP/2 and can be combined to get the best of both: HTTP/2 handling an efficient transport layer based on multiplexed streams and SSE providing the API up to the applications to enable push.&lt;/p&gt;

&lt;p&gt;To fully understand what Streams and Multiplexing are all about, let's first have a look at the IETF definition: &lt;em&gt;a "stream" is an independent, bidirectional sequence of frames exchanged between the client and server within an HTTP/2 connection. One of its main characteristics is that a single HTTP/2 connection can contain multiple concurrently open streams, with either endpoint interleaving frames from multiple streams&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntuvxh0p3hr2bdmbae8c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntuvxh0p3hr2bdmbae8c.png" alt=" " width="700" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have to remember that SSE is HTTP-based. It means that with HTTP/2, not only can several SSE streams be interleaved onto a single TCP connection, but the same can also be done with a combination of several SSE streams (server to client push) and several client requests (client to server). Thanks to HTTP/2 and SSE, now we have a pure HTTP bidirectional connection with a simple API to let application code register to server pushes. Lack of bidirectional capabilities has often been perceived as a major drawback when comparing SSE to WebSocket. Thanks to HTTP/2 this is no longer the case. This opens up the opportunity to skip WebSockets and stick to an HTTP-based signaling instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to choose between WebSocket and HTTP/2?
&lt;/h3&gt;

&lt;p&gt;WebSockets will certainly survive the domination of HTTP/2 + SSE, mainly because it's a technology already well adopted and, in very specific use cases, it has an advantage over HTTP/2 as it has been built for bidirectional capabilities with less overhead (e.g. headers).&lt;/p&gt;

&lt;p&gt;Say you want to build a Massive Multiplayer Online Game that needs a huge amount of messages from both ends of the connection. In such a case, WebSockets will perform much, much better.&lt;/p&gt;

&lt;p&gt;In general, use WebSockets whenever you need a truly low-latency, near realtime connection between the client and the server. Keep in mind that this might require rethinking how you build your server-side applications, as well as shifting the focus on technologies like event queues.&lt;/p&gt;

&lt;p&gt;If your use case requires displaying real-time market news, market data, chat applications, etc., relying on HTTP/2 + SSE will provide you with an efficient bidirectional communication channel while reaping the benefits from staying in the HTTP world:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebSockets can often be a source of pain when considering compatibility with existing web infrastructure as it upgrades an HTTP connection to a completely different protocol that has nothing to do with HTTP.&lt;/li&gt;
&lt;li&gt;Scale and security: Web components (Firewalls, Intrusion Detection, Load Balancers) are built, maintained and configured with HTTP in mind, an environment that large/critical applications will prefer in terms of resiliency, security, and scalability.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Support ❤️
&lt;/h2&gt;

&lt;p&gt;It took a lot of time and effort to create this material. If you found this article useful or interesting, please support my work with a small donation. It will help me to continue sharing my knowledge and ideas.&lt;/p&gt;

&lt;p&gt;Make a contribution or Subscription to the author's content: &lt;a href="http://buymeacoffee.com/betelgeuseo" rel="noopener noreferrer"&gt;Buy me a Coffee&lt;/a&gt;, &lt;a href="https://patreon.com/betelgeuseo" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;, &lt;a href="https://www.paypal.com/donate/?hosted_button_id=327N24D6QDLVC" rel="noopener noreferrer"&gt;PayPal&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>frontend</category>
    </item>
    <item>
      <title>@layer in CSS</title>
      <dc:creator>Andrew S.</dc:creator>
      <pubDate>Sun, 27 Apr 2025 15:49:24 +0000</pubDate>
      <link>https://dev.to/betelgeuseas/layer-in-css-552m</link>
      <guid>https://dev.to/betelgeuseas/layer-in-css-552m</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;@layer&lt;/code&gt; directive, the optional &lt;code&gt;layer()&lt;/code&gt; function, and the &lt;code&gt;layer&lt;/code&gt; keyword give you the ability to control cascading layers.&lt;/p&gt;

&lt;p&gt;Cascading layers is a way of grouping and ordering styles in a single source. They help browsers understand which styles to apply on a site.&lt;/p&gt;

&lt;p&gt;The source in CSS is where the browser gets its CSS rules from. This can be your styles on the site, user settings in the browser and system, and default browser styles. Learn more about this and other concepts in the Cascade Principle article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;With cascading layers, you directly manage layers with different sets of CSS rules and decide which styles are specific and in what order to apply them. So they are useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;resetting browser default styles;&lt;/li&gt;
&lt;li&gt;overwriting styles from CSS frameworks and libraries;&lt;/li&gt;
&lt;li&gt;styling components;&lt;/li&gt;
&lt;li&gt;storing styles in one place, for example, for the states of - interactive elements;&lt;/li&gt;
&lt;li&gt;colour themes, schemes and support for different colour modes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, here are the styles with &lt;code&gt;@layer&lt;/code&gt; for the state of the button when in focus and when inactive. In the &lt;code&gt;states&lt;/code&gt; layer we set the styles for &lt;code&gt;:disabled&lt;/code&gt; and &lt;code&gt;:focus-visible&lt;/code&gt;, and in &lt;code&gt;components&lt;/code&gt; we set the button's default styles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;states&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;210px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9px&lt;/span&gt; &lt;span class="m"&gt;15px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;18px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;inherit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;background-color&lt;/span&gt; &lt;span class="m"&gt;0.2s&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nc"&gt;.button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FFFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;background-color&lt;/span&gt; &lt;span class="m"&gt;0.2s&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;states&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;:focus-visible&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#FFFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;:disabled&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#DDDDDD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without cascading layers, we need to set styles to the .button class with the right pseudo classes. At the same time, we can't store them in one place in the file so that other developers don't accidentally overwrite them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* CSS-rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* CSS-rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.button&lt;/span&gt;&lt;span class="nd"&gt;:focus-visible&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* CSS-rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.button&lt;/span&gt;&lt;span class="nd"&gt;:disabled&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* CSS-rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With cascading layers, it's easier to defeat third-party styles. For example, from Bootstrap. Let's imagine that we want to change the size of the first level header without painful search for the necessary Sass variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"fs-1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Recent Updates&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bootstrap Styles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.fs-1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.5rem&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our styles using cascading layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url("https://cdn.com/bootstrap.min.css")&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.fs-1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With older CSS features, this problem has to be solved in several ways. For example, with the &lt;code&gt;!important&lt;/code&gt; modifier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.fs-1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3rem&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to Spell
&lt;/h2&gt;

&lt;p&gt;There are several ways to declare cascading layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@layer&lt;/code&gt; directive;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;layer&lt;/code&gt; keyword;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;layer()&lt;/code&gt; function.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Layers can be named (named) or unnamed (anonymous).&lt;/p&gt;

&lt;p&gt;With named layers, you directly control the style order or define it in one place in the CSS file.&lt;/p&gt;

&lt;p&gt;Anonymous layers prevent other developers from manipulating the rules in them and ensure that all the rules you need are stored in one place in the file. This is especially useful when replacing styles from a CSS framework with your own.&lt;/p&gt;

&lt;p&gt;After compiling styles with cascading layers, you get regular CSS code. In the developer tool, you will notice that your styles are taken from the project file. The rules also tell you what the layer is and what it's called. For example, "Layer typography" or browser styles "Layer user agent stylesheet".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxapk6e3jm6jinaad1e2b.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxapk6e3jm6jinaad1e2b.webp" alt="Image description" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Watch the size of the final styles file when you use &lt;code&gt;@layer&lt;/code&gt;. With this directive, it's easy to end up with a file with a lot of CSS rules that overwrite each other.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Directive @layer
&lt;/h3&gt;

&lt;p&gt;For &lt;strong&gt;named layers&lt;/strong&gt;, specify a name after the &lt;code&gt;@layer&lt;/code&gt; directive and list the necessary rules inside. The name of the layer can be anything in Latin. For example, &lt;code&gt;application&lt;/code&gt;, &lt;code&gt;framework&lt;/code&gt;, &lt;code&gt;base&lt;/code&gt;, &lt;code&gt;utilities&lt;/code&gt;, &lt;code&gt;typography&lt;/code&gt; or &lt;code&gt;theme&lt;/code&gt;. The names must be unique and not repeated. Exception - layers nested in other layers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;any-layer-name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more CSS rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Layers can be nested within each other - grouped. A layer with others inside it is called a parent layer, and nested layers are called children. Note that a child layer cannot "go beyond" its parent. It cannot be linked to other child layers or even parent cascading layers.&lt;/p&gt;

&lt;p&gt;Here, the &lt;code&gt;framework&lt;/code&gt; layer is the parent layer, and &lt;code&gt;base&lt;/code&gt; and &lt;code&gt;theme&lt;/code&gt; are the children:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;framework&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;/* One or more CSS rules */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;/* One or more CSS rules */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Child layers can have the same names as others outside of its parent. In this example, there are two completely different layers named &lt;code&gt;base&lt;/code&gt; and &lt;code&gt;framework.base&lt;/code&gt;, because the second &lt;code&gt;base&lt;/code&gt; layer is inside the &lt;code&gt;framework&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more CSS rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;framework&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;/* One or more CSS rules */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Layers can be listed in one place. Place their names separated by a comma after the &lt;code&gt;@layer&lt;/code&gt; directive. Here we collected two layers in one line and got &lt;code&gt;@layer layer-1, layer-2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;layer-1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layer-2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;layer-1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more CSS rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;layer-2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more CSS rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When listing child layers on a single line, specify the name of the parent layer first and the child layer after the dot. For example, we have a parent layer &lt;code&gt;framework&lt;/code&gt; and child layers &lt;code&gt;base&lt;/code&gt; and &lt;code&gt;theme&lt;/code&gt;. When enumerating, the names of the children will be &lt;code&gt;framework.base&lt;/code&gt; and &lt;code&gt;framework.theme&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;framework&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;framework&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;framework&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;/* One or more CSS rules */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;/* One or more CSS rules */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Layers can be listed inside &lt;code&gt;@layer&lt;/code&gt; as well. In this case, the name of the layer is again made up of the parent and child names. For example, in the &lt;code&gt;framework&lt;/code&gt; layer we define the order in which the base styles &lt;code&gt;base&lt;/code&gt; and &lt;code&gt;theme&lt;/code&gt; dark styles are applied. The CSS rules themselves are stored in separate layers &lt;code&gt;framework.base&lt;/code&gt; and &lt;code&gt;framework.theme&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;framework&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;framework&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more CSS rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;framework&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more CSS rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can put other directives in &lt;code&gt;@layer&lt;/code&gt;. For example, &lt;code&gt;@media&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;framework&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FFFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FFFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;strong&gt;anonymous layers&lt;/strong&gt;, only specify the @layer directive with the necessary rules inside.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more CSS rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Named layers can be inserted into anonymous layers. Other developers still cannot manipulate styles in them, as their parent remains anonymous. Here there are two children &lt;code&gt;base&lt;/code&gt; and &lt;code&gt;typography&lt;/code&gt; inside the anonymous layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;/* One or more CSS rules */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;typography&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;/* One or more CSS rules */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  How it Works
&lt;/h4&gt;

&lt;p&gt;The order in which layer styles are applied affects the order in which they are arranged in the file or list. There are also peculiarities in the behaviour of CSS rules within them.&lt;/p&gt;

&lt;p&gt;In a layer with CSS rules and another &lt;code&gt;@layer&lt;/code&gt;, separate rules win. In this example, the paragraph text will be black (&lt;code&gt;#000000&lt;/code&gt;) because the selector with this rule is outside the nested layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text--pink"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
 Paragraph
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;typography&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* I win: */&lt;/span&gt;
  &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;/* I lost: */&lt;/span&gt;
  &lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;typography&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FFFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To avoid confusion, you can always put such rules outside @layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* I lost: */&lt;/span&gt;
&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;typography&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;typography&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FFFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* I win: */&lt;/span&gt;
&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the rules aren't nested inside &lt;code&gt;@layer&lt;/code&gt;, they always win. For example, here the text will be black despite the styles for the &lt;code&gt;.text--pink&lt;/code&gt; class in &lt;code&gt;@layer&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text--pink"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Paragraph
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* I lost: */&lt;/span&gt;
&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;typography&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.text--pink&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#F498AD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* I win: */&lt;/span&gt;
&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A separate rule applies even if located above &lt;code&gt;@layer&lt;/code&gt;, so the text is still black:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* I win: */&lt;/span&gt;
&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* I lost: */&lt;/span&gt;
&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;typography&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.text--pink&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#F498AD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What if the layers have rules with the &lt;code&gt;!important&lt;/code&gt; modifier? In this case, the order is defined as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A layer with &lt;code&gt;@layer&lt;/code&gt; with the &lt;code&gt;!important&lt;/code&gt; property that sits above the others.&lt;/li&gt;
&lt;li&gt;CSS rule outside &lt;code&gt;@layer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A layer with &lt;code&gt;@layer&lt;/code&gt; with no property with &lt;code&gt;!important&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The pink text colour with the &lt;code&gt;!important&lt;/code&gt; modifier from the &lt;code&gt;typography&lt;/code&gt; layer wins here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text--pink"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Paragraph
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* I win: */&lt;/span&gt;
&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;typography&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.text--pink&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#F498AD&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* I lost: */&lt;/span&gt;
&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* I lost too: */&lt;/span&gt;
&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;typography&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FFFFFF&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you list the layers on a single line, the order of the layers is important. The first layer in the list is overwritten by the layer after it, and so on.&lt;/p&gt;

&lt;p&gt;In the example, the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; paragraph text will again be black because &lt;code&gt;layer-2&lt;/code&gt; is after &lt;code&gt;layer-1&lt;/code&gt; and therefore higher in presentation order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;layer-1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layer-2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c"&gt;/* I lost: */&lt;/span&gt;
&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;layer-1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FFFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* I win: */&lt;/span&gt;
&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;layer-2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if you increase the specificity of a paragraph from &lt;code&gt;layer-1&lt;/code&gt; with &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;layer-2&lt;/code&gt; still wins. So the text in the paragraph will remain black:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;layer-1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layer-2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c"&gt;/* I lost: */&lt;/span&gt;
&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;layer-1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="nf"&gt;#light&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FFFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* I win: */&lt;/span&gt;
&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;layer-2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Listing the child layers in a single line works the same way. This example has a parent &lt;code&gt;framework&lt;/code&gt; and two children &lt;code&gt;framework.base&lt;/code&gt; and &lt;code&gt;framework.theme&lt;/code&gt;. The paragraph text will again be black because &lt;code&gt;framework.theme&lt;/code&gt; is listed after &lt;code&gt;framework.base&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;framework&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;framework&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;framework&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* I win: */&lt;/span&gt;
  &lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;/* I lost: */&lt;/span&gt;
  &lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FFFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For anonymous layers, it matters where they are in the file. So you can't add them anywhere like named ones. Below, the anonymous layer is in front of the named &lt;code&gt;base&lt;/code&gt;, so the paragraph text is black:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* I lost: */&lt;/span&gt;
&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FFFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* I win: */&lt;/span&gt;
&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you place the anonymous layer after the named &lt;code&gt;base&lt;/code&gt;, the text becomes white (&lt;code&gt;#FFFFFFFF&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* I lost: */&lt;/span&gt;
&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* I win: */&lt;/span&gt;
&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FFFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Keyword layer
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;layer&lt;/code&gt; keyword is needed when applying anonymous layer rules when importing styles from another file. This is done with the &lt;code&gt;@import&lt;/code&gt; directive.&lt;/p&gt;

&lt;p&gt;Specify the word &lt;code&gt;layer&lt;/code&gt; after &lt;code&gt;@import&lt;/code&gt; and the path to the desired CSS file. To make sure that other styles and developers don't overwrite the rules from the anonymous layer, place it at the very end of the file. This trick helps to gather in one place the most important and basic styles that you don't want to change under any circumstances.&lt;/p&gt;

&lt;p&gt;Here we replace the necessary styles from the &lt;em&gt;tailwind.css&lt;/em&gt; file with styles from the anonymous layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url(tailwind.css)&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can place an anonymous layer before the &lt;code&gt;@import&lt;/code&gt; line as well. In this case, the priority of these styles will be lower than that of the layers behind them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url(tailwind.css)&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rules from one anonymous layer can be applied multiple times. Let's use the styles from the anonymous layer in the files &lt;em&gt;base-forms.css&lt;/em&gt;, &lt;em&gt;base-links.css&lt;/em&gt; and &lt;em&gt;base-buttons.css&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url(base-forms.css)&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url(base-links.css)&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url(base-buttons.css)&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  layer() function
&lt;/h3&gt;

&lt;p&gt;With &lt;code&gt;layer()&lt;/code&gt;, you refer to a specific layer when importing styles from one file to another.&lt;/p&gt;

&lt;p&gt;Let's imagine that we need to add our own basic styles for a site where we already use a CSS framework such as Bootstrap. Let's create a &lt;code&gt;base&lt;/code&gt; layer with the necessary CSS rules and apply them in bootstrap.css:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url(bootstrap.css)&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;layer()&lt;/code&gt; gives reuse of styles from the same named layer. Here styles from &lt;code&gt;base&lt;/code&gt; are combined with others from &lt;em&gt;headings.css&lt;/em&gt; and &lt;em&gt;links.css&lt;/em&gt; files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url(buttons.css)&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url(links.css)&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function also comes in handy when you need a specific child layer inside an anonymous one. Let's imagine that we are adding our own basic styles for a site where we are using Bootstrap again. Let's create a child layer &lt;code&gt;base&lt;/code&gt; inside the anonymous layer and access it directly using &lt;code&gt;layer(base)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url(bootstrap.css)&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  All together
&lt;/h3&gt;

&lt;p&gt;Directive, function and keyword can be combined. In this way you can more precisely define the order of layers in one place before declaring styles.&lt;/p&gt;

&lt;p&gt;At the beginning of the file, list the layers after &lt;code&gt;@layer&lt;/code&gt;. Let's arrange them so that the &lt;code&gt;tailwind&lt;/code&gt; layer has a lower priority for overwriting third-party styles, and the &lt;code&gt;application&lt;/code&gt; layer has the highest priority for its own styles. On the second line, import styles from &lt;em&gt;tailwind.css&lt;/em&gt; and overwrite the necessary ones with the &lt;code&gt;tailwind&lt;/code&gt; layer using &lt;code&gt;layer()&lt;/code&gt;. After that we will define the CSS rules we need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="nb"&gt;default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tailwind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url(tailwind.css)&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tailwind&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="nb"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;tailwind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@import&lt;/code&gt; can be placed between lines with &lt;code&gt;@layer&lt;/code&gt;. The result will be the same.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="nb"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url(tailwind.css)&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tailwind&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="nb"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;tailwind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need to apply multiple layers in the imported file, list them comma-separated on the same line as &lt;code&gt;@import&lt;/code&gt;. The specification prohibits importing other files after a single line &lt;code&gt;@layer&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="nb"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url(frameworks.css)&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tailwind&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="nb"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;bootstrap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;tailwind&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* One or more rules */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to Realise
&lt;/h2&gt;

&lt;p&gt;Cascading layers in CSS are similar to layers in image editors like PhotoShop. You can add multiple layers for images to flexibly manage different effects and filters. Since the layers are transparent and don't mix with each other, it's easy to fix a mistake or add a new effect without changing the old one.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@layer&lt;/code&gt;, &lt;code&gt;layer&lt;/code&gt;, and &lt;code&gt;layer()&lt;/code&gt; solve style problems without changing selectors, and help avoid conflicts between different layers due to their position in CSS files. Often these problems arise from multiple style sources. For example, frameworks and libraries that are mostly used in large projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Support ❤️
&lt;/h2&gt;

&lt;p&gt;It took a lot of time and effort to create this material. If you found this article useful or interesting, please support my work with a small donation. It will help me to continue sharing my knowledge and ideas.&lt;/p&gt;

&lt;p&gt;Make a contribution or Subscription to the author's content: &lt;a href="http://buymeacoffee.com/betelgeuseo" rel="noopener noreferrer"&gt;Buy me a Coffee&lt;/a&gt;, &lt;a href="https://patreon.com/betelgeuseo" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;, &lt;a href="https://www.paypal.com/donate/?hosted_button_id=327N24D6QDLVC" rel="noopener noreferrer"&gt;PayPal&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>css</category>
      <category>html</category>
    </item>
    <item>
      <title>Architecture and Design Patterns in Front-End</title>
      <dc:creator>Andrew S.</dc:creator>
      <pubDate>Sun, 27 Apr 2025 14:29:08 +0000</pubDate>
      <link>https://dev.to/betelgeuseas/architecture-and-design-patterns-in-front-end-iea</link>
      <guid>https://dev.to/betelgeuseas/architecture-and-design-patterns-in-front-end-iea</guid>
      <description>&lt;p&gt;Writing comprehensible code is hard.&lt;/p&gt;

&lt;p&gt;Each line of code increases the reader's load, so it is difficult to read a lot of code. On the other hand, if the code lacks details and explanations, it is also very difficult to understand its meaning. When writing programmes, we need to keep a balance between brevity and completeness, between abstractions and concreteness.&lt;/p&gt;

&lt;p&gt;Finding this balance is helped by solutions that the community perceives as standard, template solutions. Sometimes these solutions get names and become patterns or architectural approaches.&lt;/p&gt;

&lt;p&gt;In this article, we will give a brief overview of architectural approaches and design patterns that are used in modern frontend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Application architecture&lt;/strong&gt; is a set of decisions about how application modules will communicate with each other and with the outside world.&lt;/p&gt;

&lt;p&gt;Architecture includes approaches: constraints, rules, and heuristics to follow when writing code.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;design pattern&lt;/strong&gt; is a pattern solution to a frequent architectural problem.&lt;/p&gt;

&lt;p&gt;The area of responsibility of design patterns is smaller than that of architecture in general. Patterns help us to solve problems at a "lower level", closer to the code itself. Architecture, on the other hand, solves design problems of the whole system.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To simplify, architecture is the instruction "How to build a house in general", it covers the whole project. And patterns are instructions for specific tasks: "How to drive piles", "How to mix cement", "How to lay wiring".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Architecture in the Front-End
&lt;/h2&gt;

&lt;p&gt;Modern frontend is complex. For complex systems to behave predictably, they need to be managed. Architecture helps solve the challenges of designing such systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Architecture is Necessary
&lt;/h3&gt;

&lt;p&gt;Humans are not good at predicting the future. It is difficult for us to predict how a programme or its requirements will change. The only thing we know for sure is that the requirements (and therefore the programme) will change.&lt;/p&gt;

&lt;p&gt;Proper architecture helps to design and develop the system so that it is easier and more convenient to expand and change.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If communication between modules is regulated, it is easier to replace their implementation with another one.&lt;/li&gt;
&lt;li&gt;If communication with the outside world is regulated, there are fewer chances for data leakage.&lt;/li&gt;
&lt;li&gt;If the code is divided intelligently, the programme is easier to test.&lt;/li&gt;
&lt;li&gt;If the code is organised in a clear way, it takes less time to add new features and search for bugs in old ones.&lt;/li&gt;
&lt;li&gt;If the architecture is widely known, immersion into the project is faster.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What Architectural Approaches are Available
&lt;/h3&gt;

&lt;p&gt;We can roughly categorise architectural approaches according to their goals and scope.&lt;/p&gt;

&lt;p&gt;Part of the approach assigns responsibility to modules. They define which modules will be responsible for what.&lt;/p&gt;

&lt;p&gt;The best known of these approaches is the &lt;strong&gt;Model-View-Controller&lt;/strong&gt;. It distinguishes 3 "types" of tasks, according to which it assigns roles to modules.&lt;/p&gt;

&lt;p&gt;Others determine how close each module is to the business logic. These approaches care about which part of the code deals directly with the application task and which part deals with infrastructure tasks.&lt;/p&gt;

&lt;p&gt;For example, in a photo processing app, the business logic would be filter functions and the infrastructure tasks would be accessing the phone's camera API.&lt;/p&gt;

&lt;p&gt;These approaches divide code into "layers" based on the degree of proximity to business logic. The most common approach among such approaches is the &lt;strong&gt;Three-Layer&lt;/strong&gt; architecture.&lt;/p&gt;

&lt;p&gt;The third &lt;a href="https://dev.to/betelgeuseas/organisation-of-data-flows-33nh"&gt;manages the data flows in the application&lt;/a&gt;. They determine how modules communicate with each other: directly, indirectly, or through special services like the event bus.&lt;/p&gt;

&lt;p&gt;In frontend, the most probably well-known approach is &lt;a href="https://facebookarchive.github.io/flux/" rel="noopener noreferrer"&gt;Flux&lt;/a&gt; and its most common implementation, &lt;a href="https://redux.js.org/" rel="noopener noreferrer"&gt;Redux&lt;/a&gt;. This is an example of unidirectional data flow.&lt;/p&gt;

&lt;p&gt;In addition to it, bidirectional flow is used, such as reactive data updates. We talk about each in detail in the article &lt;a href="https://dev.to/betelgeuseas/organisation-of-data-flows-33nh"&gt;"Architecture: Data Flows"&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Other approaches define the layout of the application. Whether it will be one large programme (&lt;strong&gt;monolith&lt;/strong&gt;) or a set of several smaller programmes (&lt;strong&gt;microservices&lt;/strong&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the Disadvantages of Architecture
&lt;/h3&gt;

&lt;p&gt;Creating, organising, and following an architecture always requires resources: time, money, and mental effort. The choice should be made after comparing the costs and benefits of each candidate approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Patterns
&lt;/h2&gt;

&lt;p&gt;Some problems are too small to be isolated into an architectural approach, but are common enough to spawn standard solutions. Such standard solutions are called patterns or templates.&lt;/p&gt;

&lt;p&gt;For example, the server sends us data in the form of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;some_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;LastName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's what we want them to be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;someData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Name LastName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is an Adapter pattern to solve such a problem. It makes an incompatible third-party API suitable for our application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;serverToClientAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;someData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;some_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are many such standard solutions. We can divide them into several groups.&lt;/p&gt;

&lt;h3&gt;
  
  
  Progenitors
&lt;/h3&gt;

&lt;p&gt;Generating patterns help solve problems with the creation of entities or groups of similar entities. They remove unnecessary duplication and make the process of creating entities shorter and more straightforward.&lt;/p&gt;

&lt;p&gt;Among the generating patterns we can distinguish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Factory";&lt;/li&gt;
&lt;li&gt;"Factory Method";&lt;/li&gt;
&lt;li&gt;"Abstract Factory."&lt;/li&gt;
&lt;li&gt;"Builder."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Structural
&lt;/h3&gt;

&lt;p&gt;Structural patterns help to solve the problems of matching and combining entities. They take care of how entities can use each other.&lt;/p&gt;

&lt;p&gt;Among the structural patterns we can distinguish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Adapter";&lt;/li&gt;
&lt;li&gt;"Decorator";&lt;/li&gt;
&lt;li&gt;"Facade";&lt;/li&gt;
&lt;li&gt;"Proxy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Behavioural
&lt;/h3&gt;

&lt;p&gt;Behavioural patterns allocate responsibility between modules and determine exactly how communication will take place.&lt;/p&gt;

&lt;p&gt;Among the behavioural patterns we can distinguish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Chain of Responsibility."&lt;/li&gt;
&lt;li&gt;"Strategy."&lt;/li&gt;
&lt;li&gt;"Team."&lt;/li&gt;
&lt;li&gt;"Observer."&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture and Patterns are not the Goal
&lt;/h2&gt;

&lt;p&gt;Every design approach and pattern is first and foremost a means to solve problems. Developers should not treat them as a goal when writing code.&lt;/p&gt;

&lt;p&gt;Sometimes a solution without a complex architecture will be simpler and faster. For example, when developing a prototype, architecture is often unnecessary.&lt;/p&gt;

&lt;p&gt;Architectural approaches and patterns are tools. We advise bringing tools to a project as needed and comparing the benefits and costs of each.&lt;/p&gt;

&lt;h2&gt;
  
  
  Support ❤️
&lt;/h2&gt;

&lt;p&gt;It took a lot of time and effort to create this material. If you found this article useful or interesting, please support my work with a small donation. It will help me to continue sharing my knowledge and ideas.&lt;/p&gt;

&lt;p&gt;Make a contribution or Subscription to the author's content: &lt;a href="http://buymeacoffee.com/betelgeuseo" rel="noopener noreferrer"&gt;Buy me a Coffee&lt;/a&gt;, &lt;a href="https://patreon.com/betelgeuseo" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;, &lt;a href="https://www.paypal.com/donate/?hosted_button_id=327N24D6QDLVC" rel="noopener noreferrer"&gt;PayPal&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>frontend</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
