{"id":52130,"date":"2018-03-12T08:00:59","date_gmt":"2018-03-12T07:00:59","guid":{"rendered":"https:\/\/www.humanlevel.com\/sin-categorizar\/optimizacion-de-css.html"},"modified":"2023-05-30T09:00:00","modified_gmt":"2023-05-30T07:00:00","slug":"css-optimization","status":"publish","type":"post","link":"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization","title":{"rendered":"CSS optimization"},"content":{"rendered":"<p>In this guide to <strong>CSS optimization<\/strong> (Cascading Stylesheets), we are going to study what is necessary for the downloading and painting of a web page to be done in an optimal way.<\/p>\n<p>In the guide to <a href=\"https:\/\/www.humanlevel.com\/en\/blog\/seo\/javascript-optimization\" target=\"_blank\" rel=\"noopener noreferrer\">JavaScript optimization<\/a> already explained how <strong>WPO has grown in importance at the client side.<\/strong>and to achieve more loyal users, allowing us to <strong>better mobile positioning<\/strong>.<\/p>\n\n<p>Recall that in the JavaScript guide, I commented that the optimum, according to the <strong>Google&#8217;s RAIL performance model<\/strong> es:<\/p>\n<ul>\n<li>Interface <strong>response<\/strong>in less than 100ms.<\/li>\n<li>Full draw <strong>animations<\/strong>every 16ms which is 60 FPS (frames per second).<\/li>\n<li><strong>Disabled<\/strong>: when the user does not interact with the page, which runs in the background, it should not last more than 50ms.<\/li>\n<li><strong>Load<\/strong>: the page must load in 1000ms.<\/li>\n<\/ul>\n<p><strong>CSS affects animations and page loading in the RAIL model<\/strong>. Let&#8217;s also remember that, to load the page, the browser follows the <strong>critical representation path<\/strong>HTML download &gt;&gt; DOM construction &gt;&gt; CSS and JS download &gt;&gt; CCSOM construction &gt;&gt; representation tree construction &gt;&gt; layout or reflow &gt;&gt; painting &gt;&gt; composition.<br \/>\nThe optimization techniques that we are going to see next will affect all these stages, so if we carry them out correctly, the total loading time can be substantially improved.<\/p>\n<h2>Optimize download and interpretation<\/h2>\n<p>At this point it is important to understand <strong>the cascade of downloads<\/strong> (Network waterfall of developer tools). When a page is downloaded, <strong>some files call others<\/strong> and a <strong>tree structure of dependencies by levels<\/strong> which would be as follows:<\/p>\n\n<ol>\n<li>At the <strong>first level we would have the HTML<\/strong>, which is the first thing to be downloaded and would constitute the trunk of the tree.<\/li>\n<li>At the <strong>second level<\/strong> (the branches), we would have the <strong>image, CSS and JavaScript<\/strong> resources <strong>linked from the HTML<\/strong>.<\/li>\n<li>In the<strong> third level<\/strong> (the sheets), we have the<strong> images, fonts and additional CSS linked from the CSS downloaded in the previous step<\/strong>. The<strong> JavaScript, once it is running, can also request additional files<\/strong> of any type.<\/li>\n<li><strong>We could have a fourth level<\/strong> (which could be the nerves of the leaves), since it is possible to have<strong> a CSS that downloads another one <\/strong>that in turn downloads another one and so we could have a large number of levels that would make the download totally inefficient.<\/li>\n<\/ol>\n<p>Now that we know how some files depend on others, let&#8217;s see how to create the <strong>cascade of downloads<\/strong>:<br \/>\nThe browser uses an algorithm called <strong>preload scanner<\/strong> to determine that <strong>requested files in the HTML block the critical rendering path<\/strong> and thus <strong>request these critical resources as soon as possible<\/strong>. It also has a <strong>preload scanner for CSS<\/strong>. These algorithms barely understand HTML or CSS, they just look for the linked files to request them as soon as possible.<\/p>\n<p><strong>The critical resources of each level are attempted to be lowered in parallel<\/strong>This means that these files are requested and downloaded at the same time. But <strong>the passage from one level to the next occurs sequentially<\/strong> (files of one level are requested after the previous one), as it is necessary for the preload scanner to analyze the files in order to know which other files to download.<\/p>\n<p>Since <strong>sequential file requests are much slower than launching requests in parallel<\/strong> (it is quicker to ask for the information as soon as possible), most of the techniques I describe below are aimed at <strong>avoid new levels of the dependency tree <\/strong>(avoid sequential requests), or at least that there are as few critical files as possible at higher levels, since these will be the last files to be downloaded.<\/p>\n\n<p>Regarding the download, I believe it is necessary to explain that <strong>in HTTP1.1, parallel downloading is possible up to a certain number of files depending on the browser.<\/strong>while with <strong>HTTP2 there is no limit to the number of files downloaded in parallel<\/strong>The fact is that, internally, it is actually a <strong>multiplexed sequential download on the same data stream<\/strong>In other words, with HTTP2 it is as if we were downloading a single larger file that will occupy the same network resources as several files in parallel, but with less information and without the cost of sending the requests separately and sequentially in blocks.<\/p>\n<p>Below is a visual example of how the discharge cascade occurs:<\/p>\n<figure id=\"attachment_30707\" aria-describedby=\"caption-attachment-30707\" style=\"width: 1228px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" class=\"size-full wp-image-30707\" src=\"https:\/\/www.humanlevel.com\/wp-content\/uploads\/waterfall.png\" alt=\"Cascade of downloads from a web site\" width=\"1238\" height=\"918\" srcset=\"https:\/\/www.humanlevel.com\/wp-content\/uploads\/waterfall.png 1238w, https:\/\/www.humanlevel.com\/wp-content\/uploads\/waterfall-400x297.png 400w, https:\/\/www.humanlevel.com\/wp-content\/uploads\/waterfall-754x559.png 754w, https:\/\/www.humanlevel.com\/wp-content\/uploads\/waterfall-900x667.png 900w, https:\/\/www.humanlevel.com\/wp-content\/uploads\/waterfall-1200x890.png 1200w\" sizes=\"auto, (max-width: 1238px) 100vw, 1238px\" \/><figcaption id=\"caption-attachment-30707\" class=\"wp-caption-text\">Cascade of downloads of Google Chrome developer tools<\/figcaption><\/figure>\n<p>In short, for a quick download <strong>we want dependency trees to have as few resource-critical branches and leaves as possible <\/strong>(which are not necessary to paint the page initially).<\/p>\n\n<h3>Unify, minimize and compress from a preprocessor<\/h3>\n<p>It is always advisable not to use CSS directly, but to use a language on top like <strong>Sass, Less or Stylus<\/strong>. These languages allow you to make the code <strong>cleaner and more maintainable<\/strong>They have a syntax that allows you to write less, define variables, reuse code, separate code into files and, in the case of Sass, use programming control structures.<\/p>\n<p>A file written in any of these languages must be passed through a <strong>preprocessor that generates the unified and minimized CSS with its associated source map<\/strong>. These are .map files that will serve us to analyze the CSS in Chrome as if we were working with the original files. This work <strong>can be done before uploading the file to the web site<\/strong> with a tool such as webpack, gulp, grunt, etc. or, directly, with the tools of the languages themselves. There are also libraries to do it from the web programming itself, but this option is not recommended because it is a costly process. But, if done, always cache the result so as not to generate the CSS with each visit.<\/p>\n<p><strong>global for the entire website and one specific to the page.<\/strong>. That way we don&#8217;t make the user download styles that are not necessary for the page they are viewing.<\/p>\n\n<h3>Browser caching with HTTP protocol cache headers<\/h3>\n<p>We will use the header <strong>Cache-control with public and max-age values, with a large cache time, of at least 1 year<\/strong>. When we want to invalidate the cache we will change the file name. This renaming can be done automatically by the framework used for development and the tool for transpiling or preprocessing the CSS.<\/p>\n<h3>Compressing with brotli q11 and gzip<\/h3>\n<p>For CSS files we can follow the same recommendations that I gave in the article on <a href=\"https:\/\/www.humanlevel.com\/en\/blog\/seo\/javascript-optimization\" target=\"_blank\" rel=\"noopener noreferrer\">JavaScript optimization<\/a> and in that of <a href=\"https:\/\/www.humanlevel.com\/en\/blog\/seo\/gzip-compression-in-depth\" target=\"_blank\" rel=\"noopener noreferrer\">gzip compression<\/a>.<\/p>\n<h3>Delete unused selectors<\/h3>\n<p>CSS works with <strong>selectors<\/strong> which are patterns consisting mainly of <strong>elements, classes, identifiers, pseudo-classes, and pseudo-elements<\/strong> which are used to select those parts of the DOM of the page to which we want to style using <strong>properties<\/strong> as &#8220;color&#8221;, to which we can assign different <strong>values<\/strong>. For example:<\/p>\n<p>We do have a simple rule as follows:<br \/>\n<code><\/code><\/p>\n<pre>#pagina .producto a{  \/* &lt;- selector{ *\/ \n     color:blue;      \/* &lt;- declaraci\u00f3n formada por: propiedad:valor; *\/ \n}\n<\/pre>\n<p>We are saying that on a page with a structure like the following, the links will be blue:<\/p>\n<pre>&lt;main id=\"pagina\"&gt;\n   &lt;article class=\"producto\"&gt;\n       &lt;a href=\"\/url.html\"&gt;nombre del producto&lt;\/a&gt;\n   &lt;\/article&gt;\n&lt;\/main&gt;\n<\/pre>\n<p><strong>If we do not have any structure on the page with which the rule fits, this code will not be necessary.<\/strong>. With the tool <a href=\"https:\/\/github.com\/uncss\/uncss\">UnCSS<\/a>We can include this technique in the CSS generation process from Sass if we use gulp, grunt or broccoli.<\/p>\n<h3>Leveraging inheritance and cascading styles to create fewer rules<\/h3>\n<p>Some properties such as color, line-height, text-indent, text-transform, font and their variants, &#8230; when applied to an HTML element, <strong>all the elements contained in it inherit the value of this property<\/strong>. So, for example, we can create the following rule:<br \/>\nbody{<br \/>\nfont-family:sans-serif;<br \/>\n}<br \/>\nIn this way, <strong>we are setting the font type for the whole document<\/strong>The font type does not need to be specified for each element individually.<\/p>\n<p>CSS is an acronym for <strong>cascading style sheets<\/strong> and cascaded means that <strong>styles are applied in an order in which the highest priority rules overwrite others<\/strong>. How can we use this to write less? For example, in a blog like this one, we can have rules to style all the entries in a listing, but then we can overwrite some properties of it to style the featured entries, without having to duplicate part of the one we have already created. To know how to do this, the developer must know <strong>CSS selector specificity rules<\/strong> since, apart from the location of the styles and the order of the rules, this is what determines which rules have priority over others. For example, suppose we have a CSS with the following rules in this order:<\/p>\n<pre>\/* Regla 1 *\/ \n.clase2 div.clase1 div {\n  color:green;\n}\n\n\/* Regla 2 *\/ \ndiv {\n  color:blue!important;\n}\n\n\/* Regla 3 *\/ \ndiv.clase1 div:first-child {\n  color:yellow;\n}\n\n\/* Regla 4 *\/ \n#id1 .clase1 div {\n  color:red;\n}\n<\/pre>\n<p>And this would be the HTML fragment we want to style:<\/p>\n<pre>&lt;div id=\"id1\" class=\"clase2\"&gt;\n    &lt;div class=\"clase1\"&gt;\n        &lt;div&gt;Hola&lt;\/div&gt;\n    &lt;\/div&gt;\n&lt;\/div&gt;\n<\/pre>\n\n<p>All of the above rules affect the color of the word &#8220;Hello&#8221;, a developer who knows the rules of selector specificity should see without thinking that <strong>the rules apply in the following order<\/strong>from the highest to the lowest priority: Rule 2, Rule 4, Rule 1, Rule 3. Therefore, in this case the word &#8220;Hello&#8221;, will be shown in blue color by rule 2, although this has been done using the &#8220;important&#8221; directive, something that a good developer would not do except in certain cases.<\/p>\n<h3>Grouping rules<\/h3>\n<p>If you have to give the same style with several different selectors, <strong>groups selectors by separating them by commas<\/strong>. Example:<br \/>\nInstead of writing:<\/p>\n<pre>.clase1{\n    color:red;\n}\n\n.clase2{\n    color:red;\n}\n\n.clase3{\n   color:red;\n}\n<\/pre>\n<p>This can be written in a more abbreviated form as:<\/p>\n<pre>.clase1,.clase2,.clase3{\n    color:red;\n}\n<\/pre>\n<h3>Using abbreviated declarations<\/h3>\n<p>We can abbreviate several statements, as in the following example:<\/p>\n<pre>padding-top: 5px;\npadding-right: 5px;\npadding-bottom: 5px;\npadding-left: 5px;\n<\/pre>\n<p>The corresponding abbreviated statement should be used for this purpose:<\/p>\n<pre>padding: 5px;\n<\/pre>\n<p>This way we write less and the CSS will have less code to download.<\/p>\n<h3>Use CSS sprites intelligently<\/h3>\n<p>The term sprite in computer science arises initially from the world of video games to refer to squares containing images and characters (characters as sprites, which is the literal translation of sprite). In CSS the term sprite refers to <strong>rectangles of images to be displayed on the website<\/strong> and that <strong>are grouped in a larger image<\/strong>. <strong>By merging several images into one, we avoid having to download several files. <\/strong>and so we do not limit the parallel download capacity of the browser if we use HTTP1.1. With HTTP2 this technique does not provide any improvement.<\/p>\n<p>Procure<strong> to put together the <a>images that, because of their characteristics, are best suited to the compression of a type of image format<\/a><\/strong>. That way we can have some sprites in JPG, others in PNG-8, others in PNG-24, etc.<br \/>\nUsing this technique correctly is not about loading 300 icons into an image and then only using one. This is very common and is not the right way, because we are loading and processing a large image and then displaying only a small part of it.<\/p>\n<figure id=\"attachment_30711\" aria-describedby=\"caption-attachment-30711\" style=\"width: 915px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" class=\"size-full wp-image-30711\" src=\"https:\/\/www.humanlevel.com\/wp-content\/uploads\/css-sprites-google.png\" alt=\"CSS sprites of the Google home page\" width=\"925\" height=\"30\" srcset=\"https:\/\/www.humanlevel.com\/wp-content\/uploads\/css-sprites-google.png 925w, https:\/\/www.humanlevel.com\/wp-content\/uploads\/css-sprites-google-400x13.png 400w, https:\/\/www.humanlevel.com\/wp-content\/uploads\/css-sprites-google-754x24.png 754w, https:\/\/www.humanlevel.com\/wp-content\/uploads\/css-sprites-google-900x29.png 900w\" sizes=\"auto, (max-width: 925px) 100vw, 925px\" \/><figcaption id=\"caption-attachment-30711\" class=\"wp-caption-text\">CSS sprites of the Google home page (the image is rotated and reduced so you can see it without scrolling)<\/figcaption><\/figure>\n<h3>Embedding images with DATA-URIs<\/h3>\n<p>The <strong>data URI scheme<\/strong> o DATA-URI, <strong>allows us to embed images with encoded text strings within CSS<\/strong>. <strong>This causes the images to occupy more space<\/strong>. The file in binary format occupies less space than a text file. Let&#8217;s take a quick example, if in a file we have the binary value 1111 1111 which in decimal is the number 255, in the text we will have to have the characters 2 &#8211; 5 &#8211; 5 which in binary are encoded in ASCII with all these zeros and ones: 0011 0010 &#8211; 0011 0101 &#8211; 0011 0101.<\/p>\n<p>These are more zeros and ones than we originally had, so the file will take up more space. <strong>This increase of space is almost completely eliminated if we are compressing the CSS with brotli or gzip<\/strong>, so it is not a problem. In spite of that, this is a very good optimization technique, because <strong>we will be gaining a lot in loading time, by avoiding going down one more level in the tree to download the images<\/strong>.<\/p>\n<p>If we use this technique it is not necessary to use CSS sprites, but if we like to organize the images in sprites, we can combine the two techniques.<\/p>\n<p>It should be noted that <strong>if the same image is used in several parts of the CSS, we will have to rearrange the layout so that it appears only once<\/strong>by assigning the same class to the elements in the HTML that will display the image. If we do not do so, we will be downloading the same image several times.<\/p>\n<p>It is also necessary to<strong> pay attention to images that are not used or are only used in one part of the site <\/strong>because, contrary to what normally happens with linked images, we will always download those images, whether we use them or not. So <strong>this technique should be applied only to images that are critical resources<\/strong>. If you have not followed the recommendation to have two CSS for each page (one with the global styles and one for the current page), be careful with this.<br \/>\nThe images that we embed are best placed at the end of the CSS and <strong>should not be too large<\/strong>CSS is a critical resource that blocks page rendering and cannot take too long to download.<\/p>\n<p>Finally, we can use this technique to <strong>embed images directly into HTML<\/strong> inside the &#8220;src&#8221; attribute of the &#8220;img&#8221; element, but in this case I do not recommend using this technique with large images, because if in the HTML we have many bytes that do not belong to the content we can have indexing problems. It should also be noted that when the image is repeated on several sites or pages, it is better not to embed it in the HTML so that it can be cached and not downloaded several times.<\/p>\n<h3>Advance loading of images and fonts from HTML<\/h3>\n<p><strong>This technique is preferable to using DATA-URIs.<\/strong>because images can be cached in the browser independently of the CSS and without increasing its size. We can apply it by adding tags like this to the header:<\/p>\n<pre>&lt;link rel=\"preload\" href=\"bg-image-narrow.png\" as=\"image\" media=\"(max-width: 600px)\" \/&gt;\n<\/pre>\n<p>If we advance the request for linked images from the CSS, <strong>no need to wait for the CSS to be downloaded<\/strong> and have it analyzed by the preload scanner. This <strong>should be applied only to critical resources<\/strong>. We do not want to preload unnecessary resources.<\/p>\n<p>With this tag we can indicate which file we are going to preload and what type it is, we can even specify a media query to load only with certain screen sizes.<\/p>\n<p>Not to be confused with rel=&#8221;prefetch&#8221; which is to preload resources for the next page to be displayed.<\/p>\n<h3>Do not use @import<\/h3>\n<p>The CSS import rule (not to be confused with the import of Sass or Less), allows you to <strong>import CSS files from within other CSS files<\/strong>. If you have been paying attention you will already know that this is a very bad thing for performance, because we are increasing the levels of the dependency tree, causing one CSS to download another which in turn can download yet another one or download images.<\/p>\n<h3>Use media=&#8221;print&#8221; for print styles<\/h3>\n<p>In a style sheet we can set <strong>how the web will be printed when sent to the printer<\/strong>. This can be done <strong>within the global CSS with a media query or output it in a separate stylesheet<\/strong>in this way:<\/p>\n<pre>&lt;head&gt;\n   ...\n   &lt;link rel=\"stylesheet\" type=\"text\/css\" href=\"\/css\/main.css\"&gt;\n   &lt;link rel=\"stylesheet\" type=\"text\/css\" href=\"\/css\/print.css\" media=\"print\"&gt;\n   ...\n&lt;\/head&gt;\n<\/pre>\n<p>In the code above the main.css file blocks the rendering of the page, so it is sent to download immediately by the preload scanner. However, the print.css file does not block it and is downloaded with low priority. So in this way <strong>we do not block the painting with the download of the printing styles<\/strong>.<\/p>\n<p>We can use this technique also with the media queries that are used to make the web responsive, but if that will negatively affect the way we organize our code, I do not recommend it.<\/p>\n<h3>Request styles in the header<\/h3>\n<p>The style sheets should be requested with link elements from the header, because apart from being their correct location, <strong>are critical resources that must be downloaded as soon as possible to paint the page<\/strong>.<\/p>\n<h3>Embed the CSS in the page only if it is too little<\/h3>\n<p>In the pages made with <a href=\"https:\/\/www.humanlevel.com\/en\/blog\/seo\/amp-accelerated-mobile-pages\" target=\"_blank\" rel=\"noopener noreferrer\">AMP<\/a> CSS code must be embedded in the page and limited to a maximum of 50,000 bytes. This technique, which also <strong>can be applied to non-AMP pages<\/strong> and it is done as follows:<\/p>\n<pre>&lt;style&gt; \/* &lt;style amp-custom&gt; si es AMP *\/ \n\/* c\u00f3digo CSS *\/ \nbody{\n    background:#0AF;\n}\n&lt;\/style&gt;\n<\/pre>\n<p>In the example I have put comments, but the code must be embedded fully minimized and without comments.<\/p>\n<p><strong>This technique means that we do not have to ask for the CSS file<\/strong>\u00a0(avoids going down to the second level in the dependency tree), but <strong>if the CSS file is too large, Google will not be able to index the bytes of the page content <\/strong>so we should only do this with small files. Ideally, this should be implemented in a way that does not hinder the normal workflow and that we do not repeat the same code across multiple pages, so we can use this technique to load the CSS that is specific to the page we are visiting and load the global CSS with the link tag.<\/p>\n<h3>Do not enter inline styles<\/h3>\n<p>If we use the <strong>style attribute<\/strong> on each element of the page to style it, we will be mixing the style with the content and duplicating the styles we use across multiple pages and elements. For this reason <strong>using this attribute is considered to be an anti-pattern of performance and maintainability<\/strong>.<\/p>\n\n<p>If it is a case where we know the style will not be repeated, <strong>we can make an exception to this rule<\/strong>. For example, we have to put a decorative background image that is only used in one place and we do it like this:<\/p>\n<p>This will make the image downloadable before we have to ask for the CSS and we will not be repeating code. Although if you don&#8217;t want to mix style and content, you can leave it cleaner by taking the style to the header inside a tag<\/p>\n<style> y poni\u00e9ndole un identificador a la capa para poder referenciarla.<\/style>\n<h3>Organize the CSS well to avoid making more rules than necessary.<\/h3>\n<p>There are many ways to <strong>organize the CSS code<\/strong> clean and elegant. There are many methodologies: <strong>ITCSS, BEM, SMACSS, SMACSS, OOCSS, SUITCSS, Atomic<\/strong>&#8230; but regardless of which one is used, the important thing is that <strong>if the code is well structured, it will be less repetitive and this will have an impact not only on maintainability but also on performance.<\/strong>.<\/p>\n<p>If when it comes down to it, there is a case where the CSS code does not fit any of the recommendations of the method used, I recommend inventing new rules of your own so that the organization is not lost.<\/p>\n<h3>Avoid complex HTML<\/h3>\n<p><strong>No need to assign styles by creating new HTML elements<\/strong> instead of identifiers and classes, <strong>nor create HTML elements that are not necessary<\/strong> neither to give style, nor to provide semantic information.<\/p>\n<p>This is because if we have fewer DOM nodes, the DOM will load sooner, take up less memory and, consequently, the CSSOM will be less complex. In addition, by using identifiers and classes, we will have more efficient CSS selectors.<\/p>\n<h3>Source optimization<\/h3>\n<p>The sources <strong>are a critical resource that blocks the painting of texts on the page.<\/strong>. While downloading the font, some browsers will display the page with a system font and others will display it without text. At the end of the download, the user sees the font change or appear, which does not create a good impression.<\/p>\n<p>This is a topic that requires a separate entry, but in broad strokes I will say that <strong>do not load more sources than necessary<\/strong>Whether they are variants of the same font (different thicknesses of bold, italic, bold and italic, &#8230;) or character sets that we are not going to use in the language of the current page. <strong>Use Gzip or Brotli compression only with older EOT and TTF formats. <\/strong>(not with WOFF or WOFF2 because they are already compressed) and if you want to control how the source is loaded, use the <strong>Font Loading JavaScript API<\/strong>.<\/p>\n<p>We can also preload them from the HTML like this:<\/p>\n<pre>&lt;link rel=\"preload\" href=\"fonts\/cicle_fina-webfont.woff\" as=\"font\" type=\"font\/woff\" crossorigin=\"anonymous\"&gt;<\/pre>\n<p><a href=\"https:\/\/www.humanlevel.com\/en\/blog\/seo\/how-to-optimize-the-fonts-of-a-website\" target=\"_blank\" rel=\"noopener noreferrer\">This article provides more information on how to optimize the fonts of a Web site<\/a>.<\/p>\n<h2>Optimize painting<\/h2>\n<h3>Avoid CSS expressions<\/h3>\n<p>CSS expressions allow you to calculate property values using JavaScript. This, in addition to violating the separation of behavior and style, <strong>is very inefficient for the browser<\/strong>. So it is better to replace these expressions with JavaScript.<\/p>\n<h3>Create animations with CSS rather than JavaScript<\/h3>\n<p>With CSS animations you can make animations by creating <strong>interpolations between property values over a series of keyframes<\/strong>as was done with Flash. For those who do not know what I mean, interpolating is the mathematical operation of calculating the intermediate values between several given values. In this case it allows to calculate the values of the CSS properties along the key points set so that the browser can perform the animation. Ideally, you should use only the <em>transform<\/em> which allows us to rotate, move, enlarge or stretch any layer and the property <em>opacity<\/em>to make transparencies.<\/p>\n<p>In addition to using only the properties <em>transform<\/em> y <em>opacity<\/em>I recommend to do it with layers that have fixed or absolute position (to avoid that the animation displaces the rest of the layers), because in this way <strong>the navigator is prevented from launching reflow and painting<\/strong>and you only need to run the <strong>composition of the layers<\/strong>.<\/p>\n<p>Example:<\/p>\n<pre>&lt;style&gt;\n#animated_div_wrap{\n    position: relative;\n    height: 70px;\n}\n\n#animated_div {\n    position: absolute;\n    width: 70px;\n    height: 47px;\n    box-sizing: border-box;\n    background: #ba1c1e;\n    color: #ffffff;\n    font-weight: bold;\n    font-size: 20px;\n    padding: 10px;\n    animation: animated_div 5s infinite;\n    border-radius: 5px;\n}\n\n@keyframes animated_div\n{\n    0% {\n        transform: rotate(0deg);\n    }\n    25% {\n        transform: rotate(-5deg);\n    }\n    50% {\n        transform: translateX(320px) rotate(-20deg);\n    }\n    100% {\n        transform: translateX(0px) rotate(-360deg);\n    }\n}\n&lt;\/style&gt;\n\n&lt;div id=\"animated_div_wrap\"&gt;\n       &lt;div id=\"animated_div\"&gt;WPO&lt;\/div&gt;\n&lt;\/div&gt;\n<\/pre>\n<p>Result:<\/p>\n<div id=\"style_animated\"><\/div>\n<div id=\"animated_div_wrap\">\n<div id=\"animated_div\">WPO<\/div>\n<\/div>\n<p><script>var style_animated=document.getElementById(\"style_animated\");style_animated.innerHTML=\"<\"+\"style\"+\">#animated_div_wrap{position:relative;height:70px;}#animated_div{position:absolute;width:70px;height:47px;box-sizing:border-box;background:#ba1c1e;color:#ffffff;font-weight:bold;font-size:20px;padding:10px;animation:animated_div 5s infinite;border-radius: 5px;}@keyframes animated_div{0%{transform:rotate(0deg);}25%{transform:rotate(-5deg);}50%{transform:translateX(320px)rotate(-20deg);} 100% {transform: translateX(0px) rotate(-360deg);}}<\"+\"\/style\"+\">\";<\/script><br \/>\nMake <strong>the same animation with JavaScript would be much less efficient<\/strong> because it would be executed in the JavaScript thread along with many other things and <strong>browser is optimized to run CSS animations<\/strong> smoothly, prioritizing speed over smoothness. The latter means that if an animation consists of shifting a layer 1000 pixels to the right in one second, in which we have to display 60 frames, the layer will be shifted by 16 pixels in each frame. But if the browser only has time to paint half of the frames, the layer will move 32 pixels at each repaint.<\/p>\n<h3>Avoid reflow and repainting by specifying the image proportions with an overlay<\/h3>\n<p>When a page is painted, <strong>some images may load at the end<\/strong>making it necessary to <strong>displace everything underneath<\/strong> of these when they have already been loaded. To avoid these jumps, <strong>each image must be contained in a layer that occupies the same height that the image will occupy when it is finished loading<\/strong>. This must be implemented taking into account that the image will have different sizes depending on the device and is done as indicated below:<br \/>\nFirst, the ratio of image height to width is calculated:<\/p>\n<p>Ratio height = height\/width * 100<\/p>\n<p>This gives us a percentage that we will set to the &#8220;padding-top&#8221; property of a layer before the image, that way this layer will occupy the height of the image independently of the width modification. The image will have absolute position relative to a containing layer so that it is mounted on top of the layer that sets the height. Let&#8217;s look at an example:<\/p>\n<pre>&lt;style&gt;\n#wrap-img-ej{\n   position:relative;\n   max-width:800px;\n}\n\n#wrap-img-e div{\n   padding-top:56.25%;\n}\n\n#wrap-img-e img{\n   position:absolute;\n   top:0;\n}\n&lt;style&gt;\n&lt;div id=\"wrap-img-ej\"&gt;\n   &lt;div&gt;&lt;\/div&gt;\n   &lt;img src=\"\/img\/imagen.jpg\" alt=\"texto SEO\" \/&gt;\n&lt;\/div&gt;\n<\/pre>\n<p><strong>This technique should also be applied to sliders and carousels<\/strong>, where it is frequent that when JavaScript is executed, it causes a jump in the initial load.<\/p>\n<p>To make the use of this technique more agile, we can create a template of the example code above with a web component or directly use the <strong>web component amp-img<\/strong> from the AMP component library. The equivalent code to the previous example with the AMP component would be as follows:<\/p>\n<pre>&lt;amp-img alt=\"texto SEO\" src=\"\/img\/imagen.jpg\" width=\"800\" height=\"450\" layout=\"responsive\"&gt;&lt;\/amp-img&gt;\n<\/pre>\n<h3>If there is an identifier in the selector, there is no need to complicate it unnecessarily.<\/h3>\n<p>Let&#8217;s say we have a rule with a selector like the following:<\/p>\n<pre>div .clase1 #mi-id.clase2{ \n    background:red; \n}\n<\/pre>\n<p>With this HTML:<\/p>\n<pre>&lt;div&gt;\n    &lt;div class=\"clase1\"&gt;\n        &lt;div id=\"mi-id\" class=\"clase2\"&gt;\n            &lt;div class=\"clase3\"&gt;WPO&lt;\/div&gt;\n            &lt;div&gt;CSS&lt;\/div&gt;\n        &lt;\/div&gt;\n    &lt;\/div&gt;\n&lt;\/div&gt;\n<\/pre>\n<p>This selector doesn&#8217;t make much sense because in reality there can only be one &#8220;my-id&#8221; identifier on the page, so <strong>the following selector will work exactly the same and has less code, so it takes less time to load and run<\/strong>:<\/p>\n<pre>#mi-id{ \n    background:red; \n}\n<\/pre>\n<p>By this I do not mean that when there is an identifier in the rule, all other identifiers must be systematically removed. The following selector does make sense:<\/p>\n<pre>#mi-id .clase3{ \n    background:blue; \n}\n<\/pre>\n<h3>Use translateZ to make the browser use GPU graphics acceleration<\/h3>\n<p>On layers with animations or simply with transparency (opacity property), <strong>use will-change:transform; or translateZ(0), to promote the layer to the GPU hardware where it will be painted faster<\/strong>. But <strong>avoid overusing these rules<\/strong> promotion to the GPU, as the layers require memory and management by the browser.<\/p>\n<p>will-change: transform;<br \/>\ntransform: translateZ(0);<\/p>\n<p>The two properties will have the same effect, but &#8220;translateZ(0);&#8221;, with which we say to make a shift in the Z axis to the initial position, works in all browsers, while will-change, is the correct way to implement it because it does not modify layer properties.<\/p>\n<h3>Grouping several transformations in a rotation matrix<\/h3>\n<p>The transformations of a vector object are implemented by multiplying the vector of each vertex of the object by a matrix that gives the final position of each vertex. This matrix defines the type of transformation we are going to apply (position, scale, rotation, &#8230;). This is what happens internally in the browser when we apply a two-dimensional or three-dimensional transformation to a CSS layer with the transform property.<\/p>\n<p><strong>If we multiply all the matrices that generate the transformations we are going to do, either position, scale, rotation or deformation, we can apply them all at the same time in one step with the resulting matrix<\/strong>writing much less code and in a computationally more optimal way, since we will use the matrix function like this: transform:matrix(a11, a21, a12, a22, a13, a14) instead of something like transform:transform(x,y) skew(x,y) rotate(x,y) scale(x,y). If it is a 3D transformation we will use matrix3D instead of matrix. In addition, this function allows us to make the mirror effect transformation that cannot be done in any other way:<\/p>\n<div style=\"transform: matrix(-1, 0, 0,1, 0, 0); font-size: 20px; width: 100px;\">WPO CSS<\/div>\n<p>For the quick calculation of the transformation matrix (it is not easy to do it upside down), it will be necessary to use some Sass library, program or function to calculate it quickly, always keeping in mind that transformations, like matrix multiplication, are not commutative (translate and rotate is not the same as rotate and translate).<\/p>\n<figure id=\"attachment_30714\" aria-describedby=\"caption-attachment-30714\" style=\"width: 502px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" class=\"size-full wp-image-30714\" src=\"https:\/\/www.humanlevel.com\/wp-content\/uploads\/2D_affine_transformation_matrix.svg_.png\" alt=\"2D transformation matrices\" width=\"512\" height=\"683\" srcset=\"https:\/\/www.humanlevel.com\/wp-content\/uploads\/2D_affine_transformation_matrix.svg_.png 512w, https:\/\/www.humanlevel.com\/wp-content\/uploads\/2D_affine_transformation_matrix.svg_-400x534.png 400w\" sizes=\"auto, (max-width: 512px) 100vw, 512px\" \/><figcaption id=\"caption-attachment-30714\" class=\"wp-caption-text\">2D transformation matrices<\/figcaption><\/figure>\n<h3>Simplifying the complexity of effects that are difficult to represent<\/h3>\n<p><strong>The filter property is computationally expensive<\/strong> to apply when used for blurring, contrast changes, brightness changes, etc. However, it can be a good ally to avoid loading more images, if we want to apply some of these effects when passing the mouse over one of them.<\/p>\n<p>Other costly painting effects, <strong>are shadows and gradients<\/strong>. If you have these effects and find that the final painting stage of the page takes too long, try removing them.<\/p>\n<h3>Use CSS before images<\/h3>\n<p>In general, it will always be faster to paint something with CSS than to use an equivalent image, since the <strong>image has a download, reading, decompression and painting time that usually exceeds the download and painting time of CSS<\/strong>. Therefore, if you cannot simplify the design, as indicated in the previous point, you should not replace, for example, a text shadow with CSS by its equivalent image.<\/p>\n<h3>Do not layout with tables<\/h3>\n<p>This seems like a recommendation from the prehistory of the web, but it is still true and even more so if we want a good performance.<\/p>\n<p><strong>Tables are inefficient<\/strong> because a change in the size of a cell affects the position of all elements below it and, if it changes in width, may also affect cells above it.<\/p>\n<h3>Layout with grid layout and flexbox<\/h3>\n<p>Use <strong>Grid Layout and\/or flexbox<\/strong> is more optimal and flexible than layout with floating layers and, of course, than with tables. Here we can make use of a framework such as Bootstrap, which in version 4 already uses flexboxes.<\/p>\n<p>With this new way of layout you have the advantage of being able to visually change the location of any element, regardless of the order in which it is being painted in the HTML, with greater freedom than with floating layers. <strong>This allows us to have a totally different layout on mobile and desktop and, to leave above the HTML, the first thing we want to be indexed for SEO purposes.<\/strong>.<\/p>\n<h3>Avoid extremely complex selectors<\/h3>\n<p>Normally, <strong>in automatic tools it is suggested to avoid complex selectors <\/strong>but <strong>I do not recommend paying much attention to this rule because code maintainability is always more important than performance<\/strong>. So my recommendation is <strong>avoid only extremely complex selectors<\/strong>It is very rare that something as inefficient as this has to be done:<\/p>\n<pre>div p a *{}<\/pre>\n<p>To know when a selector is complex or inefficient we must take into account that <strong>the most general parts of the selector<\/strong> (the elements) <strong>are less efficient than more specific ones<\/strong> (identifiers). We must also understand that <strong>selectors are interpreted from right to left<\/strong>so have <strong>the more general parts of the selector further to the right makes the rule more inefficient,<\/strong> because this causes the browser to have to examine more parts of the DOM to know if it has to apply the rule. In the example above the * operator selects all the elements on the page, then looks to see if all the predecessors of all the elements on the page have a link, then looks to see if all those links have a predecessor p element, and so on, unless at some point no element is found, in which case the selector check stops.<\/p>\n<p>CSS3 pseudo-elements and pseudo-classes are also slow (:first-child, :nth-child(), ::firts-line, ::first-letter).<\/p>\n<h2>Tools<\/h2>\n<p>Use the tools to <strong>Chrome and Firefox developers to analyze loading and painting times<\/strong>by adjusting the tests to see what happens on devices with more limited processing power and a slower network. In Google Chrome&#8217;s developer tools, the latter options appear by clicking on the red gear to the right of the &#8220;Performance&#8221; tab. Here, in addition, we have the option &#8220;Enable advanced paint instrumentation&#8221; that allows us to see the &#8220;Paint Profiler&#8221; tab when clicking on a paint event. This way we can see everything the browser needs to do to paint our page:<\/p>\n<figure id=\"attachment_30703\" aria-describedby=\"caption-attachment-30703\" style=\"width: 692px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" class=\"wp-image-30703 size-full\" src=\"https:\/\/www.humanlevel.com\/wp-content\/uploads\/paint-profilers.png\" alt=\"Google Chrome developer tools painting profile browser\" width=\"702\" height=\"851\" srcset=\"https:\/\/www.humanlevel.com\/wp-content\/uploads\/paint-profilers.png 702w, https:\/\/www.humanlevel.com\/wp-content\/uploads\/paint-profilers-400x485.png 400w\" sizes=\"auto, (max-width: 702px) 100vw, 702px\" \/><figcaption id=\"caption-attachment-30703\" class=\"wp-caption-text\">In the Google Chrome developer tools and in the performance tab, we can examine what is happening in painting in the &#8220;Paint Profiler&#8221;.<\/figcaption><\/figure>\n<p>To study the speed of CSS and also how it is affected by JavaScript, it is very useful to use the <strong>options of the <a href=\"https:\/\/www.humanlevel.com\/en\/digital-marketing-dictionary\/rendering\" target=\"_blank\" rel=\"noopener noreferrer\">rendering<\/a> tab<\/strong>. The software is also equipped with a number of other tools, which show us, among other things, in real time, which rectangles are being repainted on the page and the speed in FPS at which they are being painted. This option can be obtained by clicking on the same screen we see in the previous screenshot, on the three dots at the top right and clicking on &#8220;Show console drawer&#8221; and clicking on the &#8220;Rendering&#8221; tab:<\/p>\n<figure id=\"attachment_30704\" aria-describedby=\"caption-attachment-30704\" style=\"width: 692px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" class=\"wp-image-30704 size-full\" src=\"https:\/\/www.humanlevel.com\/wp-content\/uploads\/opciones-de-renderizado.png\" alt=\"Chrome devtools rendering options to see in real time how moving scroll or animations affect.\" width=\"702\" height=\"765\" srcset=\"https:\/\/www.humanlevel.com\/wp-content\/uploads\/opciones-de-renderizado.png 702w, https:\/\/www.humanlevel.com\/wp-content\/uploads\/opciones-de-renderizado-400x436.png 400w\" sizes=\"auto, (max-width: 702px) 100vw, 702px\" \/><figcaption id=\"caption-attachment-30704\" class=\"wp-caption-text\">Options in the &#8220;rendering&#8221; tab of the Chrome developer tools to see in real time how it affects moving scroll or animations.<\/figcaption><\/figure>\n<h2>Final recommendations<\/h2>\n<p>It is important to <strong>always prioritize maintainability over performance<\/strong>. Therefore, I recommend to always write the code as cleanly as possible, using some organization methodology, giving relevant names to classes and identifiers and, if you make the mistake of not using a preprocessor, at least put all tabs, line breaks and spaces, because later you will be able to minimize the code with a tool.<\/p>\n<p>Always keep in mind the <strong>Amdhal law <\/strong> which reads as follows:<\/p>\n<blockquote><p>The improvement obtained in the performance of a system due to the alteration of one of its components is limited by the fraction of time that component is used.<\/p><\/blockquote>\n<p>This means that <strong>optimization of the most time-consuming part should always be prioritized. <\/strong>The most significant impact on the overall performance will be on the overall performance.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this CSS optimization guide, we are going to look at what is necessary for the downloading and painting of&#8230;<\/p>\n","protected":false},"author":14,"featured_media":47807,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[349],"tags":[534,379],"class_list":["post-52130","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-seo","tag-technical-seo","tag-wpo"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>CSS optimization | Human Level<\/title>\n<meta name=\"description\" content=\"Find out how to optimize CSS downloading, rendering and inpainting to improve the performance of your website with this article.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"CSS optimization | Human Level\" \/>\n<meta property=\"og:description\" content=\"Find out how to optimize CSS downloading, rendering and inpainting to improve the performance of your website with this article.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization\" \/>\n<meta property=\"og:site_name\" content=\"Human Level\" \/>\n<meta property=\"article:published_time\" content=\"2018-03-12T07:00:59+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-05-30T07:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.humanlevel.com\/wp-content\/uploads\/optimizacion-css-1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"400\" \/>\n\t<meta property=\"og:image:height\" content=\"400\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Ram\u00f3n Saquete\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@daiatron\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Ram\u00f3n Saquete\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"27 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":[\"Article\",\"BlogPosting\"],\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/blog\\\/seo\\\/css-optimization#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/blog\\\/seo\\\/css-optimization\"},\"author\":{\"name\":\"Ram\u00f3n Saquete\",\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en#\\\/schema\\\/person\\\/11ad888926867985985a0210476bae94\"},\"headline\":\"CSS optimization\",\"datePublished\":\"2018-03-12T07:00:59+00:00\",\"dateModified\":\"2023-05-30T07:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/blog\\\/seo\\\/css-optimization\"},\"wordCount\":5524,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/blog\\\/seo\\\/css-optimization#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.humanlevel.com\\\/wp-content\\\/uploads\\\/optimizacion-css-1.png\",\"keywords\":[\"Technical SEO\",\"WPO\"],\"articleSection\":[\"SEO\\\/GEO\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/blog\\\/seo\\\/css-optimization#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/blog\\\/seo\\\/css-optimization\",\"url\":\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/blog\\\/seo\\\/css-optimization\",\"name\":\"CSS optimization | Human Level\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/blog\\\/seo\\\/css-optimization#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/blog\\\/seo\\\/css-optimization#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.humanlevel.com\\\/wp-content\\\/uploads\\\/optimizacion-css-1.png\",\"datePublished\":\"2018-03-12T07:00:59+00:00\",\"dateModified\":\"2023-05-30T07:00:00+00:00\",\"description\":\"Find out how to optimize CSS downloading, rendering and inpainting to improve the performance of your website with this article.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/blog\\\/seo\\\/css-optimization#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/blog\\\/seo\\\/css-optimization\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/blog\\\/seo\\\/css-optimization#primaryimage\",\"url\":\"https:\\\/\\\/www.humanlevel.com\\\/wp-content\\\/uploads\\\/optimizacion-css-1.png\",\"contentUrl\":\"https:\\\/\\\/www.humanlevel.com\\\/wp-content\\\/uploads\\\/optimizacion-css-1.png\",\"width\":400,\"height\":400},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/blog\\\/seo\\\/css-optimization#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Inicio\",\"item\":\"https:\\\/\\\/www.humanlevel.com\\\/en\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Blog\",\"item\":\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/blog\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"SEO\\\/GEO\",\"item\":\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/blog\\\/seo\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"CSS optimization\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en#website\",\"url\":\"https:\\\/\\\/www.humanlevel.com\\\/en\",\"name\":\"Human Level\",\"description\":\"Web positioning and online marketing consultant Human Level\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.humanlevel.com\\\/en?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en#organization\",\"name\":\"Human Level\",\"url\":\"https:\\\/\\\/www.humanlevel.com\\\/en\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.humanlevel.com\\\/wp-content\\\/uploads\\\/logohl25x3.png\",\"contentUrl\":\"https:\\\/\\\/www.humanlevel.com\\\/wp-content\\\/uploads\\\/logohl25x3.png\",\"width\":600,\"height\":93,\"caption\":\"Human Level\"},\"image\":{\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.linkedin.com\\\/company\\\/human-level-communications\",\"https:\\\/\\\/www.youtube.com\\\/user\\\/humanlevelcommunica\",\"https:\\\/\\\/bsky.app\\\/profile\\\/humanlevel.bsky.social\",\"https:\\\/\\\/instagram.com\\\/humanlevel\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/en#\\\/schema\\\/person\\\/11ad888926867985985a0210476bae94\",\"name\":\"Ram\u00f3n Saquete\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.humanlevel.com\\\/wp-content\\\/uploads\\\/1x1-ramon-saquete-26-96x96.jpg\",\"url\":\"https:\\\/\\\/www.humanlevel.com\\\/wp-content\\\/uploads\\\/1x1-ramon-saquete-26-96x96.jpg\",\"contentUrl\":\"https:\\\/\\\/www.humanlevel.com\\\/wp-content\\\/uploads\\\/1x1-ramon-saquete-26-96x96.jpg\",\"caption\":\"Ram\u00f3n Saquete\"},\"description\":\"Web Developer and Technical SEO Consultant at Human Level. He holds degrees in Computer Engineering and Technical Engineering in Computer Systems. He also earned a Higher Vocational Degree in Computer Applications Development and later obtained the Certificate of Pedagogical Aptitude (CAP). He is an expert in WPO and indexability.\",\"sameAs\":[\"https:\\\/\\\/es.linkedin.com\\\/in\\\/ramonsaquete\",\"https:\\\/\\\/x.com\\\/daiatron\"],\"url\":\"https:\\\/\\\/www.humanlevel.com\\\/en\\\/author\\\/ramon\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"CSS optimization | Human Level","description":"Find out how to optimize CSS downloading, rendering and inpainting to improve the performance of your website with this article.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization","og_locale":"en_US","og_type":"article","og_title":"CSS optimization | Human Level","og_description":"Find out how to optimize CSS downloading, rendering and inpainting to improve the performance of your website with this article.","og_url":"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization","og_site_name":"Human Level","article_published_time":"2018-03-12T07:00:59+00:00","article_modified_time":"2023-05-30T07:00:00+00:00","og_image":[{"width":400,"height":400,"url":"https:\/\/www.humanlevel.com\/wp-content\/uploads\/optimizacion-css-1.png","type":"image\/png"}],"author":"Ram\u00f3n Saquete","twitter_card":"summary_large_image","twitter_creator":"@daiatron","twitter_misc":{"Written by":"Ram\u00f3n Saquete","Est. reading time":"27 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":["Article","BlogPosting"],"@id":"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization#article","isPartOf":{"@id":"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization"},"author":{"name":"Ram\u00f3n Saquete","@id":"https:\/\/www.humanlevel.com\/en#\/schema\/person\/11ad888926867985985a0210476bae94"},"headline":"CSS optimization","datePublished":"2018-03-12T07:00:59+00:00","dateModified":"2023-05-30T07:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization"},"wordCount":5524,"commentCount":0,"publisher":{"@id":"https:\/\/www.humanlevel.com\/en#organization"},"image":{"@id":"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization#primaryimage"},"thumbnailUrl":"https:\/\/www.humanlevel.com\/wp-content\/uploads\/optimizacion-css-1.png","keywords":["Technical SEO","WPO"],"articleSection":["SEO\/GEO"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization","url":"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization","name":"CSS optimization | Human Level","isPartOf":{"@id":"https:\/\/www.humanlevel.com\/en#website"},"primaryImageOfPage":{"@id":"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization#primaryimage"},"image":{"@id":"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization#primaryimage"},"thumbnailUrl":"https:\/\/www.humanlevel.com\/wp-content\/uploads\/optimizacion-css-1.png","datePublished":"2018-03-12T07:00:59+00:00","dateModified":"2023-05-30T07:00:00+00:00","description":"Find out how to optimize CSS downloading, rendering and inpainting to improve the performance of your website with this article.","breadcrumb":{"@id":"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization#primaryimage","url":"https:\/\/www.humanlevel.com\/wp-content\/uploads\/optimizacion-css-1.png","contentUrl":"https:\/\/www.humanlevel.com\/wp-content\/uploads\/optimizacion-css-1.png","width":400,"height":400},{"@type":"BreadcrumbList","@id":"https:\/\/www.humanlevel.com\/en\/blog\/seo\/css-optimization#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Inicio","item":"https:\/\/www.humanlevel.com\/en"},{"@type":"ListItem","position":2,"name":"Blog","item":"https:\/\/www.humanlevel.com\/en\/blog"},{"@type":"ListItem","position":3,"name":"SEO\/GEO","item":"https:\/\/www.humanlevel.com\/en\/blog\/seo"},{"@type":"ListItem","position":4,"name":"CSS optimization"}]},{"@type":"WebSite","@id":"https:\/\/www.humanlevel.com\/en#website","url":"https:\/\/www.humanlevel.com\/en","name":"Human Level","description":"Web positioning and online marketing consultant Human Level","publisher":{"@id":"https:\/\/www.humanlevel.com\/en#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.humanlevel.com\/en?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.humanlevel.com\/en#organization","name":"Human Level","url":"https:\/\/www.humanlevel.com\/en","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.humanlevel.com\/en#\/schema\/logo\/image\/","url":"https:\/\/www.humanlevel.com\/wp-content\/uploads\/logohl25x3.png","contentUrl":"https:\/\/www.humanlevel.com\/wp-content\/uploads\/logohl25x3.png","width":600,"height":93,"caption":"Human Level"},"image":{"@id":"https:\/\/www.humanlevel.com\/en#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.linkedin.com\/company\/human-level-communications","https:\/\/www.youtube.com\/user\/humanlevelcommunica","https:\/\/bsky.app\/profile\/humanlevel.bsky.social","https:\/\/instagram.com\/humanlevel"]},{"@type":"Person","@id":"https:\/\/www.humanlevel.com\/en#\/schema\/person\/11ad888926867985985a0210476bae94","name":"Ram\u00f3n Saquete","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.humanlevel.com\/wp-content\/uploads\/1x1-ramon-saquete-26-96x96.jpg","url":"https:\/\/www.humanlevel.com\/wp-content\/uploads\/1x1-ramon-saquete-26-96x96.jpg","contentUrl":"https:\/\/www.humanlevel.com\/wp-content\/uploads\/1x1-ramon-saquete-26-96x96.jpg","caption":"Ram\u00f3n Saquete"},"description":"Web Developer and Technical SEO Consultant at Human Level. He holds degrees in Computer Engineering and Technical Engineering in Computer Systems. He also earned a Higher Vocational Degree in Computer Applications Development and later obtained the Certificate of Pedagogical Aptitude (CAP). He is an expert in WPO and indexability.","sameAs":["https:\/\/es.linkedin.com\/in\/ramonsaquete","https:\/\/x.com\/daiatron"],"url":"https:\/\/www.humanlevel.com\/en\/author\/ramon"}]}},"_links":{"self":[{"href":"https:\/\/www.humanlevel.com\/en\/wp-json\/wp\/v2\/posts\/52130","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.humanlevel.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.humanlevel.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.humanlevel.com\/en\/wp-json\/wp\/v2\/users\/14"}],"replies":[{"embeddable":true,"href":"https:\/\/www.humanlevel.com\/en\/wp-json\/wp\/v2\/comments?post=52130"}],"version-history":[{"count":8,"href":"https:\/\/www.humanlevel.com\/en\/wp-json\/wp\/v2\/posts\/52130\/revisions"}],"predecessor-version":[{"id":53285,"href":"https:\/\/www.humanlevel.com\/en\/wp-json\/wp\/v2\/posts\/52130\/revisions\/53285"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.humanlevel.com\/en\/wp-json\/wp\/v2\/media\/47807"}],"wp:attachment":[{"href":"https:\/\/www.humanlevel.com\/en\/wp-json\/wp\/v2\/media?parent=52130"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.humanlevel.com\/en\/wp-json\/wp\/v2\/categories?post=52130"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.humanlevel.com\/en\/wp-json\/wp\/v2\/tags?post=52130"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}