A Powerful CSS Pseudo Class, Let's Take a Look at CSS :has()
Tags: webdev, beginners, css
Published: 2022-12-18 17:23:29

## Introduction

Well, since CSS got upgraded to version 3 in 1998, A lot of things happened, and until now, CSS has already got many features that we can use to enhance our website to be more beautiful and interactive.

Web Developer will never leave their CSS behind because it's one of the cores of the technology behind the web, current CSS version let us use our creativity by crafting modern and accessible web applications.

But more features mean we need more time to think about how it works _(again)_, although most modern web apps use CSS framework for managing their stylesheet, enhancing our fundamentals about the core of the CSS framework itself is necessary.

CSS has never been easy, not a few people understand how CSS works _(including me)_, but there is a person out there ready to help you fall in love with CSS, [check out his YouTube channel](https://www.youtube.com/kevinpowell "Kevin Powell's youtube channel").

One of the problems is that CSS is not a programming language, so it's very hard to debug when something goes wrong, and you might think _" CSS is quite easy, we change something, the UI reflected, what's the hard part?"_. That's what I thought when I was using [Bootstrap](https://getboostrap.com 'Bootstrap Website'), but the hard part is when you do all the stuff and some elements didn't quite fit with your expectation, like setting how to set _this style_ to a specific element that contains _this_.

Well if you back to 1998 to do all those stuff, it's going to be challenging, but don't worry we now have the feature to do all those stuff.

It's a **CSS pseudo-class** that will handle all of those for you. Just imagine you want to target an element that contains something and also the element shouldn't contain something again, it's like a condition in a programming language.

```ts
if(somethingOk && somethingOkToo) // do the stuff
```

Pretty cool right? now before we talk about this feature, let's talk a little bit about what **CSS pseudo-class** is.

### What is CSS pseudo-class?

In CSS, A pseudo-class is a keyword added to a selector that specifies a special state of the selected element(s). For example, the pseudo-class `:hover` can be used to select a button when a user's pointer hovers over the button and this selected button can then be styled.

I'm not going to talk much about what pseudo-class is, but here's a simple explanation of it, we will have a button with a black background color, and the text color will be white, I'm also going to add some padding.

```css
.button {
  padding: 0.75rem;
  background-color: black;
  color: white;
}
```

Result:

![result-1](https://ik.imagekit.io/mlnzyx/css-has/css-has-btn)

We have a nice button there, now let's add interaction, such as color change when the user hovers over the element with `:hover` pseudo-class.

```css
.button {
  padding: 0.75rem;
  background-color: black;
  color: white;
}

.button:hover {
  background-color: red;
}
```

Now the button would look like this:

![button with hover](https://ik.imagekit.io/mlnzyx/css-has/css-has-btn-hover)

After I added the `:hover` pseudo-class, the button will change it's color if I hover over the element, that's my simple explanation about the pseudo-class.

## What is CSS :has() pseudo-class?

The functional `:has()` CSS pseudo-class represents an element if any of the relative selectors that are passed as an argument match at least one element when anchored against this element. This pseudo-class presents a way of selecting a parent element or a previous sibling element concerning a reference element by taking a forgiving relative selector list as an argument.

- **Q:** Why it's called a functional?
- **A:** Because this type of pseudo-class accepts parameters rather than just calling it like `:hover`

CSS `:has()` pseudo-class will accept [forgiving relative element](https://developer.mozilla.org/en-US/docs/Web/CSS/Selector_list#forgiving_selector_list) and will apply a style if the parameters are valid as [specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity).

CSS `:has()` pseudo-class often described as _"Parent Selector"_ because a lot of people use it to target the parent element but then they actually want to select a specific element that matches with the condition.

As such, you might want to chill and understand how `:has()` works, this might break your mental model about the CSS itseld, now to simplify how `:has()` works, take a look at this CSS snippet:

```css
/* Matches <a> elements that contain an <span> child with a class colored */
a:has(span.colored) {
  /*...*/
}

/* Matches <a> elements that directly contain an <img> child */
a:has(> img) {
  /*...*/
}

/* Matches <section> elements that DON'T contain any heading elements: */
section:not(:has(h1, h2, h3, h4, h5, h6)) {
  /*...*/
}
```

### CSS :has() examples

Let's take a look at these example of how the CSS pseudo-class `:has()` works

```html
<main>
  <section>
    <h1>Punctuation</h1>
    <p>A simple punctuation will never arrive at a dragon's house tonight.</p>
  </section>

  <section>
    <h1 id="vergil">Punctuation</h1>
    <p>Hi Andrew can I borrow your pen?</p>
    <p>Lorem ipsum dolor sit amet constectum adpisicing elit.</p>
  </section>
</main>
```

```css
section:has(h1#vergil) {
  color: blue;
}
```

The result is going to look like this:

![css has example](https://ik.imagekit.io/mlnzyx/css-has/css-has-example)

So what is happening? as you can see, I'm targetting **the section element** that has an `h1` element with an **id** of **vergil**, and then **the whole section** will have a text color of blue.

It's kinda confusing if you read this pseudo-class for the first time, but you should feel comfortable later.

Another example is when your website has a lot of images and some of the images will have a `figcaption` in them. This way you can use a different style to the image that has a `figcaption` by using CSS `:has()` pseudo-class.

```html
<div class="container">
  <figure>
    <img src="/mr-crab-dank.jpg" alt="Mr. Crab" />
  </figure>
  <figure>
    <img src="/your-ms-puff.jpg" alt="Ms. Puff" />
    <figcaption>Ms. Puff waving at you</figcaption>
  </figure>
</div>
```

Also with a little bit of _base styling_ with this CSS

```css
* {
  margin: 0;
  padding: 0;
}

.container {
  padding-top: 0.875rem;
  width: 91%;
  margin: 0 auto;
  max-width: 524px;
  display: flex;
  flex-direction: column;
  gap: 0.765rem;
}

.container figure {
  width: 100%;
}

figure img {
  display: block;
  width: 50%;
  margin: 0 auto;
}
```

The result will look like this

![mr crab & ms puff](https://ik.imagekit.io/mlnzyx/tr:w-768,h-582/css-has/mr-crab-ms-puff)

Now we have 2 images that contain Mr. Crab and Ms. Puff, but you as can see between the images, only Ms. Puff who have a
descriptive `figcaption`.

Now let's style an image that contains `figcaption` to be different from the other images. I'm going to style it to have padding and box-shadow.

```css
figure:has(img + figcaption) {
  padding: 0.75rem;
  box-shadow: 2px 2px 4px 1px rgba(0, 0, 0, 0.25);
}
```

And the result will be like this

![mr crab ms puff edit](https://ik.imagekit.io/mlnzyx/css-has/mr-crab-ms-puff-edited)

I simply add some padding with a box-shadow to the `<figure>` element, if the `<figure>` element has a child that is an `<img>` element but also has `<figcaption>` element that is a sibling of the `<img />` element.

> I hope I explained well with that sentence 😅

But the point is I can style the `<figure>` element but with a condition if the element has a certain element or is followed by another selector by using CSS `:has()` pseudo-class.

CSS `:has()` can also be used along with another pseudo-class, for example using `:nth-child(n)` to manage grid column. This can be useful if you don't want to use [Media Queries](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries 'Media Queries, MDN Web Docs') that much.

```css
/* This will apply if a container has 4 children or more */
.container:has(:nth-child(5)) {
  ...;
}

/* This will apply if a container has 4 children or more */
.container:has(:nth-child(10)) {
  ...;
}
```

The above snippet can be used to modify our grid column to be 1 when the container has 5 or more items, but when the container has 10 or more items, a different style can be applied, for example, styling a grid column to be 2.

### Browser Compatibility

![cross browser](https://ik.imagekit.io/mlnzyx/css-has/css-has-compatibility)

CSS pseudo-class `:has()` is now already supported on many browsers, including **Chrome**, and **Edge**, but not for Internet Explorer and Firefox.

[Internet Explorer is already dead](https://www.wired.com/story/microsoft-internet-explorer-is-finally-really-fully-dead/, 'Article from wired.com that tells Internet Explore has been shut down by Microsoft') anyway so this is not a problem because so many people already use a modern web browser like Edge or Chrome.

> But be careful, CSS `:has()` is not supported on Firefox, but it can be enabled, so you need to be aware of this one, as of today, there are a lot of people still using FireFox.

#### Support Fallback

As on firefox, CSS `:has()` pseudo-class is not enabled by default, you might need to think about the fallback, fortunately, we have [CSS at-rule](https://developer.mozilla.org/en-US/docs/Web/CSS/@supports 'at-rules supports') to handle if the browser support some rules or style.

```css
@supports (selector(:has(p))) {
  /* Supported! */
}
```

This will seek if the browser supports the CSS `:has()` pseudo-class.

## Closing

And that's it, folks, We're reaching the end of this post, thank you so much to read the blog till the last part. I really appreciate and I hope this post is useful for you.