Dynamic video creation with React and Remotion
Learn how Remotion combines React’s flexibility with video production, allowing developers to create dynamic, data-driven, and scalable videos effortlessly.
Qubika at Databricks Data + AI Summit
Join us June 9-12 to see our leading Databricks capabilities
Financial services
Expertise in core banking, BaaS integrations, payments, and GenAI-enhanced financial solutions.
Healthcare
People-centric healthcare design and solutions, from virtual care, integrations, to smart devices.
Insurance
Modern solutions including self-service, on-demand, and algorithm-driven personalization.
Hi-tech & semiconductors
Semiconductor design, firmware and IoT development, and AI-powered embedded systems.
Qubika is a Databricks Select Partner
Learn more about our journey, our 150+ certified Databricks experts, and how we’re delivering solutions such as autonomous AI agents.
Databricks Capabilities
Learn more about Qubika's strong partnership with Databricks as a Select Partner, delivering solutions across the finance, banking, healthcare, hi-tech, and entertainment industries.
Databricks Impact on Financial Institutions
Databricks empowers financial institutions to harness unified data and AI, such as for real-time fraud detection, dynamic risk modeling, and personalized customer experiences.
July 9, 2025
CSS has evolved into a powerful language. This article dives into transformative features such as :has(), :is(), :where(), CSS Nesting, and Container Queries, exploring how they simplify selectors, enhance component-based responsiveness, and improve web development practices.
CSS has evolved into a powerful language. This article provides a nutshell of some of its transformative features, including concepts like :has(), :is(), :where(), CSS Nesting, and Container Queries, showcasing how they are reshaping modern web development.
Reliable References for Feature Use
Initiatives and tools that clarify feature readiness, browser compatibility, and modern best practices.
CSS Nesting
Native support for writing nested selectors for cleaner, scoped styles.
:has()
A powerful selector that styles elements based on their children or siblings.
:is() & :where()
Tools to simplify complex selectors and manage specificity.
Container Queries
Style components based on their parent’s size, not just the viewport.
Before exploring specific CSS features, it’s useful to highlight a few key resources that support modern web development. Platforms like web.dev, the Baseline initiative, and Can I Use provide essential guidance on feature readiness, browser support, and best practices. They serve as reliable reference points for evaluating which features are safe to adopt in real-world projects.
web.dev is a site created by Google to help developers build high-quality web experiences. It offers articles, tutorials, and tools written by members of the Chrome team and other experts in web development. The goal is to improve the overall quality and user experience of the web by providing developers with the knowledge and resources they need.
Baseline provides a clear reference point for determining whether web platform features are ready to be safely adopted. The initiative aims to standardize the adoption of web features, ensuring developers can safely integrate new technologies. By relying on Baseline, teams can more easily decide when it makes sense to use a feature, helping speed up decisions and reduce uncertainty in the development process.
Features become part of Baseline once they are supported across a defined set of core browsers. The initiative recognizes two stages of adoption: Newly available, for features that work in the latest versions, and Widely available, for those with long-term, broad support. Before reaching either stage, a feature is considered to have Limited availability.
Baseline statuses are visible directly on resources like MDN and Can I Use, making it easy to check whether a feature is ready to use. Full criteria and the core browser set can be explored in the official Baseline documentation.
Can I Use is a widely used resource that provides up-to-date browser support tables for HTML, CSS, JavaScript, and other front-end web technologies. It allows developers to quickly check if a specific feature is supported in various browser versions, helping prevent compatibility issues before they arise.
By searching for a property or API, you get a clear, color-coded overview of its support status, along with usage data, notes, and known issues. It’s a fast way to understand whether a feature is safe to use.Can I Use is community-driven and open source, with contributions from developers around the world.
Now let’s dive into the CSS features this article set out to highlight.
Write nested selectors in a native way, similar to Sass, without relying on preprocessors—improving structure and maintainability.
This feature allows related styles to be aggregated into a single structure within the CSS document, improving readability and maintainability.
/* Before*/
.card { outline: solid 2px #292929; }
.card .subtitle { color: gray; }
/* After */
.card {
outline: solid 2px #292929;
.subtitle { color: gray; }
}
Before: Every selector needed to be explicitly declared, separately from one another. This led to repetition, stylesheet bulk, and a fragmented or hard-to-follow structure.
After: Related selectors can now be grouped together using nesting, resulting in more concise and structured stylesheets.
/* Before */
.nesting { color: pink;}
.nesting > .is { color: red;}
.nesting > .is > .awesome { color: grey; }
/* After */
.nesting {
color: pink;
> .is {
color: red;
> .awesome {
color: grey;
}
}
}
If the .nesting component were removed from the project, the nested approach would allow you to delete the entire block at once, instead of searching through multiple scattered selectors across the stylesheet.
Nesting can help with: Organization | Reducing file size | Refactoring
The nesting selector (&) explicitly states the relationship between parent and child rules when using CSS nesting. It makes the nested child rule selectors relative to the parent element. Without the & nesting selector, the child rule selector selects child elements.
.button {
color: white;
background-color: blue;
/* Targets the same element if it also has a .rimary class */
&.primary {
background-color: royalblue;
}
/* Targets the same element if it is hovered */
&:hover {
background-color: navy;
}
}
The & nesting selector makes the nested rule relative to the parent selector (.button in this case):
Without the &, the nested rules would target child elements, like .button .primary or .button :hover, which is not the intended behavior in this case.
Consider the following nesting CSS block:
.card {
color:green;
& { color: blue }
color: red;
}
/* Resulting CSS */
.card {
color: green; /* hoisted */
color: red; /* hoisted */
}
.card {
color: blue; /* nested block */
}
The color of .card elements will be blue.
When you write CSS with both regular declarations and nested selectors in the same block, the browser hoists regular declarations to the top of the rule.
This means that any nested selectors are treated as separate blocks, and the cascade order (the order in which styles are applied) may not follow the written sequence.
The key advice
To avoid unexpected order or conflicts:
A game-changing relational pseudo-class that allows you to select an element if it contains or is related to specific child, descendant, or sibling elements. This was previously not possible with pure CSS and required JavaScript.
selector:has(selector)
The selector before :has() defines the element to style.
The selector inside :has() defines the related element(s) the rule depends on.
Descendant combinator
div:has(.child)
Matches a div with any descendant having the class .child
Child combinator
div:has(> .child)
Matches a div with a direct child having the class .child
Adjacent combinator
p:has(+ img)
Matches a p immediately followed by an <img>
General Sibling
div:has(~ .sibling)
Matches a div with any following sibling having the class .sibling
.cards-wrapper {
display: flex;
gap: 10px;
.card {
width: 350px;
border-radius: 10px;
outline: solid 2px #292929;
padding: 10px;
/*
Example: General sibling
*/
h3:has(~ .subtitle) {
margin-bottom: 2px;
}
/*
Example: Child combinator
*/
&:has(> span) {
outline-width: 4px;
}
/*
Example: Adjacent combinator
*/
h3:has(+ span) {
color: #5955FA;
}
.subtitle {
color: gray;
display: block;
margin-bottom: 10px;
}
/*
Example: Descendant combinator
*/
p:has(code) {
text-decoration: underline;
}
}
}
The :has() relational selector can be used to check if one of the multiple features is true or if all the features are true.
By using comma-separated values inside the :has() relational selector, you are checking to see if any of the parameters exist. x:has(a, b) will style x if descendant a OR b exists.
By chaining together multiple :has() relational selectors together, you are checking to see if all of the parameters exist. x:has(a):has(b) will style x if descendant a AND b exist.
.cards-wrapper {
display: flex;
gap: 10px;
.card {
width: 350px;
border-radius: 10px;
outline: solid 2px #292929;
padding: 10px;
.subtitle {
color: gray;
display: block;
margin-bottom: 10px;
}
/*
Example comma-separated - OR
*/
p:has(span, code) {
text-decoration: underline;
}
/*
Example chaining - AND
*/
p:has(span):has(code) {
color: red;
}
}
}
Combining :has() with :not() allows for powerful conditional styling based on what an element doesn’t contain.
p:has(:not(span))
Select every <p> element that contains at least one child that is not a <span>
p:not(:has(span))
Select every <p> that does not contain a <span> at all.
.cards-wrapper {
display: flex;
gap: 10px;
.card {
width: 350px;
border-radius: 10px;
outline: solid 2px #292929;
padding: 10px;
/*
Example: :not() combinator
*/
&:not(:has(.subtitle)) {
text-decoration: line-through;
}
/*
Example: :not() combinator
The following would select every <h3> element that contains at least one child that is not a .subtitle.
*/
/*
&:has(:not(.subtitle)) {
text-decoration: line-through;
}
*/
.subtitle {
color: gray;
display: block;
margin-bottom: 10px;
}
}
}
Solution: Add Specificity
Approach: Combine :has() with scoped and direct child selectors.
Benefit: Prevents styles from leaking into irrelevant components and improves rendering efficiency.
Key Takeaways
Be specific when using :has() to balance performance and styling precision. Avoid unintended effects by scoping the target structure, especially in dynamic and nested environments.
They simplify and optimize complex selectors by allowing you to group multiple conditions.
Key differences
:is() Contributes specificity from its contents
:where() Always has zero specificity, no matter what’s inside
Key Use Cases
:is() Use when you need to match multiple selectors and maintain specificity
:where() Use for utility styles where you don’t want to impact specificity (e.g., consistent margins, resets)
How each works
:is() Evaluates a group of selectors and applies styles if any of the selectors inside matches. It is subject to specificity. The specificity of the most specific selector inside :is() applies to the rule.
:where() Works similarly to :is(), but with zero specificity. It never contributes specificity, making it ideal for applying styles without affecting existing rules.
.cards-wrapper {
display: flex;
gap: 10px;
.card {
width: 350px;
border-radius: 10px;
outline: solid 2px #292929;
padding: 10px;
.subtitle {
color: gray;
display: block;
margin-bottom: 10px;
}
}
/*
Fails: invalid selector
.1a - breaks the entire rule
*/
.card h3,
.card p,
.card .1a {
color: red;
}
/*
Works: :is() ignores invalid selector
*/
.card :is(h3, p, .1a) {
color: #5955FA;
}
}
.cards-wrapper {
display: flex;
gap: 10px;
.card {
width: 350px;
border-radius: 10px;
outline: solid 2px #292929;
padding: 10px;
.subtitle {
color: gray;
display: block;
margin-bottom: 10px;
}
}
/*
Examples: :is() overrides :where() due to higher specificity,
even when declared later in the stylesheet.
The :where() pseudo-class has zero specificity.
*/
.card :is(h3, p) {
color: #5955FA;
}
.card :where(h3, p, code) {
color: coral;
}
}
Style elements based on the size of their parent container, not just the viewport—unlocking true component-based responsiveness.
Container queries and media queries are both useful tools for creating responsive designs.
The main difference between the two is that media queries apply styles based on the viewport size or other device characteristics, while container queries apply styles based on the size of an element’s container.
Traditionally, we’ve used media queries that look at the viewport size to make layout decisions. But often we want components to adapt based on their container’s size, not the whole viewport.
Think of a card component that needs to display differently when it’s in a narrow sidebar versus a wide main content area.
/* Define the container as a queryable container */
.card-container {
/* Enables container queries based on width (not height) */
container-type: inline-size;
/* Give this container a name so we can reference it in @container rules */
container-name: card;
border: 1px solid #ccc;
padding: 1rem;
max-width: 600px;
/* Allows user to manually resize for demo purposes */
resize: horizontal;
overflow: auto;
}
/* Default layout for the card (when container is narrow) */
.card {
background: #f2f2f2;
padding: 1rem;
display: flex;
/* Stack content vertically by default */
flex-direction: column;
}
/* Container Query: Apply styles when container is at least 500px wide */
@container card (min-width: 500px) {
.card {
/* Change layout to horizontal */
flex-direction: row;
/* Space out the children */
justify-content: space-between;
/* Align items vertically */
align-items: center;
}
.card h2 {
/* Make the title bigger on wider containers */
font-size: 2rem;
}
.card p {
/* Add space between title and description */
margin-left: 1rem;
margin-bottom: 0;
}
}
The benefits of container queries include:
This feature fundamentally changes how we can approach responsive design, moving from a global viewport-based approach to a more modular, component-based one.
It’s particularly valuable for design systems and reusable component libraries.
Container queries are a great way to design more flexible and responsive layouts without having to use fixed breakpoints, having said that, combination of container queries and media queries technique will be one of the best way forward to achieve a great responsive web design.
@media can handle the big picture stuff, user preferences and global styles
@container will take care of all the micro-adjustments inside the components
Modern CSS is about empowering components to be smarter, more adaptable, and better scoped. Features like :has(), :is(), :where(), CSS Nesting, and Container Queries mark a significant shift toward modular, maintainable, and context-aware design systems.
By combining these tools with reliable references like web.dev, Baseline, and Can I Use, developers can confidently adopt modern CSS features backed by real-world support and best practices.
Whether you’re building reusable components, improving responsiveness, or simplifying selector logic, these modern capabilities allow CSS to scale with your application’s needs. As the language continues to evolve, embracing these tools will lead to cleaner code, smarter styling decisions, and better user experiences.
By Camila Costa
Engineering Expert I and Frontend Developer at Qubika
Receive regular updates about our latest work
Learn how Remotion combines React’s flexibility with video production, allowing developers to create dynamic, data-driven, and scalable videos effortlessly.
Master layer ordering in Mapbox GL JS to enhance map clarity and control with easy, asynchronous management solutions.
Read more about why its important to utilize a scientific approach in development projects.
Receive regular updates about our latest work
Get in touch with our experts to review your idea or product, and discuss options for the best approach
Get in touchArtificial Intelligence Services
Accelerate AI
Healthcare Solutions
Data
Agentic Factory
Financial Services Technology
Platform engineering
Data Foundation