diff --git a/src/css.js b/src/css.js index c17265ced..7a225d9a9 100644 --- a/src/css.js +++ b/src/css.js @@ -28,6 +28,7 @@ var // except "table", "table-cell", or "table-caption" // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssNormalTransform = { letterSpacing: "0", @@ -57,6 +58,16 @@ function vendorPropName( name ) { } } +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + function setPositiveNumber( elem, value, subtract ) { // Any relative (+/-) values have already been @@ -218,10 +229,15 @@ jQuery.extend( { // Make sure that we're working with the right name var ret, type, hooks, origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ), style = elem.style; - name = jQuery.cssProps[ origName ] || - ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName ); + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } // Gets hook for the prefixed version, then unprefixed version hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; @@ -257,7 +273,11 @@ jQuery.extend( { if ( !hooks || !( "set" in hooks ) || ( value = hooks.set( elem, value, extra ) ) !== undefined ) { - style[ name ] = value; + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } } } else { @@ -276,11 +296,15 @@ jQuery.extend( { css: function( elem, name, extra, styles ) { var val, num, hooks, - origName = jQuery.camelCase( name ); + origName = jQuery.camelCase( name ), + isCustomProp = rcustomProp.test( name ); - // Make sure that we're working with the right name - name = jQuery.cssProps[ origName ] || - ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName ); + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } // Try prefixed name followed by the unprefixed name hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; @@ -305,6 +329,7 @@ jQuery.extend( { num = parseFloat( val ); return extra === true || isFinite( num ) ? num || 0 : val; } + return val; } } ); diff --git a/src/css/curCSS.js b/src/css/curCSS.js index 313da4222..de5333030 100644 --- a/src/css/curCSS.js +++ b/src/css/curCSS.js @@ -15,8 +15,9 @@ function curCSS( elem, name, computed ) { computed = computed || getStyles( elem ); - // Support: IE <=9 only - // getPropertyValue is only needed for .css('filter') (#12537) + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) if ( computed ) { ret = computed.getPropertyValue( name ) || computed[ name ]; diff --git a/test/unit/css.js b/test/unit/css.js index 2f529b691..460023b62 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -1556,4 +1556,68 @@ QUnit.test( "Do not throw on frame elements from css method (#15098)", function( } )(); + +QUnit.test( "css(--customProperty)", function( assert ) { + jQuery( "#qunit-fixture" ).append( + "" + ); + + var div = jQuery( "