A partial archive of discourse.wicg.io as of Saturday February 24, 2024.

Proposal !limit() keyword function to act as a “weak !important” for only permitting certain CSS values

paceaux
2020-06-11

!important serves a legitimate purpose as an interrupt to the defined cascade. It’s useful for resolving “disputes” in the “contracts” between author, user, and user agent cascades.

Unfortunately, this isn’t how it’s used. It’s often used to:

  1. Reactively breaking the cascade (i.e. I don’t know why my style isn’t working, so I’ll use !important )
  2. pro-actively preventing an override (i.e. utility classes)

In neither case is the author resolving issues in the cascade; instead the author is trying to break it.

I would like to see a keyword that fully addresses the fallout of both of these issues: !limit(). This would allow an author set a value of a property, and pro-actively prevent certain overrides, but not all.

This would be the CSS:

.button {
  display: inline-flex !limit(none); // "none" is a property that is allowed to override inline-flex
}

.ui--hidden {
  display: none;  // this would work
}

.embiggen{
  display: inline-block; // this won't work
  padding: 2em;
  font-size: 1.5em;
}

We then get the following cases, as a result:

Case 1: Standard behavior

The button is now display:none.

<button class="button ui--hidden">Click me</button>

Case 2: Preventing a reactive cascade override

Assuming the undesirable behavior is the element going from display:none to display: inline-block:

<button class="button embiggen ui--hidden">You Can't See me</button>

Previously, this would be fixed reactively

// increasing specificity
.button.ui--hidden {
    display: none;
}

// making sure nothing can ever override it
  .button.ui--hidden {
     display: none !important; 
  }

Please note my use of the term “fix” here. In an ideal world, we might solve this issue by going to .ui--hidden and proactively setting !important. In the real world, we often find cases where there is much risk in modifying earlier, already-implemented styles.

Case 3: Preventing proactive overide

Assuming the prevented behavior is the element going from display:none to display: inline-block:

<button class="button embiggen ui--hidden">You Can't See me</button>

Previously, the original code would have to be written as

.ui--hidden {
  display: none !important; 
}

Which is fine so long as we never have a class like

.ui--unHidden {
display: block !important;
}

And since “never” is a four-letter-word with an off-by-1 error:

.button.ui--unHidden {
display: inline-flex !important;
}

So !limit() acts as good pro-active control with more mild distruption

Syntax, etc

!limit() would behave like !important:

  • It would sit inline with the property, before the semicolon
  • it would follow the same precedence as !important
  • it would also be overridable by !important
  • it would accept functions as arguments effectively allowing ranges of overrideability

e.g.:

.button {
   height: 200px !limit(min(10vh, 20px)); // height could be overrided to 20px or 10vh
   width: 200px !limit(clamp(100px, 200px, 400px)); // width can be overrided between 100px and 400px
}

   .modal {
    z-index: 10 !limit(clamp(8, 10, 12)); // z-index can be overrided between 8 and 12
  }