4

I'm trying to use knockout's style binding to add CSS3 variables to some div elements, which are then used in our CSS to compute the final styles.

Example:

var viewModel = function ViewModel() {
  this.randomColor = ko.computed(function() {
    // Random color thanks to @paul_irish
    return "#" + Math.floor(Math.random() * 16777215).toString(16);
  });
}();

ko.applyBindings(viewModel);
h2 {
  /* default fall-back color: */
  --random-colour: #666;
  color: var(--random-colour);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<h2 data-bind="style: {'--random-colour': randomColor}">This should receive a random text color.</h2>

http://jsfiddle.net/tujhxdmc/5/

I would expect it to apply the css variable in a style tag, but instead it just seems to be ignored. The surrounding bindings and bindings using standard CSS properties are all working as expected, so I'm certain that it's a problem with CSS variables.

Knockout's documentation states:

If you want to apply a font-weight or text-decoration style, or any other style whose name isn’t a legal JavaScript identifier (e.g., because it contains a hyphen), you must use the JavaScript name for that style. For example,

  • Don’t write { font-weight: someValue }; do write { fontWeight: someValue }

But that doesn't work for CSS variables (which must be proceeded by a double-hyphen).

How do you use CSS variables in Knockout's style binding?

Community
  • 1
  • 1
Matthew Schlachter
  • 3,250
  • 1
  • 12
  • 26
  • Looking at the source, I don't think this is going to be supported in any pretty way if at all without a pull request: [defaultBindings/style.js](https://github.com/knockout/knockout/blob/9eb61061e45e371362aee8d182392c531b7ac2ef/src/binding/defaultBindings/style.js#L15). – zero298 Jul 16 '18 at 19:43
  • That seems to be the line that camel-cases style properties but it looks like the `--` will get eaten by the RegEx. – zero298 Jul 16 '18 at 19:45
  • ..I don't really like the look of that – Matthew Schlachter Jul 16 '18 at 19:47
  • 1
    I made an issue to track this on the GitHub. You can find it here: [Cannot bind to custom CSS property variables #2400](https://github.com/knockout/knockout/issues/2400). Maybe a better approach will come from that issue. – zero298 Jul 16 '18 at 20:15

1 Answers1

2

It looks like this won't be possible right now without augmentation of Knockout.

Consider how style bindings are actioned right now in the source here: knockout/src/binding/defaultBindings/style.js .

Particularly this line:

 element.style[styleName] = styleValue;

Whenever this runs, styleName will be the CSS variable "--random-colour".

However, you can't set the style through element.style["--random-colour"]. You have to go through style.setProperty().

Consider also this question: Accessing a CSS custom property (aka CSS variable) through JavaScript


If you need this functionality right now, you could load the knockout library script and then override the ko.bindingHandlers['style'].update function to use a version that will use setProperty():

ko.bindingHandlers['style'] = {
    'update': function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor() || {});
        ko.utils.objectForEach(value, function(styleName, styleValue) {
            styleValue = ko.utils.unwrapObservable(styleValue);

            if (styleValue === null || styleValue === undefined || styleValue === false) {
                // Empty string removes the value, whereas null/undefined have no effect
                styleValue = "";
            }

            if(styleName.substring(0, 2) === "--"){
                element.style.setProperty(styleName, styleValue);
            } else {
                element.style[styleName] = styleValue;
            }
        });
    }
};

I have added an issue on the KnockOut GitHub in case other, better responses come from there: Cannot bind to custom CSS property variables #2400.

zero298
  • 25,467
  • 10
  • 75
  • 100