Game Changer ? :has() πΈ https://survey.devographics.com/survey/state-of-css/2022 CSS π₯ β Subgrid β @container β :has() β :where() β Cascade β Layers(@layer) ς±ς± :has() π https://developer.chrome.com/blog/has-m105/ :has() ? π€ :has() Parent Selector! Family Selector πͺ /* special */ li.special { ... } /* <article> <span> */ article p span { ... } /* <h1> <ul> <p> */ h1 + ul + p { ... } Before :has() CSS <target>:has(<condition>) { <styles> } After :has() <div class="everybody"> <div> <div class="a-good-time"></div> </div> </div> <div class="everybody"></div> .everybody:first-of-type { animation: party 21600s forwards; } π€ Before :has() <div class="everybody"> <div> <div class="a-good-time"></div> </div> </div> <div class="everybody"></div> .everybody:has(.a-good-time) { animation: party 21600s forwards; } ς±ς± After :has() Cards https://codepen.io/web-dot-dev/pen/JjLJyWx <ul> <li class="card"> ... </li> <li class="card"> ... </li> <li class="card"> ... </li> <li class="card"> ... </li> <li class="card"> ... </li> </ul> /* Grid */ .card:has(.card__banner) { grid-row: 1; grid-column: 1 / -1; } .card:has(.card__media) { grid-template-columns: 1fr 1fr; grid-template-rows: repeat(3, auto); } .card__media { grid-column: 2; grid-row: 1 / -1; } Forms https://codepen.io/web-dot-dev/pen/ZExyJKx <form action=""> <div class="form-group"> <label for="email" class="form-label"> <span class="sr-only">Email</span> </label> <div class="form-group__input"> <input required type="email" id="email" class="form-input" pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$" title="Enter valid email address" placeholder="Enter valid email address"/> <div class="form-group__error">Enter a valid email address</div> </div> </div> </form> /* invalid */ .form-group:has(:invalid) { --color: var(--invalid); } .form-group:has(:invalid:not(:focus):not(:placeholder- shown )) .form-group__error { display: block; } Content https://codepen.io/web-dot-dev/pen/abYwyWQ <main> <article> <h1>Some Awesome Article</h1> <p> ... </p> <figure> <img alt="" width="200" height="200" src="https://assets.codepen.io/605876/team-awesome.png" /> </figure> <p> ... </p> <figure> <img alt="" width="200" height="200" src="https://assets.codepen.io/605876/team-awesome.png" /> <figcaption>Shot of the CSS, UI, and DevTools Chrome Dev</figcaption> </figure> <p> ... </p> </article> </main> figure:not(:has(figcaption)) { float: left; margin: 2rem 2rem 2rem 0; } Reacting to State https://codepen.io/web-dot-dev/pen/YzaQxQK const NAV_CONTROL = document.querySelector('.nav-control') const CONTROL_NAV = () => { NAV_CONTROL.setAttribute('aria-expanded', NAV_CONTROL.matches('[aria-expanded="false"]') ? true : false) NAV_CONTROL.setAttribute('aria-pressed', NAV_CONTROL.matches('[aria-expanded="false"]') ? true : false) } NAV_CONTROL.addEventListener('click', CONTROL_NAV) body { transform: translateX(calc(var(--open) * -200px)); } :root:has([aria-expanded="true"]) { --open: 1; }