<h1>Creating new Selectors with <code>:has()</code>:<br />A <code>:nth-child(n of S)</code> polyfill</em></h1>

<div class="no-support" data-support="css-nth-child-of-s" data-level="warn"><p>⚠️ Your browser does not support the <code>:nth-child(1 of S)</code>/<code>:nth-last-child(1 of S)</code> selectors but that’s no biggie. Thanks to <code>:not()</code> and <code>:has()</code> we can polyfill it.</p></div>
<div class="has-support" data-support="css-nth-child-of-s"><p>✅ Your browser supports the <code>:nth-child(1 of S)</code>/<code>:nth-last-child(1 of S)</code> selectors. However, they are not used because this demo demonstrates how <code>:not()</code> and <code>:has()</code> can polyfill them.</p></div>
<div class="no-support" data-support="css-has-basic"><p>🚨 Your browser does not support CSS <code>:has()</code>, so this demo will not work correctly.</p></div>
<div class="no-support" data-support="css-has-relative"><p>🚨 Your browser does not support relative selectors in CSS <code>:has()</code>, so this demo will not work correctly.</p></div>

<h2>What?</h2>
<p>This page is a demo for <a href="https://brm.us/nth-child-polyfill" target="_top">https://brm.us/nth-child-polyfill</a>. Please read the post to get the full details and explanation.</p>

<h2>The Rules</h2>

<ul>
	<li><code>:nth-child()</code>: The <code>.special</code> children, from first to last, have rainbow colors: <code>red</code>, <code>orange</code>, <code>yellow</code>, <code>green</code>, <code>blue</code>, <code>indigo</code>, and <code>violet</code>.</li>
	<li><code>:nth-last-child()</code>: The <code>.special</code> children, from last to first, have a different border thickness.</li>
</ul>

<p>Typically you’d use <code>:nth-child(n of S)</code> for this, but thanks to <code>:has()</code> we can polyfill it.</p>

<h2>Demo</h2>

<div>
	<p><em>TIP: You can click each paragraph to toggle the <code>.special</code> class</em></p>
</div>

<div class="demo">
	<p class="special">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Eaque in, enim rem recusandae mollitia error, natus ab atque dignissimos culpa veniam exercitationem sequi voluptates, commodi corrupti ullam sit. Debitis, a!</p>
	<p class="special">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Eaque in, enim rem recusandae mollitia error, natus ab atque dignissimos culpa veniam exercitationem sequi voluptates, commodi corrupti ullam sit. Debitis, a!</p>
	<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Eaque in, enim rem recusandae mollitia error, natus ab atque dignissimos culpa veniam exercitationem sequi voluptates, commodi corrupti ullam sit. Debitis, a!</p>
	<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Eaque in, enim rem recusandae mollitia error, natus ab atque dignissimos culpa veniam exercitationem sequi voluptates, commodi corrupti ullam sit. Debitis, a!</p>
	<p class="special">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Eaque in, enim rem recusandae mollitia error, natus ab atque dignissimos culpa veniam exercitationem sequi voluptates, commodi corrupti ullam sit. Debitis, a!</p>
	<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Eaque in, enim rem recusandae mollitia error, natus ab atque dignissimos culpa veniam exercitationem sequi voluptates, commodi corrupti ullam sit. Debitis, a!</p>
	<p class="special">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Eaque in, enim rem recusandae mollitia error, natus ab atque dignissimos culpa veniam exercitationem sequi voluptates, commodi corrupti ullam sit. Debitis, a!</p>
	<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Eaque in, enim rem recusandae mollitia error, natus ab atque dignissimos culpa veniam exercitationem sequi voluptates, commodi corrupti ullam sit. Debitis, a!</p>
	<p class="special">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Eaque in, enim rem recusandae mollitia error, natus ab atque dignissimos culpa veniam exercitationem sequi voluptates, commodi corrupti ullam sit. Debitis, a!</p>
	<p class="special">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Eaque in, enim rem recusandae mollitia error, natus ab atque dignissimos culpa veniam exercitationem sequi voluptates, commodi corrupti ullam sit. Debitis, a!</p>
</div>
:where(.demo > *) {
	margin: 0;
	padding: 0.5em 1em;
	border: 1px solid transparent; /* We set a transparent border on all sides to prevent a layout jump when actually painting the border */
	cursor: pointer;
	transition: all 0.5s ease-in-out;
}

/* Basic .special styling */
.special {
	background: rgb(0 0 0 / 0.1);
	border-left: 1px solid currentcolor;
}

/* :nth-child(1 of .special) */
.special:not(.special ~ .special) {
	color: red;
}

/* :nth-child(2 of .special) */
.special ~ .special:not(.special ~ .special ~ .special) {
	color: orange;
}

/* :nth-child(3 of .special) */
.special ~ .special ~ .special:not(.special ~ .special ~ .special ~ .special) {
	color: yellow;
}

/* :nth-child(4 of .special) */
.special ~ .special ~ .special ~ .special:not(.special ~ .special ~ .special ~ .special ~ .special) {
	color: green;
}

/* :nth-child(5 of .special) */
.special ~ .special ~ .special ~ .special ~ .special:not(.special ~ .special ~ .special ~ .special ~ .special ~ .special) {
	color: blue;
}

/* :nth-child(6 of .special) */
.special ~ .special ~ .special ~ .special ~ .special ~ .special:not(.special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special) {
	color: indigo;
}

/* :nth-child(7 of .special) */
.special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special:not(.special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special) {
	color: violet;
}

/* :nth-last-child(1 of .special) */
.special:not(:has(~ .special)) {
    border-left-width: 50px;
}

/* :nth-last-child(2 of .special) */
.special:not(:has(~ .special ~ .special)):not(.special:not(:has(~ .special))) {
    border-left-width: 45px;
}

/* :nth-last-child(3 of .special) */
.special:not(:has(~ .special ~ .special ~ .special)):not(.special:not(:has(~ .special ~ .special))) {
    border-left-width: 40px;
}

/* :nth-last-child(4 of .special) */
.special:not(:has(~ .special ~ .special ~ .special ~ .special)):not(.special:not(:has(~ .special ~ .special ~ .special))) {
    border-left-width: 35px;
}

/* :nth-last-child(5 of .special) */
.special:not(:has(~ .special ~ .special ~ .special ~ .special ~ .special)):not(.special:not(:has(~ .special ~ .special ~ .special ~ .special))) {
    border-left-width: 30px;
}

/* :nth-last-child(6 of .special) */
.special:not(:has(~ .special ~ .special ~ .special ~ .special ~ .special ~ .special)):not(.special:not(:has(~ .special ~ .special ~ .special ~ .special ~ .special))) {
    border-left-width: 25px;
}

/* :nth-last-child(7 of .special) */
.special:not(:has(~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special)):not(.special:not(:has(~ .special ~ .special ~ .special ~ .special ~ .special ~ .special))) {
    border-left-width: 20px;
}

/* :nth-last-child(8 of .special) */
.special:not(:has(~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special)):not(.special:not(:has(~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special))) {
    border-left-width: 15px;
}

/* :nth-last-child(9 of .special) */
.special:not(:has(~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special)):not(.special:not(:has(~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special))) {
    border-left-width: 10px;
}

/* :nth-last-child(10 of .special) */
.special:not(:has(~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special)):not(.special:not(:has(~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special ~ .special))) {
    border-left-width: 5px;
}

/* 💡 See https://codepen.io/bramus/pen/rNKErPe to generate more selectors … */


/* Non-demo styles below */
@layer base {
	@layer layout {
		html {
			max-width: 84ch;
			padding: 3rem 2rem;
			margin: auto;
			line-height: 1.5;
			font-size: 1.25rem;
		}
		body {
			margin: 0;
			padding: 0;
		}
		a,
		a:visited {
			color: blue;
		}
		
		h2 {
			margin-top: 2em;
		}
		
		h1 {
			display: none;
		}
	}
	
	@layer code {
		pre {
			border: 1px solid #dedede;
			padding: 1em;
			background: #f7f7f7;
			font-family: "Courier 10 Pitch", Courier, monospace;
			overflow-x: auto;
			border-left: 0.4em solid cornflowerblue;
			tab-size: 4;
		}
		
		code:not(pre code) {
			background: #f7f7f7;
			border: 1px solid rgb(0 0 0 / 0.2);
		}
	}

	@layer support {
		.no-support,
		.has-support {
			margin: 1em 0;
			padding: 1em;
			border: 1px solid #ccc;
		}

		.no-support {
			background-color: #ff00002b;
			display: block;
		}
		.no-support[data-level="warn"] {
			background-color: #ffff002b;
		}
		.has-support {
			background-color: #00ff002b;
			display: none;
		}
		:is(.has-support, .no-support) > :first-child {
			margin-top: 0;
		}
		:is(.has-support, .no-support) > :last-child {
			margin-bottom: 0;
		}

		@supports selector(:has(*)) {
			.no-support[data-support="css-has-basic"] {
				display: none;
			}
			.has-support[data-support="css-has-basic"] {
				display: block;
			}
		}

		@supports selector(:has(+ *)) {
			.no-support[data-support="css-has-relative"] {
				display: none;
			}
			.has-support[data-support="css-has-relative"] {
				display: block;
			}
		}

		@supports selector(:nth-child(1 of .foo)) {
			.no-support[data-support="css-nth-child-of-s"] {
				display: none;
			}
			.has-support[data-support="css-nth-child-of-s"] {
				display: block;
			}
		}
	}
}

@layer reset {
	
}
document.querySelectorAll('.demo p').forEach($p => {
	$p.addEventListener('click', (e) => {
		e.target.classList.toggle('special');
	});
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.