Re: [csswg-drafts] [css-values] if() function (#3455)

Very interesting idea! It got me thinking if there was a way we might be able to express a condition to test, and two results to pick between returning using CSS variables, and I think I have a basic demo of something that can work, but it's limited to only what JavaScript knows about (so right now I'm not sure how it would compare CSS units).

demo: https://codepen.io/tomhodgins/pen/jXVMPW

We can invent our own CSS variables like `--if-1` or `if-2`, or `--if-computed`, or whatever we want to named them and put them either in our CSS like this:

```css
:root {
  --if-1: '[{"equal": [5, 5]}, "lime", "hotpink"]';
  --if-2: '[{"equal": [5, 4]}, "lime", "hotpink"]';
}
```

Or set them on a tag in HTML like this (I wish the quotes didn't have to be encoded 😇):

```html
<html style='--if-computed: "{%22computed%22: [%22background-color%22, %22rgb(0, 255, 0)%22]}, %2220pt%22, %2210pt%22"'>
```

Then we can write a function that supports the various conditions we want to test — whether it's mathematical comparisons between numbers, or checking the computed styles of properties on elements — anything that JavaScript can test for us can be written as a condition. In this demo I'm supporting `<`, `<=`, `===`, `>=`, `>`, and checking if the computed value of a CSS property matches a value. We can encode that in a format that's easy for us to read from CSS using `JSON.parse()`, and then we can use what we find to pick the right comparison function to use, to compare a left and right hand side of a comparison, and then to return a different result whether the test is true or false:

```js
function comparison(value, event, ruleOrTag) {
  console.log(decodeURI(value))
  const [conditionObject, trueResult, falseResult] = JSON.parse(`[${decodeURI(value)}]`)
  const [name, [left, right]] = Object.entries(conditionObject)[0]
  const features = {
    less: (left, right) => Number(left) < Number(right),
    lessEqual: (left, right) => Number(left) <= Number(right),
    equal: (left, right) => Number(left) === Number(right),
    greaterEqual: (left, right) => Number(left) >= Number(right),
    greater: (left, right) => Number(left) > Number(right),
    computed: (left, right) => window.getComputedStyle(ruleOrTag)[left] === right
  }
  return features[name](left, right) ? trueResult : falseResult
}
```

And then all we need to do to connect the dots between CSS and JS is this to loop through all of the rules in CSSOM and the tags in DOM, find all CSS variables that contain the information we want to pick between, and process what we find. For this I'm using a [computed-variables](https://github.com/tomhodgins/computed-variables) plugin with a configuration like this:

```js
computedVariables('--if-', comparison, window, ['load'])
```

This will find every CSS variable starting with `--if-` and run what it finds through our `comparison` function, being processed when the `load` event fires on the `window`. Now anywhere we use `var(--if-1)` or `var(--if-2)` or `var(--if-computed)` in CSS we'l have the correct result for whatever condition we tested with JavaScript immediately available to use anywhere in CSS.

How far do you think JavaScript + CSS variables could go toward implementing this sort of `if()` functionality in CSS as we have it today?

-- 
GitHub Notification of comment by tomhodgins
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/3455#issuecomment-448449760 using your GitHub account

Received on Wednesday, 19 December 2018 02:45:20 UTC