Dealing with ng-style and vendor prefixes

Slidebean is an app that lets you create beautiful presentations in minutes. It transforms your content into slides automatically, all thanks to the magic of AngularJS.

Most of the slide styles Slidebean uses are prebuilt in regular CSS files. But, because of the dynamic nature of app, it applies colors and other CSS properties to slides using ng-style and javascript as well. It works great, but I ran into a small issue regarding vendor prefixes that I wanted to share.

For one of our templates, we wanted to have a radial gradient as the background of the slides. In regular CSS, you would do something like this to support different browsers:

.slide {
  background: -webkit-radial-gradient(#FFF, #DDD);
  background:    -moz-radial-gradient(#FFF, #DDD);
  background:         radial-gradient(#FFF, #DDD);
}

Thing is, Slidebean doesn’t know the colors until runtime. Instead of using a CSS file, I used Angular‘s ng-style. The slide HTML looks something like this:

<section class="slide" ng-style="getSlideStyles()">...</section>

with a function getSlideStyles that returns the CSS styles:

scope.getSlideStyles = function() {
  var colorA = "#FFF";
  var colorB = "#DDD";
  var styles = {};
  styles['background'] = '-webkit-radial-gradient(' + colorA + ',' + colorB + ')';
  styles['background'] = 'moz-radial-gradient(' + colorA + ',' + colorB + ')';
  styles['background'] = 'radial-gradient(' + colorA + ',' + colorB + ')';
  return styles;
}

All set right? Wrong. In the end, styles ends up with only one property, ‘background’, with a value of ‘radial-gradient(#FFF, #DDD)’, because there can only be one key named ‘background’ in the styles object.

Without looking at the source code of ng-style, I thought maybe it supported an array of values per property. So the styles object could be rewritten as:

scope.getSlideStyles = function() {
  var colorA = "#FFF";
  var colorB = "#DDD";
  var styles = {};
  styles['background'] = [
    '-webkit-radial-gradient(' + colorA + ',' + colorB + ')',
        'moz-radial-gradient(' + colorA + ',' + colorB + ')',
            'radial-gradient(' + colorA + ',' + colorB + ')'
  ];
  return styles;
}

Sadly, though, ng-style does not support this. I ended up creating an ng-style clone directive of my own, renamed sb-style. Here’s the original ng-style function as of this post:

scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
  if (oldStyles &amp;&amp; (newStyles !== oldStyles)) {
    forEach(oldStyles, function(val, style) { element.css(style, '');});
  }
  if (newStyles) element.css(newStyles);
}, true);

And here’s sb-style, which supports an array of values per CSS property:

scope.$watch(attrs.sbStyle, function(newStyles, oldStyles) {
  if (oldStyles &amp;&amp; (newStyles !== oldStyles)) {
    forEach(oldStyles, function(val, style) { element.css(style, '');});
  }
  if (newStyles) {
    forEach(newStyles, function(val, style) {
      if (val instanceof Array) {
        forEach(val, function(innerVal) {
          // Here's where the magic happens, thanks to jquery
          element.css(style, innerVal);
        });
      }
      else
        element.css(style, val); // Do the normal thing
    });
   }
 }, true);

To explain a bit more: The reason why this works is because jquery’s css function lets you repeat any CSS property with different values (kinda like you do in CSS), letting the browser decide which one to use.

And so, we had our background with radial gradient 🙂

What do you think: have you run into this issue? Do you think there’s a better way of dealing with this? Let me know in the comments.

Advertisements

2 thoughts on “Dealing with ng-style and vendor prefixes

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s