Home >Web Front-end >CSS Tutorial >Creating Animated, Clickable Cards With the :has() Relational Pseudo Class

Creating Animated, Clickable Cards With the :has() Relational Pseudo Class

Christopher Nolan
Christopher NolanOriginal
2025-03-10 12:21:13399browse

Creating Animated, Clickable Cards With the :has() Relational Pseudo Class

Chrome and Safari browsers have fully supported the :has() pseudo-class of CSS, which is gradually being launched in many browsers. It is often called a "parent selector" - we can select and set the style of the parent element through child selectors - but :has() is used far more than that. One of the uses is to redesign the clickable card mode that many people often use.

We will explore :has()How to help us with link cards, but first...

:has()What is a pseudo-class?

There are many excellent articles that explain the purpose of :has() well, but it is still relatively new, so we should also briefly introduce it here.

:has() is a relational pseudo-class that is part of the W3C selector level 4 working draft. This is what brackets are for: match elements associated with a specific child element (more precisely, containing a specific child element).

<code>/* 匹配包含图像元素的article元素 */
article:has(img) { }

/* 匹配article元素,其内部直接包含图像 */
article:has(> img) { }</code>

So you can understand why we might refer to it as a "parent" selector. But we can also use it in conjunction with other functional pseudo-classes to get a more specific match. Suppose we want to style the article does not contain any images. We can combine the relationship ability of with the negative ability of :has() to achieve this: :not()

<code>/* 匹配不包含图像的article元素 */
article:not(:has(img)) { }</code>
But this is just the beginning of how we can combine various capabilities to achieve more functions using

. Before we specifically solve the clickable card puzzle, let's take a look at some of the ways to deal with them without using :has(). :has()

How do we currently deal with clickable cards

Nowadays, there are three main ways for people to create fully clickable cards. In order to fully understand the powerful functions of this pseudo-class, it is necessary to summarize it.

"Link as wrapper" method

This method is often used. I never use this method, but I created a quick demo to demonstrate it:

There are many issues here, especially when it comes to accessibility. When users browse your website using the rotator feature, they hear the full text inside the

element - title, text, and link. Some people may not want to listen to all of this. We can do better. Starting with HTML5, we can nest block elements in <a></a> elements. But this always feels wrong to me, especially for this reason. <a></a>

Pros:

    Quickly implement
  • Semantic correct

Disadvantages:

    Accessibility Issues
  • Text not selectable
  • It's very troublesome to override the styles used in the default link
JavaScript Method

With JavaScript, we can attach links to cards instead of writing them into tags. I found this awesome CodePen demo by costdev, which also makes card text optional in the process:

This method has many benefits. Our links are accessible when focused and we can even select text. But there are some disadvantages in terms of style. For example, if we want to animate these cards, we have to add the .card style in the :hover main wrapper instead of the link itself. We also don't benefit from animation when the link is focused through the keyboard tab keys.

Pros:

  • Full accessibility can be achieved
  • Selectable text

Disadvantages:

  • JavaScript is required
  • Cannot right-click (although it can be fixed with some extra scripts)
  • A lot of styles are required to be done on the card itself, which does not work when focusing on the links

::afterSelector method

This method requires us to set the card to relative positioning and then set the absolute positioning on the linked ::after pseudo selector. This does not require any JavaScript and is easy to implement:

There are some drawbacks here, especially when it comes to selecting text. You won't be able to select text unless you provide a higher z-index on the card body, but if you do, be aware that clicking on text won't activate your link. Whether you want selectable text is up to you. I think this might be a UX issue, but it depends on the use case. The text is still accessible via a screen reader, but my main problem with this approach is the lack of animation possibilities.

Pros:

  • Easy to implement
  • Accessible links, no redundant text
  • Effected when hovering and focusing

Disadvantages:

  • Text not selectable
  • You can only animate the link because this is the element you hover.

A new method: use ::after in combination with :has()

Now that we have identified existing methods for clickable cards, I would like to show how to add :has() to the mix to solve most of these shortcomings.

In fact, let's base this approach on the method we last viewed using ::after on the link element. We can actually use :has() there to overcome the animation limitations of the method.

Let's start with the marker:

<code>/* 匹配包含图像元素的article元素 */
article:has(img) { }

/* 匹配article元素,其内部直接包含图像 */
article:has(> img) { }</code>

To keep it simple, I will position elements directly in CSS, instead of using classes.

For this demo, we will add image scaling and shadows to the card for hovering and animate the links so that the arrow pops up and changes the text color of the links. To simplify operations, we will add some scoped custom properties to the card. This is the basic style:

<code>/* 匹配包含图像元素的article元素 */
article:has(img) { }

/* 匹配article元素,其内部直接包含图像 */
article:has(> img) { }</code>

Very good! We have added the initial scaling (--img-scale: 1.001), the initial color of the card title (--title-color: black) and some extra properties we will use to make the arrow pop up from the link. We also set the empty state of the box-shadow declaration to be animate it later. This sets the basis for the clickable cards we need to create now, so let's add some resets and styles by adding these custom properties to the elements we want to animate:

<code>/* 匹配不包含图像的article元素 */
article:not(:has(img)) { }</code>

Let's be user-friendly and add a class hidden in the screen reader behind the link:

<img src="/static/imghwm/default1.png" data-src="https://img.php.cn/" class="lazy" alt="Creating Animated, Clickable Cards With the :has() Relational Pseudo Class "><div clas="article-body">
    <h2>Some Heading</h2>
    <p>Curabitur convallis ac quam vitae laoreet. Nulla mauris ante, euismod sed lacus sit amet, congue bibendum eros. Etiam mattis lobortis porta. Vestibulum ultrices iaculis enim imperdiet egestas.</p>
    <a href="https://www.php.cn/link/93ac0c50dd620dc7b88e5fe05c70e15b">
      Read more
       <svg fill="currentColor" viewbox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" fill-rule="evenodd"></path></svg></a>
  </div>

Our cards are starting to look beautiful. It's time to add some magic to it. Using the :has() pseudo-class, we can now check if our link is hovered or focused, then update our custom properties and add box-shadow. With this small amount of CSS code, our cards are truly come to life:

/* 卡片元素 */
article {
  --img-scale: 1.001;
  --title-color: black;
  --link-icon-translate: -20px;
  --link-icon-opacity: 0;

  position: relative;
  border-radius: 16px;
  box-shadow: none;
  background: https://www.php.cn/link/93ac0c50dd620dc7b88e5fe05c70e15bfff;
  transform-origin: center;
  transition: all 0.4s ease-in-out;
  overflow: hidden;
}
/* 链接的::after伪元素 */
article a::after {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline: 0;
  cursor: pointer;
}

Did you see the above content? Now, if any child elements in the card are hovered or focused, we will get updated styles. Even if the link element is the only element that can contain a hover or focus state in the clickable card method, we can use it to match the parent element and apply the transformation. ::afterThat's it. Another powerful use case for selectors. We can not only match the parent element by declaring other elements as parameters, but also use pseudo-classes to match and set the style of the parent element.

:has()Pros:

Accessible

    Anime can be set
  • No JavaScript required
  • Use on the correct element
  • :hover
  • Disadvantages:

Text is not easy to choose.

    Browser support is limited to Chrome and Safari (in Firefox, it is supported behind the logo).
  • This is a demonstration using this technique. You may notice an extra wrapper around the card, but this is just a few of the attempts I made when using container queries, which is just one of some other great features that are being launched in all major browsers.
Do you have some other examples you want to share? The comments section is very welcome to other solutions or ideas.

The above is the detailed content of Creating Animated, Clickable Cards With the :has() Relational Pseudo Class. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:Is There Too Much CSS Now?Next article:None