CSS :has() & Responsive Design

The CSS :has() pseudo-class was shipped for Safari in March 2022 and for Chromium browsers the same August. It's described on the Webkit blog as a way to "apply CSS to an element based on what’s happening inside that element" - so if I was to try and assign it some kind of pseudocode equivalent, an if contains.

The demands of responsive design by nature require flexibility, so the conditional qualities that :has() offers is a great addition to the CSS toolset and widens our options in aiming to achieve this kind of flexibility.

Towards the end of 2022 I was working on applying responsive design principles to the primary apps of a client suite of web apps.

In the interfaces, we have quite a few places where we have a heading aligned with some action buttons (shown here as the 'My latest devices' heading):

 

CURRENT DESKTOP HEADER LAYOUT

The heading and buttons collectively make up our React component Header, which accepts both as props.

On mobile devices, this can end up looking pretty congested - text bunched up together, and tall buttons where the icon looks a little out of place.

 

 

 

 

PREVIOUS MOBILE HEADER LAYOUT - CROWDED

Here’s what I tried at first in an effort to solve the problem:

Different button

I thought at first that we could make the buttons into a single ‘actions menu’ sort of button, before realizing that on some pages, there was a similar button just above. Having two lots of "actions" could be confusing, and even though on mobile, one would have to scroll down to see the second button and then the first one would be out of view; it wouldn't completely dispel the risk of things getting mixed up, and probably isn't best practice.

 

TWO ‘ACTIONS’ BUTTONS WASN’T GOING TO BE AS USABLE
 

Keeping these buttons, but just applying flex-direction: column so they would sit nicely underneath the heading

I then considered simply changing the main container for Header to use flex-direction: column for smaller screens, so the elements could all have some breathing room, like this:

 

COLUMN LAYOUT GAVE MULTIPLE BUTTONS SOME SPACE

That also changed the headers that just had one button, like the one adjacent to the Actions button shown above. Perhaps this is not so bad, but it was not desired. An 'actions' menu aligned next to the heading seemed most suitable, even on a small screen.

 

NOT AS DESIRED JUST FOR A SINGLE BUTTON

 

DESIRED

I also tried to implement a JavaScript solution where I added a class based on the conditions I was looking for, but the way that the header component and its props had been implemented meant it was difficult to avoid unnecessary complexity.

CSS :has() saves the day

After deciding CSS was probably the only way, I thought again about what I needed: a style that exists only where there are more than two buttons in the header. A style when a header only has two buttons.

There had been a lot of hype around CSS's :has() in my weekly dev newsletters, but even so, I wasn't sure in detail what it did - I wasn't sure it could solve this problem. After some Googling and going back to those articles, I learned that it was a "way to apply CSS to an element based on what’s happening inside that element."

At first-glance though, :has() didn't seem very complex, or powerful. I had questions I wanted :has() to answer: "Does my div have more than one button?", namely. Even though it's called :has() rather than :have, I was determined that it could answer this question for me, despite not seeing the examples that I needed immediately.

An explanatory video

Understanding CSS:has(), the top result when searching for "css has" on YouTube, really breaks down just what you can do with this seemingly humble pseudo-classs.

Towards the close of the video it presented some pretty unreadable code, but the use of the already familiar nth-child caught my eye.

The video presented a way to colour the background of alternative rows in a table:

tbody:has()(> tr:nth-child(7)) > tr:nth-child(odd) { background: silver; }

Admittedly, it took me a moment to understand this code. What is happening here?

The tbody:has()(> tr:nth-child(7)) looks for the element which has a direct descendant (> being the child combinator) which fits the description tr:nth-child(7). In other words, it's looking for a table which has more than 6 rows. There's another child combinator after that to select any row which is an odd-number child, of that same table.

So essentially, highlight in silver any odd-numbered row that's a child of any table, as long as that table has more than 6 rows. This shows how powerful :has() really is, and how it can be combined with other features of the language to achieve this power.

How I applied that to my responsive design

As explained above, the criteria I wanted to apply when it came to ordering my header buttons underneath the heading text was "the header has (within it) more than one button". I could create that criteria with this code:

.header:has()(button:nth-child(2)) { flex-direction: column; text-align: center; h2 { padding-bottom: $spacing-sm; } }

And create the design I desired once again.

 

FINAL MOBILE HEADER LAYOUT

Concluding thoughts

On the WebKit blog, Jen Simmons writes, “It’s been a long-standing dream of front-end developers to have a way to apply CSS to an element based on what’s happening inside that element.” Using has() in the scenario above, avoiding either a more convoluted solution or a restricted design has allowed me to explore why this is such a helpful development. I imagine it will provide simpler solutions for responsive design problems and a variety of other styling obstacles for time to come.

AdobeStock, zwei Männer im Büro im Austausch
Success Story

Lehmann&Voss: Successful transition to the cloud

With the introduction of M365, Lehmann&Voss has embarked on its digital journey to the cloud. A change and adoption strategy was central to the successful implementation.

Foto des Gebäudes der Schwäbisch Hall vor blauem Himmel
Success Story

Schwäbisch Hall: A modern workplace in the cloud with M365

With the introduction of M365, Schwäbisch Hall can benefit from the wide range of possibilities on offer and has thus laid the foundations for a modern digital working environment.

Blog 5/25/21

From the idea to the product: The genesis of Skwill

We strongly believe in the benefits of continuous learning at work; this has led us to developing products that we also enjoy using ourselves. Meet Skwill.

Blog 11/12/20

Announcing Domain-Driven Design Exercises

Interested in Domain Driven Design? Then this DDD exercise is perfect for you!

Blog 7/14/21

Building and Publishing Design Systems | Part 2

Learn how to build and publish design systems effectively. Discover best practices for creating reusable components and enhancing UI consistency.

Blog 7/13/21

Composite UI with Design System and Micro Frontends

Discover how to create scalable composite UIs using design systems and micro-frontends. Enhance consistency and agility in your development process.

Blog 11/15/22

5 lessons from running a (remote) design systems book club

Last year I gifted a design systems book I had been reading to a friend and she suggested starting a mini book club so that she’d have some accountability to finish reading the book.

Blog 7/15/21

Building a micro frontend consuming a design system | Part 3

In this blopgpost, you will learn how to create a react application that consumes a design system.

News 11/13/24

25 years of catworkx

25 years of catworkx – a quarter of a century of success and innovation! We celebrated this special anniversary in style on a Danube cruise: from Passau via Vienna to Budapest and back, we took time to look back together on 25 years of developments and successes. A big thank you to our fantastic team and everyone who has joined us on this journey – we look forward to the next 25 years with you!

News 6/22/23

brainbits is now part of TIMETOACT GROUP

With the akquisition of the cologne based IT expert brainbits we are enlarging our Atlassian and Webdevelopment Know How

Kompetenz 7/18/23

Advisory

Support your business goals in the best possible way ►Digital strategy & IT strategy ✅ We will be happy to advise you.

Kompetenz

Digitalization and optimization in the manufacturing industr

The TIMETOACT GROUP is a leading provider of solutions for the manufacturing industry.

Service

Digital Architecture

In order to survive in a dynamic and highly competitive market, you need to be able to adapt your business processes, products and services efficiently to the needs and expectations of your customers

Kompetenz

Governance & Operational Excellence

Digitalization inevitably leads to business processes changing and roles and responsibilities being redistributed. At the same time, new legal requirements, regulations and standards need to be met.

Service

Process Transformation, Integration & Automation

Using Process Transformation, Integration & Automation to react quickly to market changes and sustainably improve competitiveness.

Kompetenz

Business Innovation & Digital Transformation

Utilise digital technologies to improve processes, make data-driven decisions and develop new business models. Without losing sight of governance, risk and compliance.

Navigationsbild zu Data Science
Service

AI & Data Science

We offer comprehensive solutions in the fields of data science, machine learning and AI that are tailored to your specific challenges and goals.

Referenz

McKesson: Spend Management cuts software costs by 15%

Thanks to TIMETOACT's consulting project, the healthcare group is saving considerable expenditure on its software solution.

Kompetenz

Sourcing Strategy, Spend Management & Compliance

The right service providers + Costs under control + Ensure vendor compliance ► Together we develop the right strategy

Kompetenz

Technology Adoption & Integration

Fully exploit the potential of your IT ► Together we will develop a targeted strategy and provide you with holistic support

Bleiben Sie mit dem TIMETOACT GROUP Newsletter auf dem Laufenden!