jQuery.cssHooks

Hook directly into jQuery to override how particular CSS properties are retrieved or set, normalize CSS property naming, or create custom properties.

jQuery.cssHooks()🡢 Object

The $.cssHooks object provides a way to define functions for getting and setting particular CSS values. It can also be used to create new cssHooks for normalizing CSS3 features such as box shadows and gradients.

For example, some versions of Webkit-based browsers require -webkit-border-radius to set the border-radius on an element, while earlier Firefox versions require -moz-border-radius. A css hook can normalize these vendor-prefixed properties to let .css() accept a single, standard property name (border-radius, or with DOM property syntax, borderRadius).

In addition to providing fine-grained control over how specific style properties are handled, $.cssHooks also extends the set of properties available to the .animate() method.

Defining a new css hook is straight-forward. The skeleton template below can serve as a guide to creating your own.

(function ($) {
  // First, check to see if cssHooks are supported
  if (!$.cssHooks) {
    // If not, output an error message
    throw new Error(
      "jQuery 1.4.3 or above is required for this plugin to work"
    );
  }

  // Wrap in a document ready call, because jQuery writes
  // cssHooks at this time and will blow away your functions
  // if they exist.
  $(function () {
    $.cssHooks["someCSSProp"] = {
      get: function (elem, computed, extra) {
        // Handle getting the CSS property
      },
      set: function (elem, value) {
        // Handle setting the CSS value
      },
    };
  });
})(jQuery);

Feature Testing

Before normalizing a vendor-specific CSS property, first determine whether the browser supports the standard property or a vendor-prefixed variation. For example, to check for support of the border-radius property, see if any variation is a member of a temporary element's style object.

(function ($) {
  function styleSupport(prop) {
    var vendorProp,
      supportedProp,
      // Capitalize first character of the prop to test vendor prefix
      capProp = prop.charAt(0).toUpperCase() + prop.slice(1),
      prefixes = ["Moz", "Webkit", "ms"],
      div = document.createElement("div");

    if (prop in div.style) {
      // Browser supports standard CSS property name
      supportedProp = prop;
    } else {
      // Otherwise test support for vendor-prefixed property names
      for (var i = 0; i < prefixes.length; i++) {
        vendorProp = prefixes[i] + capProp;
        if (vendorProp in div.style) {
          supportedProp = vendorProp;
          break;
        }
      }
    }

    // Avoid memory leak in IE
    div = null;

    // Add property to $.support so it can be accessed elsewhere
    $.support[prop] = supportedProp;
    return supportedProp;
  }

  // Call the function, e.g. testing for "border-radius" support:
  styleSupport("borderRadius");
})(jQuery);

Defining a complete css hook

To define a complete css hook, combine the support test with a filled-out version of the skeleton template provided in the first example:

(function ($) {
  if (!$.cssHooks) {
    throw new Error("jQuery 1.4.3+ is needed for this plugin to work");
  }

  function styleSupport(prop) {
    var vendorProp,
      supportedProp,
      capProp = prop.charAt(0).toUpperCase() + prop.slice(1),
      prefixes = ["Moz", "Webkit", "ms"],
      div = document.createElement("div");

    if (prop in div.style) {
      supportedProp = prop;
    } else {
      for (var i = 0; i < prefixes.length; i++) {
        vendorProp = prefixes[i] + capProp;
        if (vendorProp in div.style) {
          supportedProp = vendorProp;
          break;
        }
      }
    }

    div = null;
    $.support[prop] = supportedProp;
    return supportedProp;
  }

  var borderRadius = styleSupport("borderRadius");

  // Set cssHooks only for browsers that support a vendor-prefixed border radius
  if (borderRadius && borderRadius !== "borderRadius") {
    $.cssHooks.borderRadius = {
      get: function (elem, computed, extra) {
        return $.css(elem, borderRadius);
      },
      set: function (elem, value) {
        elem.style[borderRadius] = value;
      },
    };
  }
})(jQuery);

You can then set the border radius in a supported browser using either the DOM (camelCased) style or the CSS (hyphenated) style:

$("#element").css("borderRadius", "10px");
$("#another").css("border-radius", "20px");

If the browser lacks support for any form of the CSS property, vendor-prefixed or not, the style is not applied to the element. However, if the browser supports a proprietary alternative, it can be applied to the cssHooks instead.

(function ($) {
  // Feature test for support of a CSS property
  // and a proprietary alternative
  // ...
  if ($.support.someCSSProp && $.support.someCSSProp !== "someCSSProp") {
    // Set cssHooks for browsers that
    // support only a vendor-prefixed someCSSProp
    $.cssHooks.someCSSProp = {
      get: function (elem, computed, extra) {
        return $.css(elem, $.support.someCSSProp);
      },
      set: function (elem, value) {
        elem.style[$.support.someCSSProp] = value;
      },
    };
  } else if (supportsProprietaryAlternative) {
    $.cssHooks.someCSSProp = {
      get: function (elem, computed, extra) {
        // Handle crazy conversion from the proprietary alternative
      },
      set: function (elem, value) {
        // Handle crazy conversion to the proprietary alternative
      },
    };
  }
})(jQuery);

Special units

By default, jQuery adds a "px" unit to the values passed to the .css() method. This behavior can be prevented by adding the property to the jQuery.cssNumber object

$.cssNumber.someCSSProp = true;

Animating with cssHooks

A css hook can also hook into jQuery's animation mechanism by adding a property to the jQuery.fx.step object:

$.fx.step.someCSSProp = function (fx) {
  $.cssHooks.someCSSProp.set(fx.elem, fx.now + fx.unit);
};

Note that this works best for simple numeric-value animations. More custom code may be required depending on the CSS property, the type of value it returns, and the animation's complexity.

Looking for a Web Developer?

👋

Hi! I'm Basti, author of this site. If you are looking for a web developer with 15+ years of experience, holla at me!

Be it the good 'ol jQuery, vanilla JS or modern frameworks like Vue and Svelte, front- or backend, I can help you.

Just write me at jobs@jqapi.com :)