{"id":6665,"date":"2021-11-16T17:52:31","date_gmt":"2021-11-16T17:52:31","guid":{"rendered":"https:\/\/www.terluinwebdesign.nl\/en\/?p=6665"},"modified":"2025-07-18T14:51:29","modified_gmt":"2025-07-18T14:51:29","slug":"remove-unused-css-classes-automatically","status":"publish","type":"post","link":"https:\/\/www.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/","title":{"rendered":"Remove unused CSS classes automatically"},"content":{"rendered":"<pre><prevent-autop><div class=\"row all d__content-in-narrow-container t__content-in-container m__content-in-container\" data-cache-vw-d=\"1512\" data-cache-h-d=\"18249.7890625\" data-cache-vw-t=\"617\" data-cache-h-t=\"14817.203125\" data-cache-vw-m=\"462\" data-cache-h-m=\"29556.1796875\"><div class=\"col all\"><p>This article focuses on how to <strong>remove unused CSS classes<\/strong>, but the same methods can apply to <strong>tag names<\/strong> as well.&nbsp;You can even <strong>optimize your JavaScript<\/strong> with the resources, after you\u2019ve implemented the solution that I will explain in this article.<\/p><p>However, instead of removing unused JavaScript code, you conditionally add JavaScript code by looking in the list of used classes (using PHP code).<\/p><p>Removing unused CSS and JavaScript will definitely help a lot for your Core Web Vitals optimization.<\/p><p>The code shown in this article is not ready-to-use; you should modify it. The code is meant to give you an idea of how you can remove unused CSS classes by yourself.<\/p><aside class=\"row all bg-yellow__light v-center h-center c half-row-gap d__pad-top-s t__pad-top-m m__pad-top-m d__pad-bottom-s t__pad-bottom-m m__pad-bottom-m d__in-narrow-container wrap t__vertical m__vertical t__in-container m__in-container\" data-cache-vw-d=\"1512\" data-cache-h-d=\"80.203125\" data-cache-vw-t=\"617\" data-cache-h-t=\"116.9375\" data-cache-vw-m=\"462\" data-cache-h-m=\"247.125\"><div class=\"col all d__mar-right-0 d__mar-bottom-0 t__mar-bottom-s m__mar-bottom-s\"><p class=\"wrap-balance anim-fade-in\"><b class=\"h6-size\">Professional AI-built website, no setup costs, for only \u20ac49\/month<\/b><\/p><\/div><div class=\"col all mar-bottom-0 w-auto\"><a class=\"button anim-fade-in bor-pitch-black__light txt-pitch-black-hover__light bg-transparent-hover__light bor-pitch-black-hover__light bg-pitch-black__light txt-yellow__light bg-pitch-black__dark txt-yellow__dark bor-pitch-black__dark bg-transparent-hover__dark txt-pitch-black-hover__dark bor-pitch-black-hover__dark d__h6-size t__h6-size w-auto pad-left-s pad-right-s pad-bottom-xs pad-top-xs\" href=\"https:\/\/www.terluinwebdesign.nl\/en\/ai-website-builder\/\"><span>AI Site Builder<\/span><\/a><\/div><\/aside><h2>Tracking used classes by pages<\/h2><p>What you have to do first is create two JSON files:<\/p><ol><li>Filename: <code>classes-by-page-id.json<\/code><br>Contents: <code>{}<\/code><\/li><li>Filename: <code>classes-by-pages.json<\/code><br>Contents: <code>[]<\/code><\/li><\/ol><p>The first file will contain what classes are used by which page (ID of page).<\/p><p>All classes from the first JSON file are merged into a single list of classes and are put into the second JSON file (<code>classes-by-pages.json<\/code>).<\/p><p>In order for the fact that you need two files to make sense, I\u2019ll have to tell you that the CSS file that you are going to optimize, has to make use of a version-parameter.<\/p><p>The value for the version parameter is equal to when the second file (<code>classes-by-pages.json<\/code>) has been last modified as a Unix timestamp, for instance: <code>?v=1636559118<\/code>.<\/p><p>If you keep modifying the file, even though the contents are the same (no new classes, and no removed CSS classes), then the version changes too often.<\/p><p>Another reason is that if a page is removed, or when it doesn\u2019t use a certain class anymore, how are you supposed to know whether or not other pages might still use it; just by looking at the contents of the second JSON file (<code>classes-by-pages.json<\/code>)?<\/p><p>That\u2019s right, you can\u2019t. Actually, you can, but then you have to query the whole database for all pages to look for classes inside of the content, every time you update a page.<\/p><p>Obviously, the latter is very inefficient and will not catch all classes either.<\/p><h3>Getting all classes from the page<\/h3><p>Whenever you update a page, the content is sent through either POST or AJAX. What you have to do is put all elements\u2019 classes into an array, convert it to a JSON string and store it in an input field or send it along with the AJAX call.<\/p><tw-pre><code class=\"js-code\">var allUsedClasses = [];\r\npageContent.querySelectorAll('[class]').forEach(function(el) {\r\n  el.classList.forEach(function(elClass) {\r\n    if(!allUsedClasses.includes(elClass)) {\r\n      allUsedClasses.push(elClass);\r\n    }\r\n  });\r\n});\r\ninputFieldForUsedClasses.value = JSON.stringify(allUsedClasses);<\/code><\/tw-pre><p>Variable <code>pageContent<\/code> refers to the element that wraps the content that is specific to the page, not the elements surrounding it: header, footer, etc. This is to prevent classes that are added by template files, from being added to the classes added by pages.<\/p><p>I will discuss how to keep track of classes added by template files not much further into this article. It is more complicated and it takes way more effort than keeping track of classes added by pages, as those are mostly static.<\/p><h3>Updating the first JSON file (classes-by-page-id.json)<\/h3><p>Since you\u2019ve received the list of classes used by the page to be updated, you should now create an empty array. That array should contain lists of classes, by page ID.<\/p><p>The array should store the new list of classes for the page to be updated, which is easy as you\u2019ve just received that list through either POST or an AJAX call.<\/p><p>Then, the updated array of classes by page should be converted to a JSON string, and will then be the new content for the first JSON file (<code>classes-by-page-id.json<\/code>).<\/p><tw-pre><code class=\"php-code\">$currentPageID = $_POST['page_id'];\r\n$usedClassesByCurrentPage = $_POST['used_classes'];\r\n\r\n$filePathUsedClassesByPage = 'classes-by-page-id.json';\r\n$jsonUsedClassesByPage = json_decode (\r\n  file_get_contents($filePathUsedClassesByPage),\r\n  true\r\n);\r\n$jsonUsedClassesByCurrentPage = json_decode (\r\n  $usedClassesByCurrentPage,\r\n  true\r\n);\r\n\r\n$jsonUsedClassesByPage[$currentPageID] = $jsonUsedClassesByCurrentPage;\r\n$jsonStringUsedClassesByPage = json_encode($jsonUsedClassesByPage);\r\n\r\nfile_put_contents($filePathUsedClassesByPage, $jsonStringUsedClassesByPage);<\/code><\/tw-pre><h3>Deciding whether or not to update the second JSON file<\/h3><p>The second JSON file should, as I said, only be updated if the content of the file is about to be changed. To do this, all you have to do is create a sorted list of unique classes, convert it to a JSON string, and compare it to the contents of the second JSON file.<\/p><tw-pre><code class=\"php-code\">$filePathUsedClasses = 'classes-by-pages.json';\r\n$jsonStringPreviouslyUsedClasses = file_get_contents($filePathUsedClasses);\r\n$usedClasses = [];\r\n\r\nforeach($jsonUsedClassesByPage as $pageID =&gt; $usedClassesByThisPage) {\r\n  if($currentPageID !== $pageID) {\r\n    array_push (\r\n      $usedClasses,\r\n      ...$usedClassesByThisPage\r\n    );\r\n  }\r\n}\r\narray_push (\r\n  $usedClasses,\r\n  ...$jsonUsedClassesByCurrentPage\r\n);\r\n$usedClasses = array_values(array_unique($usedClasses));\r\nsort($usedClasses);\r\n$jsonStringUsedClasses = json_encode($usedClasses);\r\n\r\nif($jsonStringPreviouslyUsedClasses !== $jsonStringUsedClasses) {\r\n  file_put_contents($filePathUsedClasses, $jsonStringUsedClasses);\r\n} else {\r\n  \/\/ nothing changed, so don't update the JSON file (classes-by-pages.json)\r\n}\r\n\r\n$lastModifiedClassesByTemplates = filemtime($filePathClassesByTemplates);<\/code><\/tw-pre><h2>Tracking classes added by template files<\/h2><p>After keeping track of all classes by pages, I came across the problem that some pages are generated using template files. Product pages, for instance, add classes as well. But wait, there is more: classes they add can also depend on the situation.<\/p><p>For example, a shopping cart with items might add classes for those items. Now, what is going to happen if the shopping cart is empty? Well, then it does not add those classes, and then guess what.. there will be a difference in the list of classes added by template files.<\/p><p>To prevent that from happening, I used suffixes to append to the file path of the template file when saving the classes added by every template file.<\/p><p>All classes added within the if-statement that executes whenever there are items in the cart, will be added to an array with the key <code>\/some_path\/cart.php<strong>:not_empty<\/strong><\/code>.<\/p><aside class=\"row all bg-yellow__light v-center h-center c half-row-gap d__pad-top-s t__pad-top-m m__pad-top-m d__pad-bottom-s t__pad-bottom-m m__pad-bottom-m d__in-narrow-container wrap t__vertical m__vertical t__in-container m__in-container\" data-cache-vw-d=\"1512\" data-cache-h-d=\"80.203125\" data-cache-vw-t=\"617\" data-cache-h-t=\"116.9375\" data-cache-vw-m=\"462\" data-cache-h-m=\"247.125\"><div class=\"col all d__mar-right-0 d__mar-bottom-0 t__mar-bottom-s m__mar-bottom-s\"><p class=\"wrap-balance anim-fade-in\"><b class=\"h6-size\">Professional AI-built website, no setup costs, for only \u20ac49\/month<\/b><\/p><\/div><div class=\"col all mar-bottom-0 w-auto\"><a class=\"button anim-fade-in bor-pitch-black__light txt-pitch-black-hover__light bg-transparent-hover__light bor-pitch-black-hover__light bg-pitch-black__light txt-yellow__light bg-pitch-black__dark txt-yellow__dark bor-pitch-black__dark bg-transparent-hover__dark txt-pitch-black-hover__dark bor-pitch-black-hover__dark d__h6-size t__h6-size w-auto pad-left-s pad-right-s pad-bottom-xs pad-top-xs\" href=\"https:\/\/www.terluinwebdesign.nl\/en\/ai-website-builder\/\"><span>AI Site Builder<\/span><\/a><\/div><\/aside><h3>This is where I realized that it takes a lot more effort<\/h3><p>It took a lot more effort, because I had to edit every template file in the WordPress theme I\u2019ve built for this website.<\/p><p>Every template file had to use a function that keeps track of what classes are used by which template files.<\/p><p>That function is written in a file that has to get included by every template file, and it creates a namespace so that you can use only the functions that a specific template file needs. This is what the file (<code>extra-functions.php<\/code>) looks like:<\/p><tw-pre><code class=\"php-code\">namespace ExtraFunctions;\r\n\r\nfunction addClasses($classes, $modifier = false, $caller = false) {\r\n  global $classesAddedByTemplates;\r\n  \r\n  if($caller === false) {\r\n    $caller = str_replace(get_template_directory(), '', debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1)[0]['file']);\r\n  }\r\n  if($modifier !== false) {\r\n    $caller .= ':' . strval($modifier);\r\n  }\r\n  \r\n  if(!isset($classesAddedByTemplates[$caller])) {\r\n    $classesAddedByTemplates[$caller] = [];\r\n  }\r\n  \r\n  array_push (\r\n    $classesAddedByTemplates[$caller],\r\n    ...explode(' ', $classes)\r\n  );\r\n  \r\n  $classesAddedByTemplates[$caller] = array_unique($classesAddedByTemplates[$caller]);\r\n  \r\n  return $classes;\r\n}<\/code><\/tw-pre><p>So, the function keeps tracks of all classes added by what templates and in what situation (using modifiers). In order to be able to use functions in the namespace, you <span class=\"code php-code\">require<\/span> the PHP file once, in a file to which your template files have access to it\u2019s global variables, and <span class=\"code php-code\">use<\/span> the function. The following example loads the PHP file:<\/p><tw-pre><code class=\"php-code\">require_once(__DIR__ . '\/extra-functions.php');<\/code><\/tw-pre><p>The following example uses a function inside the namespace:<\/p><tw-pre><code class=\"php-code\">use function ExtraFunctionsaddClasses;<\/code><\/tw-pre><p>In a callback function that I use to filter the final HTML output, there is also a piece of code that iterates through the whole array of classes, and decides whether or not to update the JSON files. This is what that looks like:<\/p><tw-pre><code class=\"php-code\">global $classesAddedByTemplates;\r\n$filePathClassesByTemplateFile = get_template_directory() . '\/classes-by-template-file.json';\r\n$contentClassesByTemplateFile = file_get_contents($filePathClassesByTemplateFile);\r\n$jsonClassesByTemplateFile = json_decode (\r\n  $contentClassesByTemplateFile,\r\n  true\r\n);\r\n\r\nforeach($classesAddedByTemplates as $templateFile =&gt; $classesByTemplateFile) {\r\n  $jsonClassesByTemplateFile[$templateFile] = $classesByTemplateFile;\r\n}\r\n\r\n$jsonStringClassesByTemplateFiles = json_encode($jsonClassesByTemplateFile);\r\n\r\n$filePathClassesByTemplates = get_template_directory() . '\/classes-by-templates.json';\r\n\r\nif($jsonStringClassesByTemplateFiles !== $contentClassesByTemplateFile) {\r\n  file_put_contents($filePathClassesByTemplateFile, $jsonStringClassesByTemplateFiles);\r\n  \r\n  $contentClassesByTemplates = file_get_contents($filePathClassesByTemplates);\r\n  \r\n  $classesByTemplates = [];\r\n  foreach($jsonClassesByTemplateFile as $templateFile =&gt; $classesByTemplateFile) {\r\n    foreach($classesByTemplateFile as $classByTemplateFile) {\r\n      if(!in_array($classByTemplateFile, $classesByTemplates)) {\r\n        array_push (\r\n          $classesByTemplates,\r\n          $classByTemplateFile\r\n        );\r\n      }\r\n    }\r\n  }\r\n  sort($classesByTemplates);\r\n  \r\n  $jsonStringClassesByTemplates = json_encode($classesByTemplates);\r\n  if($jsonStringClassesByTemplates !== $contentClassesByTemplates) {\r\n    file_put_contents($filePathClassesByTemplates, $jsonStringClassesByTemplates);\r\n  }\r\n  \r\n}<\/code><\/tw-pre><h2>Functionality to remove unused CSS classes<\/h2><p>In order to be able to automatically remove unused CSS classes in the CSS file, you would have to turn the CSS file into a PHP file.<\/p><p>Then, you have to add a <code data-not-linked=\"\">.htaccess<\/code> file in the same folder. That file will make sure that a request for, let\u2019s say, <code>stylesheet<strong>.css<\/strong><\/code> will get handled by <code>stylesheet<strong>.php<\/strong><\/code>. This is what the <code>.htaccess<\/code> file looks like:<\/p><tw-pre><code class=\"htaccess-code\">RewriteCond %{REQUEST_FILENAME} !-d\r\nRewriteCond %{REQUEST_FILENAME} !-f\r\nRewriteRule stylesheet.css stylesheet.php [L]<\/code><\/tw-pre><p>Now, the PHP\/CSS file should contain the following PHP code in the beginning:<\/p><tw-pre><code class=\"php-code\">header('Content-type: text\/css', false);\r\nheader('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime(__FILE__)) . ' GMT', false);\r\nheader_remove('X-Powered-By');\r\n\r\nob_start();<\/code><\/tw-pre><p>This makes sure that the <code>Content-Type<\/code> <span data-not-linked=\"\">HTTP header<\/span> indicates that it is a CSS file. It also starts <a href=\"https:\/\/www.php.net\/manual\/en\/function.ob-start.php\" target=\"_blank\" rel=\"noopener\">output buffering using PHP function ob_start<\/a>, in order to be able to collect all CSS code before outputting optimized CSS.<\/p><p>In order to know what classes are used, you have to get the contents of the following JSON files, and turn it into a usable array: <code>classes-by-pages.json<\/code> and <code>classes-by-templates.json<\/code>. Here\u2019s how:<\/p><tw-pre><code class=\"php-code\">$classesByPagesJSON = file_get_contents('classes-by-pages.json');\r\n$classesByPages = json_decode($classesByPagesJSON, true);\r\n\r\n$classesByTemplatesJSON = file_get_contents('classes-by-templates.json');\r\n$classesByTemplates = json_decode($classesByTemplatesJSON, true);<\/code><\/tw-pre><p>At the end of the PHP\/CSS file the <a href=\"https:\/\/www.php.net\/manual\/en\/function.ob-get-clean.php\" target=\"_blank\" rel=\"noopener\">output buffering is stopped and the output is retrieved using PHP function ob_get_clean<\/a> and put in a variable named <code class=\"php-code\">$css<\/code>.<\/p><p>I have created some PHP classes (not to be confused with CSS classes), which are necessary to be able to fully and partially deconstruct CSS queries to remove unused CSS classes:<\/p><ul><li><code class=\"php-code\">CSSDocument<\/code><\/li><li><code class=\"php-code\">CSSAtRule<\/code><\/li><li><code class=\"php-code\">CSSSelector<\/code><\/li><li><code class=\"php-code\">CSSQuery<\/code><\/li><li><code class=\"php-code\">CSSDeclaration<\/code><\/li><\/ul><p>The PHP classes above are sorted by depth of which such an element, such as a CSS declaration, appears inside of a CSS document.<\/p><p>Before showing the code, I\u2019d like to explain why it\u2019s necessary to cut the whole CSS document into bits and pieces (in the form of specific PHP objects).<\/p><p>If I were to remove unused CSS class <code class=\"css-code\">menu<\/code> from the following selector:<\/p><tw-pre><code class=\"css-code\">ul.menu <span class=\"SEMI-OPAQUE\">{\r\n  \/* ... *\/\r\n}<\/span><\/code><\/tw-pre><p>then I should remove the whole rule set, instead of removing the unused CSS class. However, if I were to remove unused CSS class <code class=\"css-code\">menu<\/code> from the following selector:<\/p><tw-pre><code class=\"css-code\">ul:not(.menu) <span class=\"SEMI-OPAQUE\">{\r\n  \/* ... *\/\r\n}<\/span><\/code><\/tw-pre><p>then, as I remove <code class=\"css-code\">:not(.menu)<\/code>, the selector becomes less specific due to the loss of a class inside of CSS\u2019s negation function <code class=\"css-code\">:not()<\/code>.<\/p><p>Instead, the class should get replaced by a placeholder class:<\/p><tw-pre><code class=\"css-code\">ul:not(.?) <span class=\"SEMI-OPAQUE\">{\r\n  \/* ... *\/\r\n}<\/span><\/code><\/tw-pre><p>That way, it\u2019s just as specific, but the unused class is replaced by a placeholder class.<\/p><p>You could also use a single underscore (<code class=\"css-code\">._<\/code>), instead of a backward slash escaped question mark (<code class=\"css-code\">.?<\/code>); that\u2019s even shorter. It is suitable as a placeholder class as long as it\u2019s short (word play), and not used in HTML.<\/p><p>Using regex would require you to create a pattern for a whole CSS rule set, which consists of: the selector, queries of the selector and declarations.<\/p><p>I found it more debuggable if I were to write it in seperate steps (in the form of specific PHP objects), so here it is:<\/p><tw-pre><code class=\"php-code\">class CSSDeclaration {\r\n  public $property;\r\n  public $value;\r\n  \r\n  public $ruleSet; \/\/ parent\r\n  \r\n  public function __construct (\r\n    $property,\r\n    $value\r\n  ) {\r\n    $this -&gt; property = $property;\r\n    $this -&gt; value = $value;\r\n  }\r\n}\r\nclass CSSQuery {\r\n  public $queryString;\r\n\r\n  public $queryKey;\r\n  \r\n  public $selector; \/\/ parent\r\n  \r\n  public function __construct (\r\n    $queryString,\r\n    CSSSelector $selector,\r\n    $queryKey\r\n  ) {\r\n    preg_match_all (\r\n      '\/[ &gt;]|::[^ :&gt;]+|[@:#.]?[^ :&gt;]+|*\/',\r\n      $queryString,\r\n      $piecesMatch\r\n    );\r\n    $this -&gt; queryString = $queryString;\r\n    \r\n    $this -&gt; selector = $selector;\r\n    $this -&gt; queryKey = $queryKey;\r\n  }\r\n  \r\n  public function __destruct() {\r\n    if(count($this -&gt; selector -&gt; queries) &lt; 2) {\r\n      unset($this -&gt; selector -&gt; ruleSet);\r\n    }\r\n  }\r\n}\r\nclass CSSSelector {\r\n  public $queries = [];\r\n  public $originalQueryAmount = 0;\r\n  \r\n  public $ruleSet; \/\/ parent\r\n  \r\n  public function __construct (\r\n    $selector\r\n  ) {\r\n    preg_match_all (\r\n      '\/[^,{}]+\/',\r\n      $selector,\r\n      $queriesMatch\r\n    );\r\n    $queriesMatch = $queriesMatch[0];\r\n    \r\n    foreach($queriesMatch as $queryMatch) {\r\n      $this -&gt; queries[$this -&gt; originalQueryAmount] = new CSSQuery (\r\n        $queryMatch,\r\n        $this,\r\n        $this -&gt; originalQueryAmount\r\n      );\r\n      $this -&gt; originalQueryAmount++;\r\n    }\r\n  }\r\n  \r\n  public function removeQuery(CSSQuery $query) {\r\n    unset($this -&gt; queries[$query -&gt; queryKey]);\r\n  }\r\n  \r\n  public function __destruct() {\r\n    \r\n  }\r\n}\r\nclass CSSRuleSet {\r\n  public $selector;\r\n  public $declarations;\r\n  \r\n  public $document;\r\n  \r\n  public function __construct (\r\n    CSSSelector $selector,\r\n    $declarations,\r\n    CSSDocument $document\r\n  ) {\r\n    $this -&gt; selector = $selector;\r\n    $this -&gt; selector -&gt; ruleSet = $this;\r\n    \r\n    $this -&gt; declarations = $declarations;\r\n    foreach($this -&gt; declarations as $declaration) {\r\n      $declaration -&gt; ruleSet = $this;\r\n    }\r\n  }\r\n  \r\n  public function removeDeclaration(CSSDeclaration $declarationToRemove) {\r\n    foreach($this -&gt; declarations as $iDeclaration =&gt; $declaration) {\r\n      if (\r\n        $declaration -&gt; property === $declarationToRemove -&gt; property\r\n        &amp;&amp;\r\n        $declaration -&gt; value === $declarationToRemove -&gt; value\r\n      ) {\r\n        unset($this -&gt; declarations[$iDeclaration]);\r\n      }\r\n    }\r\n  }\r\n  \r\n  public function __destruct() {\r\n    \r\n  }\r\n}\r\nclass CSSAtRule {\r\n  public $selector;\r\n  public $ruleSets;\r\n  \r\n  public function __construct (\r\n    CSSSelector $selector,\r\n    $ruleSets\r\n  ) {\r\n    $this -&gt; selector = $selector;\r\n    $this -&gt; ruleSets = $ruleSets;\r\n  }\r\n}\r\n\r\nclass CSSDocument {\r\n  public $atRules = [];\r\n  \r\n  private $currentAtRuleSets;\r\n  \r\n  public function __construct (\r\n    $source\r\n  ) {\r\n    $source = '@media all{' . preg_replace (\r\n      [\r\n        '\/@(keyframes|media|supports)\/',\r\n        '\/}}@font-face\/',\r\n        '\/}}([^@])\/'\r\n      ],\r\n      [\r\n        '}@$1',\r\n        '}}@media all{@font-face',\r\n        '}}@media all{$1'\r\n      ],\r\n      $source\r\n    ) . '}';\r\n    $source = str_replace('@media all{}', '', $source);\r\n    \r\n    preg_replace_callback (\r\n      '\/@(keyframes|media|supports)([^{}]+){(.+})}\/sU',\r\n      function($atRuleMatch) {\r\n        $this -&gt; currentAtRuleSets = [];\r\n        \r\n        $atRuleRuleSetsMatch = $atRuleMatch[3];\r\n        \r\n        preg_replace_callback (\r\n          [\r\n            '\/([^{}]+){([^{}]*)}\/m'\r\n          ],\r\n          function($ruleSet) {\r\n            \r\n            $selector = $ruleSet[1];\r\n            \r\n            $declarationBlock = $ruleSet[2];\r\n            $declarations = [];\r\n            \r\n            preg_match_all (\r\n              '\/([^:;{}]+)[:]([^:;}{]+)\/',\r\n              $declarationBlock,\r\n              $declarationsMatch,\r\n              PREG_SET_ORDER\r\n            );\r\n            $declarationsMatch = $declarationsMatch;\r\n            \r\n            foreach($declarationsMatch as $declarationMatch) {\r\n              \r\n              array_push (\r\n                $declarations,\r\n                new CSSDeclaration (\r\n                  $declarationMatch[1],\r\n                  $declarationMatch[2]\r\n                )\r\n              );\r\n            }\r\n            \r\n            array_push (\r\n              $this -&gt; currentAtRuleSets,\r\n              new CSSRuleSet (\r\n                new CSSSelector (\r\n                  $selector\r\n                ),\r\n                $declarations,\r\n                $this\r\n              )\r\n            );\r\n          },\r\n          $atRuleRuleSetsMatch\r\n        );\r\n        \r\n        array_push (\r\n          $this -&gt; atRules,\r\n          new CSSAtRule (\r\n            new CSSSelector('@' . $atRuleMatch[1] . $atRuleMatch[2]),\r\n            $this -&gt; currentAtRuleSets\r\n          )\r\n        );\r\n        \r\n      },\r\n      $source\r\n    );\r\n  }\r\n  \r\n  public function save() {\r\n    $css = '';\r\n    \r\n    foreach($this -&gt; atRules as $atRule) {\r\n      $iAtQuery = 0;\r\n      foreach($atRule -&gt; selector -&gt; queries as $iAtQuery =&gt; $query) {\r\n        if($query -&gt; queryString == '@media all') {\r\n          unset($atRule -&gt; selector -&gt; queries[$iAtQuery]);\r\n        }\r\n      }\r\n      $amountOfAtQueries = count($atRule -&gt; selector -&gt; queries);\r\n      \r\n      if($amountOfAtQueries &gt; 0) {\r\n        foreach($atRule -&gt; selector -&gt; queries as $query) {\r\n          $iAtQuery++;\r\n          $css .= $query -&gt; queryString;\r\n          if($iAtQuery &lt; $amountOfAtQueries) {\r\n            $css .= ',';\r\n          }\r\n        }\r\n        $css .= '{';\r\n      }\r\n      \r\n      foreach($atRule -&gt; ruleSets as $ruleSet) {\r\n        $amountOfQueries = count($ruleSet -&gt; selector -&gt; queries);\r\n        if($amountOfQueries &gt; 0) {\r\n          $iQuery = 0;\r\n          foreach($ruleSet -&gt; selector -&gt; queries as $query) {\r\n            $iQuery++;\r\n            $css .= $query -&gt; queryString;\r\n            if($iQuery &lt; $amountOfQueries) {\r\n              $css .= ',';\r\n            }\r\n          }\r\n          \r\n          $css .= '{';\r\n          $amountOfDeclarations = count($ruleSet -&gt; declarations);\r\n          $iDeclaration = 0;\r\n          foreach($ruleSet -&gt; declarations as $declaration) {\r\n            $iDeclaration++;\r\n            $css .= $declaration -&gt; property . ':' . $declaration -&gt; value;\r\n            if($iDeclaration &lt; $amountOfDeclarations) {\r\n              $css .= ';';\r\n            }\r\n          }\r\n          $css .= '}';\r\n        }\r\n      }\r\n      \r\n      if($amountOfAtQueries &gt; 0) {\r\n        $css .= '}';\r\n      }\r\n    }\r\n    \r\n    return $css;\r\n  }\r\n  \r\n  public function removeUnusedClasses($usedClasses, $whiteListedClasses = [], $stateClassesByDefaultState = []) {\r\n    foreach($stateClassesByDefaultState as $defaultState =&gt; $stateClasses) {\r\n      if (\r\n        in_array($defaultState, $usedClasses)\r\n        ||\r\n        in_array($defaultState, $whiteListedClasses)\r\n      ) {\r\n        array_push (\r\n          $whiteListedClasses,\r\n          ...$stateClasses\r\n        );\r\n      }\r\n    }\r\n    \r\n    foreach($this -&gt; atRules as $atRule) {\r\n      foreach($atRule -&gt; ruleSets as $ruleSet) {\r\n        foreach($ruleSet -&gt; selector -&gt; queries as $query) {\r\n          $queryStringWithoutNegation = preg_replace (\r\n            '\/:not(.[^0123456789 #.([{}]):&gt;+~*,][^ #.([{}]):&gt;+~*,]+)\/',\r\n            '',\r\n            $query -&gt; queryString\r\n          );\r\n          \r\n          preg_match_all (\r\n            '\/.([^0123456789 #.([{}]):&gt;+~*,][^ #.([{}]):&gt;+~*,]+)\/',\r\n            $queryStringWithoutNegation,\r\n            $classesInQueryWithoutNegation\r\n          );\r\n          \r\n          $queryRemoved = false;\r\n          \r\n          foreach($classesInQueryWithoutNegation[1] as $class) {\r\n            if (\r\n              !in_array($class, $usedClasses)\r\n              &amp;&amp;\r\n              !in_array($class, $whiteListedClasses)\r\n            ) {\r\n              $query -&gt; selector -&gt; removeQuery($query);\r\n              $queryRemoved = true;\r\n              break;\r\n            }\r\n          }\r\n          \r\n          if(!$queryRemoved) {\r\n            $query -&gt; queryString = preg_replace_callback (\r\n              '\/.([^0123456789 #.([{}]):&gt;+~*,][^ #.([{}]):&gt;+~*,]+)\/',\r\n              function($class) use ($usedClasses, $whiteListedClasses) {\r\n                if (\r\n                  !in_array($class[1], $usedClasses)\r\n                  &amp;&amp;\r\n                  !in_array($class[1], $whiteListedClasses)\r\n                ) {\r\n                  return '.__';\r\n                } else {\r\n                  return $class[0];\r\n                }\r\n              },\r\n              $query -&gt; queryString\r\n            );\r\n          }\r\n        }\r\n      }\r\n    }\r\n  }\r\n}<\/code><\/tw-pre><p>The above code consist only of PHP classes, so there is no object constructed yet.<\/p><p><strong>Note: this code does not support nested at-rules (@media, @supports, @keyframes).<\/strong><\/p><p>In order to use this functionality, you create a new <code class=\"php-code\">CSSDocument<\/code> object using the collected CSS code as the argument.<\/p><tw-pre><code class=\"php-code\">$cssDocument = new CSSDocument($css);<\/code><\/tw-pre><p>This object carries a function called <code class=\"php-code\">removeUnusedClasses<\/code>. That\u2019s my favorite function so far, what about you?<\/p><h3>Whitelisting classes indicating non-default states<\/h3><p>Some classes indicate a non-default state for certain elements, for example:<\/p><ul><li>Hamburger menus \/ expandable menus may or may not be <strong>expanded<\/strong>.<\/li><li>An element\u2019s animation may or may not yet be <strong>activated<\/strong>.<\/li><\/ul><p>These non-default states are indicated by classes that might not be present when saving a page, and thus may not be present in the JSON files for keeping track of what classes are used.<\/p><p>Such classes, <code class=\"css-code\">expanded<\/code> for example, are often tied to other classes, for instance: <code class=\"css-code\">hamburger-menu<\/code>.<\/p><p>In the example below I\u2019ve whitelisted class <code class=\"css-code\">expanded<\/code> for when class <code class=\"css-code\">hamburger-menu<\/code> is used.<\/p><tw-pre><code class=\"php-code\">$stateClassesByDefaultState = [\r\n  'hamburger-menu' =&gt; [\r\n    'expanded'\r\n  ],\r\n  'anim-fade-in' =&gt; [\r\n    'activated'\r\n  ]\r\n];<\/code><\/tw-pre><h3>Moment of truth: remove unused CSS classes<\/h3><p>Once you\u2019ve whitelisted some classes, you can now use the two JSON files containing used classes as arguments for function <code class=\"php-code\">removeUnusedClasses<\/code>:<\/p><ul><li><code>classes-by-pages.json<\/code><\/li><li><code>classes-by-templates.json<\/code><\/li><\/ul><p>The array of classes to whitelist when certain classes are used, <code class=\"php-code\">$stateClassesByDefaultState<\/code>, is used as the third and last argument for the said function call. Here we go:<\/p><tw-pre><code class=\"php-code\">$cssDocument -&gt; removeUnusedClasses (\r\n  $classesByPages,\r\n  $classesByTemplates,\r\n  $stateClassesByDefaultState\r\n);\r\n\r\n$optimizedCSS = $cssDocument -&gt; save();\r\necho $optimizedCSS;<\/code><\/tw-pre><h2>Fine tuning the process of removing unused CSS<\/h2><p>There is some fine tuning to be done in order to, for instance, make sure that the list of used classes won\u2019t get updated when not necessary.<\/p><h3>Excluding certain classes from list of used classes<\/h3><p>Some classes should not get added to the list of classes, as they are either random, or they are both unused and specific to the page (ID), etc.<\/p><ul><li>Randomized classes, as they change often and are not used (probably).<\/li><li>Classes that are specific to the page, like the page id: <code class=\"css-code\">page-id-9<\/code>.<\/li><li>Classes that indicate a certain state, because they will get whitelisted anyways if the class that indicates it\u2019s default state is present. I\u2019ve covered this earlier.<\/li><\/ul><h4>Page-specific and randomized classes<\/h4><p>Predictable page-specific and randomized classes can be easily excluded from being added to the list of used classes. You can just write a regular expression, like this:<\/p><tw-pre><code class=\"js-code\">if(!elClass.match(\/post-(d)+\/g)) {\r\n  \/\/ class didn't match, you can add the class to the list of used classes\r\n}<\/code><\/tw-pre><p>The example above excludes all classes that start with <code class=\"css-code\">post-<\/code> and end with digits.<\/p><h4>Classes that indicate a non-default state<\/h4><p>I have discussed these kind of classes earlier. However, what I haven\u2019t told you is that there is no need to add these classes to the list of used classes, as they will get whitelisted anyways \u2013 if the class indicating it\u2019s default state is present.<\/p><tw-pre><code class=\"js-code\">if(!['expanded', 'activated'].includes(elClass)) {\r\n  \/\/ add class to list of used classes\r\n}<\/code><\/tw-pre><h3>Tracking classes added by JavaScript<\/h3><p>If some classes are added by JavaScript files, you should just whitelist them by calling <code>addClasses<\/code> and providing the path to the JavaScript file for the 3rd argument.<\/p><tw-pre><code class=\"php-code\">addClasses (\r\n  'some-class another-class and-another-one',\r\n  false,\r\n  '\/some-javascript\/file.js'\r\n);\r\n<\/code><\/tw-pre><p>You can also directly add them to the array of classes added by templates, like this:<\/p><tw-pre><code class=\"php-code\">$classesAddedByTemplates['\/some\/javascript\/file.js'] = [\r\n  'some-class',\r\n  'another-class',\r\n  'and-another-one'\r\n];<\/code><\/tw-pre><h3>Denying public access to the JSON files<\/h3><p>Since nobody has to read the JSON files, you might as well make them not publicly available. You can do this by adding a <code>.htaccess<\/code> file and the JSON files in a seperate folder. Make sure to modify the file paths in your PHP code. Contents of <code>.htaccess<\/code> file:<\/p><tw-pre><code class=\"htaccess-code\">deny from all<\/code><\/tw-pre><p><strong>The code showcased in this article is used on this website to remove unused CSS classes. It took me a lot of time and effort to make it work. If you happen to like articles or unique solutions like these, be sure to stick around for more <a href=\"https:\/\/www.terluinwebdesign.nl\/en\/css\/\">blog posts about CSS<\/a>.<\/strong><\/p><\/div><\/div><aside class=\"row all t__content-in-container m__content-in-container d__in-container v-center bg-yellow__light m__vertical color-scheme-light__dark bg-yellow__dark t__vertical t__h-center t__c m__c\" data-cache-vw-d=\"1512\" data-cache-h-d=\"318.53125\" data-cache-vw-t=\"617\" data-cache-h-t=\"836.5546875\" data-cache-vw-m=\"462\" data-cache-h-m=\"870.9609375\"><div class=\"col all w-1\/d\/3 w-10\/t\/13\"><h2 class=\"t__h1 wrap-balance anim-fade-in\">Professional AI-built website, no setup costs, for only \u20ac49\/month<\/h2><a class=\"button bor-pitch-black__light txt-pitch-black-hover__light bg-transparent-hover__light bor-pitch-black-hover__light bg-pitch-black__light txt-yellow__light bg-pitch-black__dark txt-yellow__dark bor-pitch-black__dark bg-transparent-hover__dark txt-pitch-black-hover__dark bor-pitch-black-hover__dark d__h6-size t__h6-size\" href=\"https:\/\/www.terluinwebdesign.nl\/en\/ai-website-builder\/\"><span>AI Site Builder<\/span><\/a><\/div><div class=\"col all\"><div class=\"row all m__vertical t__vertical\"><div class=\"col all\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.terluinwebdesign.nl\/wp-content\/uploads\/2025\/07\/website-builder-ai-bizbuilder-homepage.png\" class=\"anim-fade-in\" data-src-light=\"\" data-src-dark=\"\" title=\"\" alt=\"\" width=\"3020\" height=\"1645\" srcset=\"https:\/\/www.terluinwebdesign.nl\/wp-content\/plugins\/tw-builder\/access\/img\/tmp\/2025\/07\/website-builder-ai-bizbuilder-homepage-w512.png.webp\" data-img-vw-d=\"1512\" data-img-w-d=\"356.2890625\" data-img-h-d=\"193.453125\" data-img-of-d=\"fill\" data-img-vw-t=\"617\" data-img-w-t=\"502.421875\" data-img-h-t=\"272.796875\" data-img-of-t=\"fill\" data-img-vw-m=\"462\" data-img-w-m=\"404.25\" data-img-h-m=\"219.4921875\" data-img-of-m=\"fill\"><\/div><div class=\"col all\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.terluinwebdesign.nl\/wp-content\/uploads\/2025\/07\/bizbuilder-dienst-pagina-desktop.png\" class=\"anim-fade-in\" data-src-light=\"\" data-src-dark=\"\" title=\"\" alt=\"\" width=\"3840\" height=\"2160\" srcset=\"https:\/\/www.terluinwebdesign.nl\/wp-content\/plugins\/tw-builder\/access\/img\/tmp\/2025\/07\/bizbuilder-dienst-pagina-desktop-w512.png.webp\" data-img-vw-d=\"1512\" data-img-w-d=\"356.2890625\" data-img-h-d=\"200.40625\" data-img-of-d=\"fill\" data-img-vw-t=\"617\" data-img-w-t=\"502.421875\" data-img-h-t=\"282.609375\" data-img-of-t=\"fill\" data-img-vw-m=\"462\" data-img-w-m=\"404.25\" data-img-h-m=\"227.390625\" data-img-of-m=\"fill\"><\/div><\/div><\/div><\/aside><\/prevent-autop><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>This article focuses on how to remove unused CSS classes, but the same methods can apply to tag names as well.&nbsp;You can even optimize your JavaScript with the resources, after you\u2019ve implemented the solution that I will explain in this article.However, instead of removing unused JavaScript code, you conditionally add JavaScript code by looking in <a href=\"https:\/\/www.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/\" class=\"read-more-link block\">Read more<\/a><\/p>\n","protected":false},"author":2,"featured_media":8539,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1,56],"tags":[],"class_list":["post-6665","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","category-css"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Remove unused CSS classes automatically, for better performance<\/title>\n<meta name=\"description\" content=\"Future-proof solution to remove unused CSS classes automatically, so there is no manual work after implementing this PHP\/JS solution.\" \/>\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.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Remove unused CSS classes automatically, for better performance\" \/>\n<meta property=\"og:description\" content=\"Future-proof solution to remove unused CSS classes automatically, so there is no manual work after implementing this PHP\/JS solution.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/\" \/>\n<meta property=\"og:site_name\" content=\"Terluin Webdesign\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/TerluinWebdesign\/\" \/>\n<meta property=\"article:published_time\" content=\"2021-11-16T17:52:31+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-07-18T14:51:29+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.terluinwebdesign.nl\/en\/wp-content\/uploads\/2021\/11\/remove-unused-css-classes-automatically.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"676\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Thijs Terluin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@terluinwdesign\" \/>\n<meta name=\"twitter:site\" content=\"@terluinwdesign\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Thijs Terluin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"16 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/blog\\\/remove-unused-css-classes-automatically\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/blog\\\/remove-unused-css-classes-automatically\\\/\"},\"author\":{\"name\":\"Thijs Terluin\",\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/#\\\/schema\\\/person\\\/a6f6b03a4d7acb99553ec297f1d6d1dd\"},\"headline\":\"Remove unused CSS classes automatically\",\"datePublished\":\"2021-11-16T17:52:31+00:00\",\"dateModified\":\"2025-07-18T14:51:29+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/blog\\\/remove-unused-css-classes-automatically\\\/\"},\"wordCount\":5,\"publisher\":{\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/blog\\\/remove-unused-css-classes-automatically\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/wp-content\\\/uploads\\\/2021\\\/11\\\/remove-unused-css-classes-automatically.jpg\",\"articleSection\":[\"Blog\",\"CSS\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/blog\\\/remove-unused-css-classes-automatically\\\/\",\"url\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/blog\\\/remove-unused-css-classes-automatically\\\/\",\"name\":\"Remove unused CSS classes automatically, for better performance\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/blog\\\/remove-unused-css-classes-automatically\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/blog\\\/remove-unused-css-classes-automatically\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/wp-content\\\/uploads\\\/2021\\\/11\\\/remove-unused-css-classes-automatically.jpg\",\"datePublished\":\"2021-11-16T17:52:31+00:00\",\"dateModified\":\"2025-07-18T14:51:29+00:00\",\"description\":\"Future-proof solution to remove unused CSS classes automatically, so there is no manual work after implementing this PHP\\\/JS solution.\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/blog\\\/remove-unused-css-classes-automatically\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/blog\\\/remove-unused-css-classes-automatically\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/wp-content\\\/uploads\\\/2021\\\/11\\\/remove-unused-css-classes-automatically.jpg\",\"contentUrl\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/wp-content\\\/uploads\\\/2021\\\/11\\\/remove-unused-css-classes-automatically.jpg\",\"width\":1200,\"height\":676,\"caption\":\"Remove unused CSS class names automatically\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/#website\",\"url\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/\",\"name\":\"Terluin Webdesign\",\"description\":\"Let your website work for you\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/#organization\",\"name\":\"Terluin Webdesign\",\"url\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/wp-content\\\/uploads\\\/2019\\\/05\\\/terluin.png\",\"contentUrl\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/wp-content\\\/uploads\\\/2019\\\/05\\\/terluin.png\",\"width\":294,\"height\":674,\"caption\":\"Terluin Webdesign\"},\"image\":{\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/TerluinWebdesign\\\/\",\"https:\\\/\\\/x.com\\\/terluinwdesign\",\"https:\\\/\\\/www.instagram.com\\\/terluinwebdesign\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/terluin-webdesig\\\/\",\"https:\\\/\\\/www.youtube.com\\\/channel\\\/UCqaaHJh0caCmucUaWsewhKQ\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/#\\\/schema\\\/person\\\/a6f6b03a4d7acb99553ec297f1d6d1dd\",\"name\":\"Thijs Terluin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/adff8d4881876bce4a26779bbab04daa390a45232b37b4f00a6ad954e4bc705f?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/adff8d4881876bce4a26779bbab04daa390a45232b37b4f00a6ad954e4bc705f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/adff8d4881876bce4a26779bbab04daa390a45232b37b4f00a6ad954e4bc705f?s=96&d=mm&r=g\",\"caption\":\"Thijs Terluin\"},\"description\":\"Thijs Terluin is a web designer at Terluin Webdesign. He specializes in providing the structure, functionalities and speed of websites and web shops on devices and web browsers.\",\"sameAs\":[\"https:\\\/\\\/www.linkedin.com\\\/in\\\/thijs-terluin\\\/\"],\"url\":\"https:\\\/\\\/www.terluinwebdesign.nl\\\/en\\\/about-us\\\/thijs-terluin\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Remove unused CSS classes automatically, for better performance","description":"Future-proof solution to remove unused CSS classes automatically, so there is no manual work after implementing this PHP\/JS solution.","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.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/","og_locale":"en_US","og_type":"article","og_title":"Remove unused CSS classes automatically, for better performance","og_description":"Future-proof solution to remove unused CSS classes automatically, so there is no manual work after implementing this PHP\/JS solution.","og_url":"https:\/\/www.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/","og_site_name":"Terluin Webdesign","article_publisher":"https:\/\/www.facebook.com\/TerluinWebdesign\/","article_published_time":"2021-11-16T17:52:31+00:00","article_modified_time":"2025-07-18T14:51:29+00:00","og_image":[{"width":1200,"height":676,"url":"https:\/\/www.terluinwebdesign.nl\/en\/wp-content\/uploads\/2021\/11\/remove-unused-css-classes-automatically.jpg","type":"image\/jpeg"}],"author":"Thijs Terluin","twitter_card":"summary_large_image","twitter_creator":"@terluinwdesign","twitter_site":"@terluinwdesign","twitter_misc":{"Written by":"Thijs Terluin","Est. reading time":"16 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/#article","isPartOf":{"@id":"https:\/\/www.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/"},"author":{"name":"Thijs Terluin","@id":"https:\/\/www.terluinwebdesign.nl\/en\/#\/schema\/person\/a6f6b03a4d7acb99553ec297f1d6d1dd"},"headline":"Remove unused CSS classes automatically","datePublished":"2021-11-16T17:52:31+00:00","dateModified":"2025-07-18T14:51:29+00:00","mainEntityOfPage":{"@id":"https:\/\/www.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/"},"wordCount":5,"publisher":{"@id":"https:\/\/www.terluinwebdesign.nl\/en\/#organization"},"image":{"@id":"https:\/\/www.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/#primaryimage"},"thumbnailUrl":"https:\/\/www.terluinwebdesign.nl\/en\/wp-content\/uploads\/2021\/11\/remove-unused-css-classes-automatically.jpg","articleSection":["Blog","CSS"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/","url":"https:\/\/www.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/","name":"Remove unused CSS classes automatically, for better performance","isPartOf":{"@id":"https:\/\/www.terluinwebdesign.nl\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/#primaryimage"},"image":{"@id":"https:\/\/www.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/#primaryimage"},"thumbnailUrl":"https:\/\/www.terluinwebdesign.nl\/en\/wp-content\/uploads\/2021\/11\/remove-unused-css-classes-automatically.jpg","datePublished":"2021-11-16T17:52:31+00:00","dateModified":"2025-07-18T14:51:29+00:00","description":"Future-proof solution to remove unused CSS classes automatically, so there is no manual work after implementing this PHP\/JS solution.","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.terluinwebdesign.nl\/en\/blog\/remove-unused-css-classes-automatically\/#primaryimage","url":"https:\/\/www.terluinwebdesign.nl\/en\/wp-content\/uploads\/2021\/11\/remove-unused-css-classes-automatically.jpg","contentUrl":"https:\/\/www.terluinwebdesign.nl\/en\/wp-content\/uploads\/2021\/11\/remove-unused-css-classes-automatically.jpg","width":1200,"height":676,"caption":"Remove unused CSS class names automatically"},{"@type":"WebSite","@id":"https:\/\/www.terluinwebdesign.nl\/en\/#website","url":"https:\/\/www.terluinwebdesign.nl\/en\/","name":"Terluin Webdesign","description":"Let your website work for you","publisher":{"@id":"https:\/\/www.terluinwebdesign.nl\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.terluinwebdesign.nl\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.terluinwebdesign.nl\/en\/#organization","name":"Terluin Webdesign","url":"https:\/\/www.terluinwebdesign.nl\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.terluinwebdesign.nl\/en\/#\/schema\/logo\/image\/","url":"https:\/\/www.terluinwebdesign.nl\/en\/wp-content\/uploads\/2019\/05\/terluin.png","contentUrl":"https:\/\/www.terluinwebdesign.nl\/en\/wp-content\/uploads\/2019\/05\/terluin.png","width":294,"height":674,"caption":"Terluin Webdesign"},"image":{"@id":"https:\/\/www.terluinwebdesign.nl\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/TerluinWebdesign\/","https:\/\/x.com\/terluinwdesign","https:\/\/www.instagram.com\/terluinwebdesign\/","https:\/\/www.linkedin.com\/company\/terluin-webdesig\/","https:\/\/www.youtube.com\/channel\/UCqaaHJh0caCmucUaWsewhKQ"]},{"@type":"Person","@id":"https:\/\/www.terluinwebdesign.nl\/en\/#\/schema\/person\/a6f6b03a4d7acb99553ec297f1d6d1dd","name":"Thijs Terluin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/adff8d4881876bce4a26779bbab04daa390a45232b37b4f00a6ad954e4bc705f?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/adff8d4881876bce4a26779bbab04daa390a45232b37b4f00a6ad954e4bc705f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/adff8d4881876bce4a26779bbab04daa390a45232b37b4f00a6ad954e4bc705f?s=96&d=mm&r=g","caption":"Thijs Terluin"},"description":"Thijs Terluin is a web designer at Terluin Webdesign. He specializes in providing the structure, functionalities and speed of websites and web shops on devices and web browsers.","sameAs":["https:\/\/www.linkedin.com\/in\/thijs-terluin\/"],"url":"https:\/\/www.terluinwebdesign.nl\/en\/about-us\/thijs-terluin\/"}]}},"_links":{"self":[{"href":"https:\/\/www.terluinwebdesign.nl\/en\/wp-json\/wp\/v2\/posts\/6665","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.terluinwebdesign.nl\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.terluinwebdesign.nl\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.terluinwebdesign.nl\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.terluinwebdesign.nl\/en\/wp-json\/wp\/v2\/comments?post=6665"}],"version-history":[{"count":1,"href":"https:\/\/www.terluinwebdesign.nl\/en\/wp-json\/wp\/v2\/posts\/6665\/revisions"}],"predecessor-version":[{"id":9081,"href":"https:\/\/www.terluinwebdesign.nl\/en\/wp-json\/wp\/v2\/posts\/6665\/revisions\/9081"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.terluinwebdesign.nl\/en\/wp-json\/wp\/v2\/media\/8539"}],"wp:attachment":[{"href":"https:\/\/www.terluinwebdesign.nl\/en\/wp-json\/wp\/v2\/media?parent=6665"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.terluinwebdesign.nl\/en\/wp-json\/wp\/v2\/categories?post=6665"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.terluinwebdesign.nl\/en\/wp-json\/wp\/v2\/tags?post=6665"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}