// 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",
}
}
+// 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
// 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 ];
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 {
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 ];
num = parseFloat( val );
return extra === true || isFinite( num ) ? num || 0 : val;
}
+
return val;
}
} );
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 ];
} )();
+
+QUnit.test( "css(--customProperty)", function( assert ) {
+ jQuery( "#qunit-fixture" ).append(
+ "<style>\n" +
+ " .test__customProperties {\n" +
+ " --prop1:val1;\n" +
+ " --prop2: val2;\n" +
+ " --prop3:val3 ;\n" +
+ " --prop4:\"val4\";\n" +
+ " --prop5:'val5';\n" +
+ " }\n" +
+ "</style>"
+ );
+
+ var div = jQuery( "<div>" ).appendTo( "#qunit-fixture" ),
+ $elem = jQuery( "<div>" ).addClass( "test__customProperties" ).appendTo( "#qunit-fixture" ),
+ webkit = /\bsafari\b/i.test( navigator.userAgent ) &&
+ !/\firefox\b/i.test( navigator.userAgent ) &&
+ !/\edge\b/i.test( navigator.userAgent ),
+ oldSafari = webkit && ( /\b9\.\d(\.\d+)* safari/i.test( navigator.userAgent ) ||
+ /\b10\.0(\.\d+)* safari/i.test( navigator.userAgent ) ),
+ expected = 10;
+
+ if ( webkit ) {
+ expected -= 2;
+ }
+ if ( oldSafari ) {
+ expected -= 2;
+ }
+ assert.expect( expected );
+
+ div.css( "--color", "blue" );
+ assert.equal( div.css( "--color" ), "blue", "Modified CSS custom property using string" );
+
+ div.css( "--color", "yellow" );
+ assert.equal( div.css( "--color" ), "yellow", "Overwrite CSS custom property" );
+
+ div.css( { "--color": "red" } );
+ assert.equal( div.css( "--color" ), "red", "Modified CSS custom property using object" );
+
+ div.css( { "--mixedCase": "green" } );
+ assert.equal( div.css( "--mixedCase" ), "green", "Modified CSS custom property with mixed case" );
+
+ div.css( { "--theme-dark": "purple" } );
+ assert.equal( div.css( "--theme-dark" ), "purple", "Modified CSS custom property with dashed name" );
+
+ assert.equal( $elem.css( "--prop1" ), "val1", "Basic CSS custom property" );
+
+ // Support: Safari 9.1-10.0 only
+ // Safari collapses whitespaces & quotes. Ignore it.
+ if ( !oldSafari ) {
+ assert.equal( $elem.css( "--prop2" ), " val2", "Preceding whitespace maintained" );
+ assert.equal( $elem.css( "--prop3" ), "val3 ", "Following whitespace maintained" );
+ }
+
+ // Support: Chrome 49-55, Safari 9.1-10.0
+ // Chrome treats single quotes as double ones.
+ // Safari treats double quotes as single ones.
+ if ( !webkit ) {
+ assert.equal( $elem.css( "--prop4" ), "\"val4\"", "Works with double quotes" );
+ assert.equal( $elem.css( "--prop5" ), "'val5'", "Works with single quotes" );
+ }
+} );
+
}