Repository: capricorn86/happy-dom
Pull request #365 (2022-02-17 16:55:39)

#352@minor: Adds support for Window.CSS and Window.CSSUnitValue.


Patch:
diff --git a/package-lock.json b/package-lock.json
index b8c6076c..2cd359fd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,6 +17,7 @@
 				"@lit/reactive-element": "^1.0.1",
 				"cpy": "^8.1.2",
 				"css-tree": "^1.0.0-alpha.29",
+				"css.escape": "^1.5.1",
 				"glob": "^7.1.6",
 				"he": "^1.1.1",
 				"jest-mock": "^27.0.3",
@@ -924,30 +925,30 @@
 			}
 		},
 		"node_modules/@jest/environment": {
-			"version": "27.4.6",
-			"resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.4.6.tgz",
-			"integrity": "sha512-E6t+RXPfATEEGVidr84WngLNWZ8ffCPky8RqqRK6u1Bn0LK92INe0MDttyPl/JOzaq92BmDzOeuqk09TvM22Sg==",
+			"version": "27.5.1",
+			"resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz",
+			"integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==",
 			"dependencies": {
-				"@jest/fake-timers": "^27.4.6",
-				"@jest/types": "^27.4.2",
+				"@jest/fake-timers": "^27.5.1",
+				"@jest/types": "^27.5.1",
 				"@types/node": "*",
-				"jest-mock": "^27.4.6"
+				"jest-mock": "^27.5.1"
 			},
 			"engines": {
 				"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
 			}
 		},
 		"node_modules/@jest/fake-timers": {
-			"version": "27.4.6",
-			"resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.6.tgz",
-			"integrity": "sha512-mfaethuYF8scV8ntPpiVGIHQgS0XIALbpY2jt2l7wb/bvq4Q5pDLk4EP4D7SAvYT1QrPOPVZAtbdGAOOyIgs7A==",
+			"version": "27.5.1",
+			"resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz",
+			"integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==",
 			"dependencies": {
-				"@jest/types": "^27.4.2",
+				"@jest/types": "^27.5.1",
 				"@sinonjs/fake-timers": "^8.0.1",
 				"@types/node": "*",
-				"jest-message-util": "^27.4.6",
-				"jest-mock": "^27.4.6",
-				"jest-util": "^27.4.2"
+				"jest-message-util": "^27.5.1",
+				"jest-mock": "^27.5.1",
+				"jest-util": "^27.5.1"
 			},
 			"engines": {
 				"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
@@ -965,17 +966,17 @@
 			}
 		},
 		"node_modules/@jest/fake-timers/node_modules/jest-message-util": {
-			"version": "27.4.6",
-			"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.6.tgz",
-			"integrity": "sha512-0p5szriFU0U74czRSFjH6RyS7UYIAkn/ntwMuOwTGWrQIOh5NzXXrq72LOqIkJKKvFbPq+byZKuBz78fjBERBA==",
+			"version": "27.5.1",
+			"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz",
+			"integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==",
 			"dependencies": {
 				"@babel/code-frame": "^7.12.13",
-				"@jest/types": "^27.4.2",
+				"@jest/types": "^27.5.1",
 				"@types/stack-utils": "^2.0.0",
 				"chalk": "^4.0.0",
-				"graceful-fs": "^4.2.4",
+				"graceful-fs": "^4.2.9",
 				"micromatch": "^4.0.4",
-				"pretty-format": "^27.4.6",
+				"pretty-format": "^27.5.1",
 				"slash": "^3.0.0",
 				"stack-utils": "^2.0.3"
 			},
@@ -984,9 +985,9 @@
 			}
 		},
 		"node_modules/@jest/fake-timers/node_modules/pretty-format": {
-			"version": "27.4.6",
-			"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz",
-			"integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==",
+			"version": "27.5.1",
+			"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
+			"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
 			"dependencies": {
 				"ansi-regex": "^5.0.1",
 				"ansi-styles": "^5.0.0",
@@ -1298,9 +1299,9 @@
 			}
 		},
 		"node_modules/@jest/types": {
-			"version": "27.4.2",
-			"resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz",
-			"integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==",
+			"version": "27.5.1",
+			"resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz",
+			"integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==",
 			"dependencies": {
 				"@types/istanbul-lib-coverage": "^2.0.0",
 				"@types/istanbul-reports": "^3.0.0",
@@ -2673,9 +2674,9 @@
 			}
 		},
 		"node_modules/@lit/reactive-element": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.2.0.tgz",
-			"integrity": "sha512-7i/Fz8enAQ2AN5DyJ2i2AFERufjP6x1NjuHoNgDyJkjjHxEoo8kVyyHxu1A9YyeShlksjt5FvpvENBDuivQHLA=="
+			"version": "1.2.3",
+			"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.2.3.tgz",
+			"integrity": "sha512-fu0HW3VpeQdTx2BxjcMD0pEXB6M3xYi7Cgmqr7+jtyN7hNZJGFWqqQFfyJRwP8cBGQz3WW1txBiPPf9dK2xdUg=="
 		},
 		"node_modules/@mrmlnc/readdir-enhanced": {
 			"version": "2.2.1",
@@ -5875,6 +5876,11 @@
 				"node": ">=8.0.0"
 			}
 		},
+		"node_modules/css.escape": {
+			"version": "1.5.1",
+			"resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
+			"integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s="
+		},
 		"node_modules/cssom": {
 			"version": "0.4.4",
 			"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz",
@@ -8435,9 +8441,9 @@
 			}
 		},
 		"node_modules/graceful-fs": {
-			"version": "4.2.6",
-			"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
-			"integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
+			"version": "4.2.9",
+			"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
+			"integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="
 		},
 		"node_modules/growly": {
 			"version": "1.3.0",
@@ -10418,11 +10424,11 @@
 			}
 		},
 		"node_modules/jest-mock": {
-			"version": "27.4.6",
-			"resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.6.tgz",
-			"integrity": "sha512-kvojdYRkst8iVSZ1EJ+vc1RRD9llueBjKzXzeCytH3dMM7zvPV/ULcfI2nr0v0VUgm3Bjt3hBCQvOeaBz+ZTHw==",
+			"version": "27.5.1",
+			"resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz",
+			"integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==",
 			"dependencies": {
-				"@jest/types": "^27.4.2",
+				"@jest/types": "^27.5.1",
 				"@types/node": "*"
 			},
 			"engines": {
@@ -10852,15 +10858,15 @@
 			}
 		},
 		"node_modules/jest-util": {
-			"version": "27.4.2",
-			"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz",
-			"integrity": "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==",
+			"version": "27.5.1",
+			"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz",
+			"integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==",
 			"dependencies": {
-				"@jest/types": "^27.4.2",
+				"@jest/types": "^27.5.1",
 				"@types/node": "*",
 				"chalk": "^4.0.0",
 				"ci-info": "^3.2.0",
-				"graceful-fs": "^4.2.4",
+				"graceful-fs": "^4.2.9",
 				"picomatch": "^2.2.3"
 			},
 			"engines": {
@@ -11452,9 +11458,9 @@
 			"dev": true
 		},
 		"node_modules/lit": {
-			"version": "2.1.1",
-			"resolved": "https://registry.npmjs.org/lit/-/lit-2.1.1.tgz",
-			"integrity": "sha512-yqDqf36IhXwOxIQSFqCMgpfvDCRdxLCLZl7m/+tO5C9W/OBHUj17qZpiMBT35v97QMVKcKEi1KZ3hZRyTwBNsQ==",
+			"version": "2.1.4",
+			"resolved": "https://registry.npmjs.org/lit/-/lit-2.1.4.tgz",
+			"integrity": "sha512-m1tHAZdXQhiBe0ReAjyVIUeKnHZpBfx+A5R5dkia8dtvIBwOR6KhD+RxaDnCwrEavRqkZAy5ntLv7chiOZCdNg==",
 			"dependencies": {
 				"@lit/reactive-element": "^1.1.0",
 				"lit-element": "^3.1.0",
@@ -11462,18 +11468,18 @@
 			}
 		},
 		"node_modules/lit-element": {
-			"version": "3.1.1",
-			"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.1.1.tgz",
-			"integrity": "sha512-14ClnMAU8EXnzC+M2/KDd3SFmNUn1QUw1+GxWkEMwGV3iaH8ObunMlO5svzvaWlkSV0WlxJCi40NGnDVJ2XZKQ==",
+			"version": "3.1.2",
+			"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.1.2.tgz",
+			"integrity": "sha512-5VLn5a7anAFH7oz6d7TRG3KiTZQ5GEFsAgOKB8Yc+HDyuDUGOT2cL1CYTz/U4b/xlJxO+euP14pyji+z3Z3kOg==",
 			"dependencies": {
 				"@lit/reactive-element": "^1.1.0",
 				"lit-html": "^2.1.0"
 			}
 		},
 		"node_modules/lit-html": {
-			"version": "2.1.1",
-			"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.1.1.tgz",
-			"integrity": "sha512-E4BImK6lopAYanJpvcGaAG8kQFF1ccIulPu2BRNZI7acFB6i4ujjjsnaPVFT1j/4lD9r8GKih0Y8d7/LH8SeyQ==",
+			"version": "2.1.3",
+			"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.1.3.tgz",
+			"integrity": "sha512-WgvdwiNeuoT0mYEEJI+AAV2DEtlqzVM4lyDSaeQSg5ZwhS/CkGJBO/4n66alApEuSS9WXw9+ADBp8SPvtDEKSg==",
 			"dependencies": {
 				"@types/trusted-types": "^2.0.2"
 			}
@@ -17148,7 +17154,7 @@
 			"version": "2.1.8",
 			"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
 			"integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
-			"deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.",
+			"deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies",
 			"optional": true,
 			"dependencies": {
 				"anymatch": "^2.0.0",
@@ -18826,27 +18832,27 @@
 			}
 		},
 		"@jest/environment": {
-			"version": "27.4.6",
-			"resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.4.6.tgz",
-			"integrity": "sha512-E6t+RXPfATEEGVidr84WngLNWZ8ffCPky8RqqRK6u1Bn0LK92INe0MDttyPl/JOzaq92BmDzOeuqk09TvM22Sg==",
+			"version": "27.5.1",
+			"resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz",
+			"integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==",
 			"requires": {
-				"@jest/fake-timers": "^27.4.6",
-				"@jest/types": "^27.4.2",
+				"@jest/fake-timers": "^27.5.1",
+				"@jest/types": "^27.5.1",
 				"@types/node": "*",
-				"jest-mock": "^27.4.6"
+				"jest-mock": "^27.5.1"
 			}
 		},
 		"@jest/fake-timers": {
-			"version": "27.4.6",
-			"resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.6.tgz",
-			"integrity": "sha512-mfaethuYF8scV8ntPpiVGIHQgS0XIALbpY2jt2l7wb/bvq4Q5pDLk4EP4D7SAvYT1QrPOPVZAtbdGAOOyIgs7A==",
+			"version": "27.5.1",
+			"resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz",
+			"integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==",
 			"requires": {
-				"@jest/types": "^27.4.2",
+				"@jest/types": "^27.5.1",
 				"@sinonjs/fake-timers": "^8.0.1",
 				"@types/node": "*",
-				"jest-message-util": "^27.4.6",
-				"jest-mock": "^27.4.6",
-				"jest-util": "^27.4.2"
+				"jest-message-util": "^27.5.1",
+				"jest-mock": "^27.5.1",
+				"jest-util": "^27.5.1"
 			},
 			"dependencies": {
 				"ansi-styles": {
@@ -18855,25 +18861,25 @@
 					"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="
 				},
 				"jest-message-util": {
-					"version": "27.4.6",
-					"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.6.tgz",
-					"integrity": "sha512-0p5szriFU0U74czRSFjH6RyS7UYIAkn/ntwMuOwTGWrQIOh5NzXXrq72LOqIkJKKvFbPq+byZKuBz78fjBERBA==",
+					"version": "27.5.1",
+					"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz",
+					"integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==",
 					"requires": {
 						"@babel/code-frame": "^7.12.13",
-						"@jest/types": "^27.4.2",
+						"@jest/types": "^27.5.1",
 						"@types/stack-utils": "^2.0.0",
 						"chalk": "^4.0.0",
-						"graceful-fs": "^4.2.4",
+						"graceful-fs": "^4.2.9",
 						"micromatch": "^4.0.4",
-						"pretty-format": "^27.4.6",
+						"pretty-format": "^27.5.1",
 						"slash": "^3.0.0",
 						"stack-utils": "^2.0.3"
 					}
 				},
 				"pretty-format": {
-					"version": "27.4.6",
-					"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz",
-					"integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==",
+					"version": "27.5.1",
+					"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
+					"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
 					"requires": {
 						"ansi-regex": "^5.0.1",
 						"ansi-styles": "^5.0.0",
@@ -19133,9 +19139,9 @@
 			}
 		},
 		"@jest/types": {
-			"version": "27.4.2",
-			"resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz",
-			"integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==",
+			"version": "27.5.1",
+			"resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz",
+			"integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==",
 			"requires": {
 				"@types/istanbul-lib-coverage": "^2.0.0",
 				"@types/istanbul-reports": "^3.0.0",
@@ -20227,9 +20233,9 @@
 			}
 		},
 		"@lit/reactive-element": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.2.0.tgz",
-			"integrity": "sha512-7i/Fz8enAQ2AN5DyJ2i2AFERufjP6x1NjuHoNgDyJkjjHxEoo8kVyyHxu1A9YyeShlksjt5FvpvENBDuivQHLA=="
+			"version": "1.2.3",
+			"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.2.3.tgz",
+			"integrity": "sha512-fu0HW3VpeQdTx2BxjcMD0pEXB6M3xYi7Cgmqr7+jtyN7hNZJGFWqqQFfyJRwP8cBGQz3WW1txBiPPf9dK2xdUg=="
 		},
 		"@mrmlnc/readdir-enhanced": {
 			"version": "2.2.1",
@@ -22845,6 +22851,11 @@
 				"source-map": "^0.6.1"
 			}
 		},
+		"css.escape": {
+			"version": "1.5.1",
+			"resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
+			"integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s="
+		},
 		"cssom": {
 			"version": "0.4.4",
 			"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz",
@@ -24881,9 +24892,9 @@
 			}
 		},
 		"graceful-fs": {
-			"version": "4.2.6",
-			"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
-			"integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
+			"version": "4.2.9",
+			"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
+			"integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="
 		},
 		"growly": {
 			"version": "1.3.0",
@@ -26402,11 +26413,11 @@
 			}
 		},
 		"jest-mock": {
-			"version": "27.4.6",
-			"resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.6.tgz",
-			"integrity": "sha512-kvojdYRkst8iVSZ1EJ+vc1RRD9llueBjKzXzeCytH3dMM7zvPV/ULcfI2nr0v0VUgm3Bjt3hBCQvOeaBz+ZTHw==",
+			"version": "27.5.1",
+			"resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz",
+			"integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==",
 			"requires": {
-				"@jest/types": "^27.4.2",
+				"@jest/types": "^27.5.1",
 				"@types/node": "*"
 			}
 		},
@@ -26755,15 +26766,15 @@
 			}
 		},
 		"jest-util": {
-			"version": "27.4.2",
-			"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz",
-			"integrity": "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==",
+			"version": "27.5.1",
+			"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz",
+			"integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==",
 			"requires": {
-				"@jest/types": "^27.4.2",
+				"@jest/types": "^27.5.1",
 				"@types/node": "*",
 				"chalk": "^4.0.0",
 				"ci-info": "^3.2.0",
-				"graceful-fs": "^4.2.4",
+				"graceful-fs": "^4.2.9",
 				"picomatch": "^2.2.3"
 			},
 			"dependencies": {
@@ -27236,9 +27247,9 @@
 			"dev": true
 		},
 		"lit": {
-			"version": "2.1.1",
-			"resolved": "https://registry.npmjs.org/lit/-/lit-2.1.1.tgz",
-			"integrity": "sha512-yqDqf36IhXwOxIQSFqCMgpfvDCRdxLCLZl7m/+tO5C9W/OBHUj17qZpiMBT35v97QMVKcKEi1KZ3hZRyTwBNsQ==",
+			"version": "2.1.4",
+			"resolved": "https://registry.npmjs.org/lit/-/lit-2.1.4.tgz",
+			"integrity": "sha512-m1tHAZdXQhiBe0ReAjyVIUeKnHZpBfx+A5R5dkia8dtvIBwOR6KhD+RxaDnCwrEavRqkZAy5ntLv7chiOZCdNg==",
 			"requires": {
 				"@lit/reactive-element": "^1.1.0",
 				"lit-element": "^3.1.0",
@@ -27246,18 +27257,18 @@
 			}
 		},
 		"lit-element": {
-			"version": "3.1.1",
-			"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.1.1.tgz",
-			"integrity": "sha512-14ClnMAU8EXnzC+M2/KDd3SFmNUn1QUw1+GxWkEMwGV3iaH8ObunMlO5svzvaWlkSV0WlxJCi40NGnDVJ2XZKQ==",
+			"version": "3.1.2",
+			"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.1.2.tgz",
+			"integrity": "sha512-5VLn5a7anAFH7oz6d7TRG3KiTZQ5GEFsAgOKB8Yc+HDyuDUGOT2cL1CYTz/U4b/xlJxO+euP14pyji+z3Z3kOg==",
 			"requires": {
 				"@lit/reactive-element": "^1.1.0",
 				"lit-html": "^2.1.0"
 			}
 		},
 		"lit-html": {
-			"version": "2.1.1",
-			"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.1.1.tgz",
-			"integrity": "sha512-E4BImK6lopAYanJpvcGaAG8kQFF1ccIulPu2BRNZI7acFB6i4ujjjsnaPVFT1j/4lD9r8GKih0Y8d7/LH8SeyQ==",
+			"version": "2.1.3",
+			"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.1.3.tgz",
+			"integrity": "sha512-WgvdwiNeuoT0mYEEJI+AAV2DEtlqzVM4lyDSaeQSg5ZwhS/CkGJBO/4n66alApEuSS9WXw9+ADBp8SPvtDEKSg==",
 			"requires": {
 				"@types/trusted-types": "^2.0.2"
 			}
diff --git a/packages/happy-dom/package.json b/packages/happy-dom/package.json
index 8e6c2771..984213ce 100644
--- a/packages/happy-dom/package.json
+++ b/packages/happy-dom/package.json
@@ -53,7 +53,8 @@
 		"sync-request": "^6.1.0",
 		"whatwg-encoding": "^1.0.5",
 		"whatwg-mimetype": "^2.3.0",
-		"webidl-conversions": "^7.0.0"
+		"webidl-conversions": "^7.0.0",
+		"css.escape": "^1.5.1"
 	},
 	"devDependencies": {
 		"@types/he": "latest",
diff --git a/packages/happy-dom/src/css/CSS.ts b/packages/happy-dom/src/css/CSS.ts
new file mode 100644
index 00000000..403ebc55
--- /dev/null
+++ b/packages/happy-dom/src/css/CSS.ts
@@ -0,0 +1,43 @@
+import CSSUnitValue from './CSSUnitValue';
+import CSSUnits from './CSSUnits';
+import CSSEscape from 'css.escape';
+
+/**
+ * The CSS interface holds useful CSS-related methods.
+ *
+ * Reference:
+ * https://developer.mozilla.org/en-US/docs/Web/API/CSS.
+ */
+export default class CSS {
+	/**
+	 * Constructor.
+	 */
+	constructor() {
+		for (const unit of CSSUnits) {
+			this[unit] = (value: number) => new CSSUnitValue(value, unit);
+		}
+	}
+
+	/**
+	 * Returns a Boolean indicating if the pair property-value, or the condition, given in parameter is supported.
+	 *
+	 * TODO: Always returns "true" for now, but it should probably be improved in the future.
+	 *
+	 * @param _condition Property name or condition.
+	 * @param [_value] Value when using property name.
+	 * @returns "true" if supported.
+	 */
+	public supports(_condition: string, _value?: string): boolean {
+		return true;
+	}
+
+	/**
+	 * Escapes a value.
+	 *
+	 * @param value Value to escape.
+	 * @returns Escaped string.
+	 */
+	public escape(value: string): boolean {
+		return CSSEscape(value);
+	}
+}
diff --git a/packages/happy-dom/src/css/CSSUnitValue.ts b/packages/happy-dom/src/css/CSSUnitValue.ts
new file mode 100644
index 00000000..ff29ce76
--- /dev/null
+++ b/packages/happy-dom/src/css/CSSUnitValue.ts
@@ -0,0 +1,26 @@
+import CSSUnits from './CSSUnits';
+
+/**
+ * CSS unit value.
+ */
+export default class CSSUnitValue {
+	public unit: string = null;
+	public value: number = null;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param value Value.
+	 * @param unit Unit.
+	 */
+	constructor(value: number, unit: string) {
+		if (typeof value !== 'number') {
+			throw new TypeError('The provided double value is non-finite');
+		}
+		if (!CSSUnits.includes(unit)) {
+			throw new TypeError('Invalid unit: ' + unit);
+		}
+		this.value = value;
+		this.unit = unit;
+	}
+}
diff --git a/packages/happy-dom/src/css/CSSUnits.ts b/packages/happy-dom/src/css/CSSUnits.ts
new file mode 100644
index 00000000..c0bd5d36
--- /dev/null
+++ b/packages/happy-dom/src/css/CSSUnits.ts
@@ -0,0 +1,31 @@
+export default [
+	'Hz',
+	'Q',
+	'ch',
+	'cm',
+	'deg',
+	'dpcm',
+	'dpi',
+	'dppx',
+	'em',
+	'ex',
+	'fr',
+	'grad',
+	'in',
+	'kHz',
+	'mm',
+	'ms',
+	'number',
+	'pc',
+	'percent',
+	'pt',
+	'px',
+	'rad',
+	'rem',
+	's',
+	'turn',
+	'vh',
+	'vmax',
+	'vmin',
+	'vw'
+];
diff --git a/packages/happy-dom/src/window/IWindow.ts b/packages/happy-dom/src/window/IWindow.ts
index 98d32602..76fe8298 100644
--- a/packages/happy-dom/src/window/IWindow.ts
+++ b/packages/happy-dom/src/window/IWindow.ts
@@ -37,13 +37,15 @@ import MutationObserver from '../mutation-observer/MutationObserver';
 import DOMParser from '../dom-parser/DOMParser';
 import XMLSerializer from '../xml-serializer/XMLSerializer';
 import ResizeObserver from '../resize-observer/ResizeObserver';
-import CSSStyleSheet from '../css/CSSStyleSheet';
 import Blob from '../file/Blob';
 import File from '../file/File';
 import DOMException from '../exception/DOMException';
 import FileReader from '../file/FileReader';
 import History from '../history/History';
+import CSSStyleSheet from '../css/CSSStyleSheet';
 import CSSStyleDeclaration from '../css/CSSStyleDeclaration';
+import CSS from '../css/CSS';
+import CSSUnitValue from '../css/CSSUnitValue';
 import PointerEvent from '../event/events/PointerEvent';
 import MouseEvent from '../event/events/MouseEvent';
 import FocusEvent from '../event/events/FocusEvent';
@@ -142,6 +144,8 @@ export default interface IWindow {
 	readonly URLSearchParams: typeof URLSearchParams;
 	readonly HTMLCollection: typeof HTMLCollection;
 	readonly NodeList: typeof NodeList;
+	readonly CSSUnitValue: typeof CSSUnitValue;
+	readonly CSS: CSS;
 
 	// Events
 	onload: (event: Event) => void;
diff --git a/packages/happy-dom/src/window/Window.ts b/packages/happy-dom/src/window/Window.ts
index a5f22247..c817378f 100644
--- a/packages/happy-dom/src/window/Window.ts
+++ b/packages/happy-dom/src/window/Window.ts
@@ -40,13 +40,15 @@ import ElementClass from '../config/ElementClass';
 import DOMParser from '../dom-parser/DOMParser';
 import XMLSerializer from '../xml-serializer/XMLSerializer';
 import ResizeObserver from '../resize-observer/ResizeObserver';
-import CSSStyleSheet from '../css/CSSStyleSheet';
 import Blob from '../file/Blob';
 import File from '../file/File';
 import DOMException from '../exception/DOMException';
 import FileReader from '../file/FileReader';
 import History from '../history/History';
+import CSSStyleSheet from '../css/CSSStyleSheet';
 import CSSStyleDeclaration from '../css/CSSStyleDeclaration';
+import CSS from '../css/CSS';
+import CSSUnitValue from '../css/CSSUnitValue';
 import MouseEvent from '../event/events/MouseEvent';
 import PointerEvent from '../event/events/PointerEvent';
 import FocusEvent from '../event/events/FocusEvent';
@@ -155,6 +157,7 @@ export default class Window extends EventTarget implements IWindow, NodeJS.Globa
 	public readonly HTMLCollection = HTMLCollection;
 	public readonly NodeList = NodeList;
 	public readonly MediaQueryList = MediaQueryList;
+	public readonly CSSUnitValue = CSSUnitValue;
 
 	// Events
 	public onload: (event: Event) => void = null;
@@ -278,6 +281,15 @@ export default class Window extends EventTarget implements IWindow, NodeJS.Globa
 		}
 	}
 
+	/**
+	 * The CSS interface holds useful CSS-related methods.
+	 *
+	 * @returns CSS interface.
+	 */
+	public get CSS(): CSS {
+		return new CSS();
+	}
+
 	/**
 	 * Evaluates code.
 	 *


Test patch:
diff --git a/packages/happy-dom/test/css/CSS.test.ts b/packages/happy-dom/test/css/CSS.test.ts
new file mode 100644
index 00000000..b251da8c
--- /dev/null
+++ b/packages/happy-dom/test/css/CSS.test.ts
@@ -0,0 +1,38 @@
+import CSS from '../../src/css/CSS';
+import CSSUnits from '../../src/css/CSSUnits';
+import CSSUnitValue from '../../src/css/CSSUnitValue';
+
+describe('CSS', () => {
+	let css: CSS = null;
+
+	beforeEach(() => {
+		css = new CSS();
+	});
+
+	for (const property of CSSUnits) {
+		describe(`${property}()`, () => {
+			it('Returns an instance of CSSUnitValue.', () => {
+				const cssUnitValue: CSSUnitValue = css[property](100);
+				expect(cssUnitValue.unit).toBe(property);
+				expect(cssUnitValue.value).toBe(100);
+			});
+		});
+	}
+
+	describe('supports()', () => {
+		it('Always returns "true".', () => {
+			expect(css.supports('condition')).toBe(true);
+			expect(css.supports('property', 'value')).toBe(true);
+		});
+	});
+
+	describe('escape()', () => {
+		it('Escapes a value.', () => {
+			expect(css.escape('.foo#bar')).toBe('\\.foo\\#bar');
+			expect(css.escape('()[]{}')).toBe('\\(\\)\\[\\]\\{\\}');
+			expect(css.escape('--a')).toBe('--a');
+			expect(css.escape('0')).toBe('\\30 ');
+			expect(css.escape('\0')).toBe('\ufffd');
+		});
+	});
+});
diff --git a/packages/happy-dom/test/css/CSSUnitValue.test.ts b/packages/happy-dom/test/css/CSSUnitValue.test.ts
new file mode 100644
index 00000000..70297b73
--- /dev/null
+++ b/packages/happy-dom/test/css/CSSUnitValue.test.ts
@@ -0,0 +1,17 @@
+import CSSUnitValue from '../../src/css/CSSUnitValue';
+
+describe('CSSUnitValue', () => {
+	describe('constructor()', () => {
+		it('Creates an instance of CSSUnitValue.', () => {
+			const cssUnitValue = new CSSUnitValue(5, 'cm');
+			expect(cssUnitValue.unit).toBe('cm');
+			expect(cssUnitValue.value).toBe(5);
+		});
+
+		it('Throws exception when invalid unit.', () => {
+			expect(() => new CSSUnitValue(5, 'invalid')).toThrowError(
+				new TypeError('Invalid unit: invalid')
+			);
+		});
+	});
+});