CSS Web Dev

Conditional Rules in CSS?

Conditional Rules in CSS?

CSS conditional rules? It's well known that web technologies are evolving over time, we are almost not surprised about the new features coming to our technologies no matter how unbelievable they seem to be. We are in the magic era.

Often times we have been worried about how to create a fallback solution for some specific sets of CSS rules.

As a developer, you might have thought that making an if...else cases in CSS will be a good idea, isn't it? But CSS is a stylesheet language, and adding such a procedure would be nothing better than weird.

Property Value Fallback

Firstly, let's talk about writing a fallback if a specific CSS property value is not supported.

Let's look at these two scenarios.

.color-red {
  background-color: blue;
  background-color: red;
}

As you know, the final property for background-color is red because in CSS specificity, the browser uses the last read supported value. Let's look at the second scenario:

When you write an unsupported property value in CSS, the browser ignores and uses the last known supported one.

In this case, the browser first sees background-color: red; which it understands, and then sees background-color: asdf; which does make a color sense even to humans, and ignores it. In this sense, a fallback value can be defined in CSS thus:

.color-red {
  background: url('transparent-red.png') no-repeat;
  background: rgba(255, 0, 0, .5);
}

The more the browser keeps understanding the next values of a property, it interprets it, else, it sticks to the last value understood.

In the CSS rule above, if the browser is new enough to understand the rgba() it interprets this, instead, sticks to the url() function to fetch the background image, which is new enough for any old browser in town, in 2021.

Just recently (In CSS Level 4), the rgb() is slightly modified to now have the same capability as rgba() function and also allows the whitespace syntax. We can check for this compatibility like this:

.color-red {
  background: rgba(255, 0, 0, .5);
  background: rgb(255, 0, 0, .5);
}

Checking for the whitespace syntax:

.color-red {
  background: rgb(255, 0, 0, .4);
  background: rgb(255 0 0 / 50%);
}

The code above will pick background: rgb(255 0 0 / 50%); if the browser supports the whitespace syntax.

All the above codes are based on creating a fallback value for one specific CSS property, it doesn't provide a way to define sets of properties and values to be used when a particular property is not supported by a browser.

The @supports Property

The @supports is a feature query that solves the problem. This query receives some declarations to determine whether the browser supports or not, one or more specific CSS features. Added in CSS Conditional Rules Module LevelĀ 3.

Syntax

@supports (declaration) {
/* CSS rules here */
}

Let's put this to code

@supports (background: rgb(255 0 0 / 50%)) {
  .grid {
    background: rgb(255 0 0 / 50%);
  }
}

The selector() function

The @supports query also comes with a function syntax. We only have the selector() as the time of this writing, which was added in CSS Conditional Rules Module Level 4.

The selector() function allows you to check for browser support for specific CSS selectors. This should not be directly used on selectors, you can just specify the two operands and A and B.

For example, to check if a browser supports the adjacent sibling combinator, we can use the following query:

@supports selector(A + B) {
  /* CSS rules to execute if the browser supports adjacent child combinator */ 
  ul + ol {
    border-bottom: dashed 1px red;
  }
}

Check for more than one condition?

Let's try to check if the browser supports checking a specific declaration and another specific declaration.

We can intrinsically achieve this in this way:

@supports (display: table) {
  @supports(display: table-header) {
    // Haven't tested this out though.
    .table-display {
      display: table;
    }
    .table-display h3 {
      display: table-header;
    }
  }
}

This looks good and also readable, but what happens to it if we have more than two nested feature queries?

You can combine declarations with conjunctions(and) , disjunctions(or) , negations (not) and just as in a normal programming language, precedence can be defined with parenthesis ().

Let's rewrite the code above

@supports (display: tabel) and (display: table-header) {
    .table-display {
      display: table;
    }
    .table-display h3 {
      display: table-header;
    }
  }
}

More examples on conjunctions and disjunctions, preceding the order with parenthesis.

@supports not (display: grid) and ((display: flex)) {
  // CSS applied if display:grid is not supported but display:flex is.
  .flexbox {
    display: flex;
  }
  .flexbox div {
    flex: 1;
  }
}

If...else Conditions?

The @supports feature does not implement if..else conditions but we can achieve this with the not negation.

@supports(display: grid) {
  .parent {
    display: grid;
    gap: 20px;
    grid-column-templates: repeat(3, 1fr);
    height: 200px;
}
} @supports not (display: grid) {
  .parent {
    display: block;
}
.parent .child {
  margin-right: 20px;
  width: 33.33%;
  height: 200px;
  float: left;
}
.parent .child:last-child {
  margin-right: 0;
}
}

The first rule of codes executes if our browser supports display: grid

It sets repeated grid columns of three equal widths and height of 200px;

The same thing can be achieved with some of couple of CSS properties if the browser does not support the declaration display: grid.

JavaScript API

Conditional rules in CSS also comes with a JavaScript API that lets you programmatically check for the browser's feature support using the CSS.supports() method. It takes two parameters propertyName and value or just one parameter supportCondition.

Syntax

CSS.supports(propertyName, value);
CSS.supports(supportCondition);

This method returns true if the browser supports the declaration, else false. Let's look at an example:

if(CSS.supports('display', 'grid')) {
  // JavaScript to be executed if browser supports the display:grid declaration
}

Check if the browser does not support the display:grid declaration. As discussed, with can use the not negation in our CSS to check this. We can also negate the condition in our JavaScript to check the same:

if(!CSS.supports('display', 'grid')) {
  // JavaScript to be executed if browser supports the display:grid declaration
}

Real-Life Examples

Let's put @supports into use by creating some real-life examples with it.

This example will:

  • Checks if the browser supports the -webkit-line-clamp: 3, display:-webkit-box and -webkit-box-orient: vertical declarations, if true:
    • Set -webkit-line-clamp to 3.
    • Set display to -webkit-box.
    • Set -webkit-box-orient to vertical.
    • Display a message in the ::after that indicates that the browser supports -webkit-line-clamp: 3.
  • If not true:
    • Check if the browser supports the text-overflow: ellipsis property, if true:
      • Set overflow to hidden.
      • Set text-overflow to ellipsis
      • white-space to nowrap
      • Display a message in the ::after that indicates that the browser does not support -webkit-line-clamp: 3 but supports text-overflow: ellipsis.
    • if not true:
      • Set display to block.
      • Set overflow to hidden.
      • Set height to 100px
      • Display a message in the ::after that indicates that the browser does not support -webkit-line-clamp: 3 and text-overflow: ellipsis.

We have made a live demo for this:

Conclusion

The CSS conditional rules are a neat way to make better design decisions in just CSS. I see this as something cool enough to make quick decisions that are meant to be made only with JavaScript before the @supports feature. Another brilliant use case is to determine the type of browser that is being used and display a message like "You are on Firefox" or "You are using Google Chrome or a Chromium-based browser". Cool right? What is the first hack that comes into your mind this mind-blowing feature? Please share your thoughts in the comment session below.

Leave a comment

Your email address will not be published.*

Comments (0)