skip to content
Nikolas Barwicki - Javascript Blog Nikolas's Blog

6 practical uses of the CSS :has selector

/ 9 min read

In the ever-evolving landscape of web development, CSS continues to offer powerful tools that simplify the way we style web pages. Among these tools, the CSS :has selector stands out for its ability to apply styles based on the presence of certain child elements within a component. This capability introduces a new level of dynamism and conditionality to CSS, traditionally achievable only through JavaScript.

In this article, we deep dive into practical, real-life examples of the :has selector in action, showcasing its potential to enhance UI/UX design, simplify coding practices, and maintain cleaner, more efficient stylesheets. From highlighting urgent items in a list to dynamically adjusting form layouts, each example will provide you with insights and techniques to leverage this powerful selector in your front-end development projects.

1. Styling a <div> that Contains a Specific <button>

Consider a user interface where certain <div> elements contain a <button> with a class .urgent. You want these <div> containers to have a distinct background color to draw attention to them, differentiating urgent actions from regular ones. Here’s how you might write the CSS:

div:has(> button.urgent) {
  background-color: #ffcccc; /* Light red background */
  border-left: 5px solid red; /* Strong red left border */
  padding: 10px;
  margin-top: 20px;
}

Explanation:

The :has selector is used here to target any <div> that directly contains a <button> with the class .urgent. The > combinator is crucial as it specifies direct children, ensuring that the style is not applied to <div> elements where the .urgent button is nested further down the DOM tree.

In this example, the selected <div> elements are styled to have a light red background and a bold red left border, instantly signaling importance to the user. The padding and margin improve the visual appeal and readability by providing space inside the <div> and separating it from surrounding elements.

2. Highlighting Lists with Specific Items

Consider a scenario where we want to highlight a list if it contains items marked as “urgent”. Here’s how you can achieve this using the :has selector:

ul:has(li.urgent) {
  background-color: #ffdddd;
  border-left: 5px solid red;
}

In this example, any <ul> element containing at least one <li> with the class .urgent will have a light red background and a bold red left border. This visual distinction makes it immediately apparent which lists contain urgent items.

Explanation:

The :has selector checks for a specified condition inside its parent element. In the code snippet above, the selector ul:has(li.urgent) applies styles to the <ul> element if and only if there is at least one <li> child with the class .urgent. This approach is particularly advantageous because it allows developers to apply styles based on child content without JavaScript, reducing complexity and improving performance.

3. Highlighting Task Lists with Overdue Items

Suppose you have a task management application where tasks are categorized under different lists. Each task within a list can be flagged as “overdue”. Using the :has selector, we can highlight any list that contains overdue tasks to alert users effectively.

<ul class="task-list">
    <li class="task">Pay bills</li>
    <li class="task overdue">Submit report</li>
    <li class="task">Schedule meeting</li>
</ul>
<ul class="task-list">
    <li class="task">Write blog post</li>
    <li class="task">Update resume</li>
</ul>
ul.task-list:has(li.overdue) {
    border: 2px solid red;
    background-color: #ffcccc;
}

Explanation:

In the above example, the :has selector targets any <ul> element with the class .task-list that contains at least one <li> element with the class .overdue. The targeted list is then styled with a red border and a light red background, making it stand out on the page. This visual cue can help users instantly recognize lists that require urgent attention.

This method bypasses the traditional approach where JavaScript would be used to traverse the DOM and apply styles dynamically. With the :has selector, the styling becomes cleaner and more declarative. The CSS engine handles the conditional formatting internally, making the front-end code less complex and potentially more performant.

4. Enhancing Form Usability

The usability of forms on any website plays a crucial role in the overall user experience. Efficient and dynamic forms can greatly enhance interaction and user satisfaction. The CSS :has selector opens up possibilities for enhancing form usability by allowing developers to apply styles conditionally based on the presence of certain child elements or specific attributes within a form. Let’s explore how this selector can be leveraged to modify the appearance and behavior of form elements dynamically.

Dynamic Label Enhancement

Often, form elements require visual emphasis when they are mandatory. Traditionally, this might be handled via JavaScript, but with the :has selector, you can simplify this process using pure CSS. Consider a form where certain input fields are marked as required. You might want to style these labels differently to catch the user’s attention immediately.

Here’s how you could apply a bold and colored label to required fields using the :has selector:

/* CSS to style labels for required input fields */
form label:has(+ input[required]) {
  color: #d32f2f;  /* Red color for emphasis */
  font-weight: bold;
}

In this example, the :has selector targets any label element that is immediately followed by an input element with the required attribute. The plus sign (+) denotes an adjacent sibling combinator, which means that the styling will only apply if the input directly follows the label.

Visual Feedback for Input Validation

Another practical use of the :has selector in forms is to provide visual feedback based on input validation states. For instance, if an input field contains an incorrect or incomplete value, you might want to highlight its surrounding borders or change the background color to indicate an error.

/* CSS to highlight input fields with validation errors */
form:has(input:invalid) {
  border: 1px solid #e53935;  /* Red border for error indication */
  background-color: #ffebee;  /* Light red background for better visibility */
}

This snippet demonstrates how to use the :has selector to apply styles to a form if it contains an input element that is in an invalid state (:invalid). This allows for immediate visual cues to users, which can help prevent submission errors and improve form completion rates.

Adapting Form Layouts Based on Content

Sometimes, the layout of form elements needs to be adapted based on the type or quantity of inputs present. For example, a form intended for both desktop and mobile view might need different layouts depending on the presence of multiple choice versus text input fields.

/* CSS to adjust form layouts dynamically */
form:has([type="checkbox"]), form:has([type="radio"]) {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
}

form:has([type="text"], [type="email"]) {
  display: flex;
  flex-direction: column;
}

This code uses the :has selector to check for the presence of specific types of input fields (checkbox or radio) and applies a grid layout to better accommodate these elements. Conversely, if text or email inputs are present, it switches to a vertical layout by using a flexbox. This adaptability enhances the form’s usability across different devices and screen sizes.

5. Responsive Design Enhancements

Imagine a scenario where a web page contains multiple articles, each with a mix of images. Some images are portraits, which are best displayed in a narrow column, while others are landscapes, which require a broader space to be effectively showcased. Using the :has selector, we can dynamically adjust the layout of each article based on the type of image it contains.

/* Base styles for all articles */
article {
  display: flex;
  flex-direction: column;
  margin-bottom: 20px;
}

/* Adjusting layout for articles containing landscape images */
article:has(img[orientation="landscape"]) {
  flex-direction: row;
}

/* Adjusting layout for articles containing portrait images */
article:has(img[orientation="portrait"]) {
  flex-direction: column;
}

In this example, each article element typically displays its content in a column format. However, if an article contains an image with the attribute orientation="landscape", the layout switches to a row format, making better use of horizontal space. Conversely, if the image is a portrait, the default column layout is maintained.

Explanation and Insights The :has selector checks for the presence of an image with a specific attribute (orientation) inside the article element. This allows us to apply different CSS styles based on the image’s orientation, which is particularly useful in responsive design where adapting to content types dynamically can significantly enhance user experience.

This approach reduces the need for additional JavaScript or server-side processing to alter the layout based on content, streamlining the page load and rendering processes. It also maintains CSS’s role as the primary tool for visual adjustments, keeping the styling logic within the stylesheet and not scattered across multiple technologies.

6. Styling Hover States Based on Nested Content

Consider a scenario where you want to style a card element differently when hovered, but only if it contains an image or a specific type of button. This can improve visual feedback on interactive elements, making the interface more intuitive.

<div class="card">
  <img src="thumbnail.jpg" alt="Thumbnail">
  <h3>Card Title</h3>
  <p>Description of the card content that might be lengthy.</p>
  <button class="special-action">Learn More</button>
</div>
.card:hover:has(img) {
    box-shadow: 0 8px 16px rgba(0,0,0,0.2);
}

.card:hover:has(.special-action) {
  background-color: #f0f0f0;
  border-left: 5px solid blue;
}

Explanation:

In the CSS snippet above, the :has selector is used to check for specific conditions within the .card element when it is hovered over:

  • .card:hover:has(img): Applies a shadow effect to any .card on hover if it contains an element. This visual cue can help users associate images with clickable or interactive content.
  • .card:hover:has(.special-action): Changes the background color and adds a distinctive left border to the .card on hover if it contains a button with the class .special-action. This style alteration makes the button stand out, encouraging users to click on it. These selectors add a layer of dynamic styling based on the content of the elements, enabling developers to create more responsive and intuitive interfaces without the need for JavaScript.

Conclusion

In conclusion, the CSS :has selector offers a robust solution for implementing responsive and intuitive designs without relying heavily on JavaScript. This article has walked you through six practical examples, demonstrating how this selector can be effectively used to enhance various aspects of web design—from highlighting important information to dynamically adjusting UI elements based on content. Whether you’re looking to streamline your styling process, increase site performance, or simply add a layer of sophistication to your designs, the :has selector is a valuable tool in any frontend developer’s arsenal. As web technologies continue to evolve, embracing such advanced CSS features will undoubtedly keep your projects ahead of the curve.