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?

4
  • 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. Commented Jul 16, 2018 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. Commented Jul 16, 2018 at 19:45
  • ..I don't really like the look of that Commented Jul 16, 2018 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. Maybe a better approach will come from that issue. Commented Jul 16, 2018 at 20:15

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

4 Comments

You do not need to fork Knockout to add binding handlers.
@MichaelBest Could you add how as an answer? I agree that forking is overkill if you can override the default behavior.
After including the Knockout library, include your code above. You will then have replaced the style binding handler with your own.
@MichaelBest You're right, that is a much better interim solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.