10 minutes reading time (1923 words)

CSS is evolving, evolve your code with this simple guide

March-CSS

I love the way some technologies are aware of what is going on around them and then pivot to make their own technology all the better by seeing if they can do the same as the bright young techs around them, bringing a new lease of life.

Javascript was surrounded by libraries and frameworks that extended its potential, and then vanilla javascript subsumed a lot of these ideas and lept forward. When once jQuery was a must to speed development, now sites such as https://youmightnotneedjquery.com/

The world of CSS is similar. Technologies such as LESS, Sass, SCSS and Stylus grow up to extend the abilities of CSS: but CSS is not a static resource and has adopted several of the improvements they offer into its core.

Lets look through some of the recent CSS changes and see if we can extend our own capabilities with these new selectors.

:has() selector - 

The CSS :has() selector represents a significant leap in styling capabilities. It allows developers to style elements based on the presence of descendants that match a given condition. 

This feature enhances the selectivity and dynamism of CSS without additional JavaScript!

The :has() pseudo-class selects an element if any of the relative selectors passed as an argument match at least one element when anchored against this element.

It provides a way to select a parent element or a previous sibling element with respect to a reference element, by taking a relative selector list as an argument.

Using :has() enables complex styling scenarios directly within stylesheets.

It's particularly useful for designing responsive interfaces and enhancing user interaction, based on the content structure. 

As CSS continues to evolve, the introduction of :has() paves the way for other advanced features, fostering more intuitive and flexible web design practices.

Here's a concise code example utilising the CSS :has() selector:

/* Styles the <li> only if it contains a link with the class .active */

li:has(a.active) {

  background-color: lightblue;

}

This snippet demonstrates how :has() can be used to apply styles conditionally based on the presence of certain elements within another, enhancing the dynamism and specificity of CSS selectors.

Here is another simple example

/* Selects an <h1> heading with a <p> element that immediately follows the <h1> and applies the style to <h1> */

h1:has(+ p) {

  margin-bottom: 0;

}

The :has() pseudo-class takes on the specificity of the most specific selector in its arguments, similar to :is() and :not().

Limitations:

  • If :has() is not supported in a browser, the entire selector block will fail unless it’s within a forgiving selector list like :is() or :where().
  • :has() cannot be nested within another :has() due to potential cyclic querying.
  • Pseudo-elements are not valid selectors within :has(), and pseudo-elements cannot be anchors for :has().

Consider the following HTML snippet:

<section>

  <article>

    <h1>Morning Times</h1>

    <p>Lorem ipsum dolor sit amet...</p>

  </article>

  <article>

    <h1>Morning Times</h1>

    <h2>Delivering you news every morning</h2>

    <p>Lorem ipsum dolor sit amet...</p>

  </article>

</section>

 

The following CSS rule selects the <h1> element immediately followed by an <h2> element (indicated by the next-sibling combinator +):

h1:has(+ h2) {

  margin: 0 0 0.25rem 0;

}

 

Without :has(), you cannot use CSS selectors to select a preceding sibling of a different type or a parent element.

You can extend it to multiple elements:

h1:has(+ h2, + p) {

  /* Styles for h1 followed by h2 or p */

}

 

For more examples and compatibility details, check https://caniuse.com/css-has.

CSS Nesting - keeping it tidy

CSS Nesting represents a major advancement, allowing for more structured and efficient style sheets by enabling selectors to be nested within one another.

This feature simplifies the management of complex stylesheets and enhances readability. 

CSS Nesting allows you to write CSS rules inside other CSS rules. This helps to scope the styling to specific parts of your HTML structure, making your CSS more maintainable and readable. Here's an example:

article {

  color: black;

  background-color: white;

  

  h2 {

    font-size: 1.5em;

  }

  p {

    font-size: 1em;

    &.lead {

      font-weight: bold;

    }

  }

  @media (max-width: 600px) {

    background-color: #eee;

    

    h2, p {

      text-align: center;

    }

  }

}

In this example, the h2 and p styles are nested within article, applying only when they are descendants of article.

The & symbol is used to refer back to the primary selector within nested blocks, allowing for more complex selections like the .lead class on p. 

You have probably come across  @media rules, they are a perfect example of nested CSS, but did you know you can make other nested blocks as well?

History behind CSS Nesting

CSS nesting's development is a collaborative effort led by the CSS Working Group, part of the W3C (World Wide Web Consortium), which oversees web standards. The idea borrows from CSS preprocessors like SASS and LESS, which have supported nesting for years.

The CSS Nesting Module Level 1 introduces native nesting in CSS, aiming to bring this popular feature directly into browsers for more straightforward, readable stylesheets.

The & symbol is used within nested blocks to reference the parent selector, crucial for applying styles based on parent-child relationships or modifying the parent based on child conditions.

It's recommended to use & for clarity and specificity, especially when dealing with pseudo-classes, modifiers, or when the nested style depends on the parent's state or structure.

The Advantages

Using CSS nesting offers several advantages, including improved readability and organization by allowing related styles to be grouped together. It reduces the need to repeat selectors, making stylesheets more maintainable and concise. This structure mirrors the HTML structure, making it easier to understand the relationship between styles and document elements. Additionally, nesting can lead to more efficient styling workflows, especially when working with complex layouts or component-based designs.

For the latest support and usage details, check https://caniuse.com/css-nesting

Newer CSS ideas related to nesting include more intuitive conditionals within stylesheets and enhanced scope management for styles, potentially leading to a more modular and component-based approach in CSS design.

CSS text-wrap: balance - Making text easier to read

The CSS text-wrap: balance property is a response to the need for more aesthetically pleasing text layouts on the web.

Historically, achieving balanced text blocks required manual adjustments or complex scripting. 

This property aims to automate the balancing of line lengths within a text block, distributing text more evenly across lines. It represents an effort to bring traditional typography principles; where balanced text is key for readability and visual appeal, into web design.

This feature is part of ongoing developments in CSS to enhance text layout capabilities.

For an example:

p {

  text-wrap: balance;

}

 

The CSS text-wrap: balance property should be used judiciously.

Avoid it in cases where exact control over text layout is necessary, as it aims for a balance that might not suit every design need.

It is less suitable for lengthy text blocks where traditional wrapping might suffice without impacting readability.

Also, consider performance implications on complex layouts or when applied indiscriminately to large amounts of text, as balancing could affect rendering speed. 

For the latest support and usage details, check https://caniuse.com/css-text-wrap-balance

Container Queries

Container Queries represent a significant advancement in CSS, enabling components to style themselves based on their own size rather than the viewport's size. This feature is particularly useful for creating responsive designs that adapt more fluidly within different containers.

For example, you could write:

 

.card {

  container-type: inline-size;

}

.card:container(width >= 500px) {

  background: lightblue;

}

.card:container(width < 500px) {

  background: lavender;

}

 

This CSS snippet makes .card elements have a different background colour depending on their width, not the viewport's width.

Basic Usage

First, define a container by specifying a container-type. This enables the element to be a container query container.

 

.container {

 container-type: inline-size;

}

 

Then, use @container to apply styles based on the container's size:

@container (min-width: 500px) {

 .box {

 background: lightblue;

 padding: 2rem;

 }

}

@container (max-width: 499px) {

 .box {

 background: lavender;

 padding: 1rem;

 }

}

Advanced Example: Card Component

Imagine a card component that changes layout based on its size:

.card {

 container-type: inline-size;

}

.card:container(width >= 600px) {

 display: flex;

 gap: 20px;

}

.card img {

 max-width: 100%;

 height: auto;

}

@container (min-width: 600px) {

 .card-content {

 flex: 1;

 }

}

This setup allows the .card component to switch from a vertical to a horizontal layout when its width is at least 600px, providing a more flexible and responsive design.

Responsive Grid with Container Queries

Container Queries can also be used to create a responsive grid that adjusts not only based on the viewport but also based on the container's width:

 

.grid {

 container-type: inline-size;

 display: grid;

}

@container (min-width: 500px) {

 .grid {

 grid-template-columns: repeat(2, 1fr);

 gap: 20px;

 }

}

@container (min-width: 800px) {

 .grid {

 grid-template-columns: repeat(3, 1fr);

 }

}

 

This example demonstrates how a grid layout can dynamically adjust its columns based on the container's width, enhancing the adaptability of grid-based designs.

Container Queries and Aspect Ratio

Container Queries can be combined with aspect-ratio properties to create elements that maintain a specific aspect ratio at different container sizes:

 

.aspect-ratio-box {

 container-type: inline-size;

 aspect-ratio: 16 / 9;

 background: lightcoral;

}

@container (min-width: 400px) {

 .aspect-ratio-box {

 aspect-ratio: 4 / 3;

 }

}

 

This code snippet adjusts the aspect ratio of .aspect-ratio-box based on the container's width, showcasing the flexibility of Container Queries in managing responsive aspect ratios.

To check the current browser support for Container Queries https://caniuse.com/css-container-queries.

Looking ahead, developments related to Container Queries might include more nuanced control over container contexts or integration with other layout models like Grid or Flexbox, enhancing the toolkit for responsive design.

@Layer - Managing Your Styles

The CSS @layer rule is a recent development in the world of web design, aimed at improving the way stylesheets are managed, organised, and applied.

This new feature introduces a method to explicitly define layers of styles, allowing for more straightforward and conflict-free cascading of CSS rules.

Understanding the @layer Rule

The @layer rule enables developers to group CSS rules into distinct layers. These layers follow a specific order, which is used by the browser to determine which styles take precedence when conflicts arise. This approach simplifies the management of complex stylesheets, particularly in large projects or when integrating third-party styles.

Usage of @layer Rule

You can declare a layer and then add styles to it as follows:

 

@layer base {

 body {

 font-family: sans-serif;

 line-height: 1.6;

 }

}

@layer themes {

 .dark-mode {

 background-color: #333;

 color: #fff;

 }

}

@layer components {

 .button {

 padding: 10px 15px;

 border-radius: 5px;

 }

}

 

In this example, the styles are organised into three layers: base, themes, and components. The browser applies these layers in the order they are declared, unless specified otherwise.

Overriding Layers

You can use the @import rule to import external stylesheets into a specific layer:

@layer base;

@import url("base-styles.css") layer(base);

@import url("theme.css") layer(themes);

 

This code imports external styles into the base and themes layers, ensuring that the cascade follows the intended order.

Layer Ordering

Explicitly control the order of layers using the @layer rule with multiple layers:

@layer reset, base, themes, components;

 

This declaration sets the cascade order for the layers, regardless of where they are defined in the CSS.

Browser Support

To check the current browser support for Container Queries https://caniuse.com/css-cascade-layers.

Future Directions

The introduction of the @layer rule opens up new possibilities for managing stylesheet complexity and enhancing performance. Future CSS proposals may build on this concept by introducing more granular control over layer interactions, or by integrating layering more deeply with CSS frameworks and methodologies.

CSS is an evolving language, what was impossible some years ago and needed third party attempts to overcome its deficiencies are now possible and easy to achieve.It will pay us all dividends to revisit our own code and styling and see if we can modernise our own sites.

Some articles published on the Joomla Community Magazine represent the personal opinion or experience of the Author on the specific topic and might not be aligned to the official position of the Joomla Project

0
You can't fool me when it comes to SPF, DKIM, and ...
A first step into volunteering: Pizza , Bugs and ...
 

Comments 4

Already Registered? Login Here
Semaphore on Tuesday, 26 March 2024 08:39
Container pseudo class doesn't seem to exist

Hi,
Are you really sure about the .card:container. It would be a cool feature but I did'nt see it anywhere in docs and it doesn't work with FF.
Thanks

1
Hi, Are you really sure about the .card:container. It would be a cool feature but I did'nt see it anywhere in docs and it doesn't work with FF. Thanks
Philip Walton on Wednesday, 27 March 2024 14:55
Checking with firefox

That is an interesting point you raise.
I have looked from the perspective of Firefox and found this article
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries

I've not had time to test it, but I will see if I need to revise the article. Thanks for your comments; it all helps me improve and get things right.

0
That is an interesting point you raise. I have looked from the perspective of Firefox and found this article https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries I've not had time to test it, but I will see if I need to revise the article. Thanks for your comments; it all helps me improve and get things right.
Semaphore on Wednesday, 17 April 2024 10:40
Still not corrected

It's not an interesting point : the part about container is false. You have to use a container for your .card and the syntax .card:container doesn't exist. Have you tested the code before posting ?

0
It's not an interesting point : the part about container is false. You have to use a container for your .card and the syntax .card:container doesn't exist. Have you tested the code before posting ?
Semaphore on Thursday, 28 March 2024 16:48
Complete review of modern CSS

Very complete review of modern CSS :
https://frontendmasters.com/blog/what-you-need-to-know-about-modern-css-spring-2024-edition/

0
Very complete review of modern CSS : https://frontendmasters.com/blog/what-you-need-to-know-about-modern-css-spring-2024-edition/

By accepting you will be accessing a service provided by a third-party external to https://magazine.joomla.org/