4

In a userscript that previously only worked on Chrome, I was copying the entire background (completely unknown, could be an image, color, anything) from one element to another, like so:

$(target).css('background', $(source).css('background'));

This worked great, on Chrome, in all cases, because Chrome includes all background-related styles when returning a computed background property. Now I'm making the script compatible with Firefox, and this no longer works, as Firefox doesn't seem to compute background from other background-related styles.

Consider the following example:

let test = $('#test');
let style = test[0].style;
let comp = window.getComputedStyle(test[0]);
let output = '';

output += `> ${test.css('background')}\n`;
output += `> ${style.getPropertyValue('background')}\n`;
output += `> ${comp.getPropertyValue('background')}\n`;
output += 'all background styles:\n';

for (key in comp)
  if (key.startsWith('background'))
    output += `${key} = ${comp.getPropertyValue(key)}\n`;
    
$('#output').val(output);
#test {
  background-image: url(https://cdn.sstatic.net/img/share-sprite-new.svg);
  background-position-x: 10px;
  background-position-y: -20px;
  background-color: black;
  width: 150px;
  height: 34px;
}

#output {
  width: 80ex;
  height: 30ex;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="test"></div>
<textarea id="output"></textarea>

When run on Chrome (58, Windows), the output is:

> rgb(0, 0, 0) url("https://cdn.sstatic.net/img/share-sprite-new.svg") repeat scroll 10px -20px / auto padding-box border-box
> 
> rgb(0, 0, 0) url("https://cdn.sstatic.net/img/share-sprite-new.svg") repeat scroll 10px -20px / auto padding-box border-box
all background styles:
background = rgb(0, 0, 0) url("https://cdn.sstatic.net/img/share-sprite-new.svg") repeat scroll 10px -20px / auto padding-box border-box
backgroundAttachment = 
backgroundBlendMode = 
backgroundClip = 
backgroundColor = 
backgroundImage = 
backgroundOrigin = 
backgroundPosition = 
backgroundPositionX = 
backgroundPositionY = 
backgroundRepeat = 
backgroundRepeatX = 
backgroundRepeatY = 
backgroundSize = 

However, when run on Firefox (53, Windows), the output is:

> 
> 
> 
all background styles:
background = 
backgroundAttachment = 
background-attachment = scroll
backgroundBlendMode = 
background-blend-mode = normal
backgroundClip = 
background-clip = border-box
backgroundColor = 
background-color = rgb(0, 0, 0)
backgroundImage = 
background-image = url("https://cdn.sstatic.net/img/share-sprite-new.svg")
backgroundOrigin = 
background-origin = padding-box
backgroundPosition = 
background-position = 10px -20px
backgroundPositionX = 
background-position-x = 10px
backgroundPositionY = 
background-position-y = -20px
backgroundRepeat = 
background-repeat = repeat
backgroundSize = 
background-size = auto auto

There are two significant differences:

  1. Firefox returns an empty string for computed background (although, oddly, manages to compute background-position from its parts), whereas Chrome builds it from all the other background properties, and
  2. Firefox includes background- forms of each item in the computed style with their explicit values, whereas Chrome does not have any of the individual values.

My question is: Is there any simple way to retrieve the full computed background of an element that works on both Chrome and Firefox (or, really, to copy the background of one element to another, which is my end goal)? The Chrome method is very straightforward, but Firefox complicates things. jQuery is available if needed.

Jason C
  • 38,729
  • 14
  • 126
  • 182
  • I want to say that's a dupe of [_Cross-browser (IE8-) getComputedStyle with Javascript_](https://stackoverflow.com/q/15733365/1218980) but it looks like a specific case which might benefit from its own question thread. – Emile Bergeron Jun 09 '17 at 20:26

1 Answers1

3

The problem here seems to be, that the following is indeed working:

window.getComputedStyle(...).getPropertyValue('background-image')

while

window.getComputedStyle(...).getPropertyValue('backgroundImage')

is not. Note that the dasherized variant (background-image) is the CSS property name and the lower camelcase one (backgroundImage) is the JavaScript naming. This behaviour makes sense to me, since getPropertyValue

returns a DOMString containing the value of a specified CSS property.

However, the name with dashes seems to be only returned in Firefox, hence your observation that in Chrome there seems to be only the computed shorthand value.

I must admit, I never used getPropertyValue before. I always accessed such values for instance by

window.getComputedStyle(...)['backgroundImage']

which seems to work fine in both browsers. However, there's still differences in the output. But that's not a problem with the code but with the way the browser provides you with the computed values.

The below snippet returns the following in Firefox (note that there's the dasherized and camelized variantes):

all background styles:
background = 
backgroundAttachment = scroll
background-attachment = scroll
backgroundClip = border-box
background-clip = border-box
backgroundColor = rgb(0, 0, 0)
background-color = rgb(0, 0, 0)
backgroundImage = url("https://cdn.sstatic.net/img/share-sprite-new.svg")
background-image = url("https://cdn.sstatic.net/img/share-sprite-new.svg")
backgroundBlendMode = normal
background-blend-mode = normal
backgroundOrigin = padding-box
background-origin = padding-box
backgroundPosition = 0% 0%
background-position = 0% 0%
backgroundRepeat = repeat
background-repeat = repeat
backgroundSize = auto auto
background-size = auto auto

And this in Chrome:

> rgb(0, 0, 0) url("https://cdn.sstatic.net/img/share-sprite-new.svg") repeat scroll 10px -20px / auto padding-box border-box
> 
> rgb(0, 0, 0) url("https://cdn.sstatic.net/img/share-sprite-new.svg") repeat scroll 10px -20px / auto padding-box border-box
all background styles:
background = rgb(0, 0, 0) url("https://cdn.sstatic.net/img/share-sprite-new.svg") repeat scroll 10px -20px / auto padding-box border-box
backgroundAttachment = scroll
backgroundBlendMode = normal
backgroundClip = border-box
backgroundColor = rgb(0, 0, 0)
backgroundImage = url("https://cdn.sstatic.net/img/share-sprite-new.svg")
backgroundOrigin = padding-box
backgroundPosition = 10px -20px
backgroundPositionX = 10px
backgroundPositionY = -20px
backgroundRepeat = repeat
backgroundRepeatX = 
backgroundRepeatY = 
backgroundSize = auto

(I only changed your usage of getPropertyName(...) in favor of the access using the bracket notation [...])

let test = $('#test');
let style = test[0].style;
let comp = window.getComputedStyle(test[0]);
let output = '';

output += `> ${test.css('background')}\n`;
output += `> ${style.getPropertyValue('background')}\n`;
output += `> ${comp.getPropertyValue('background')}\n`;
output += 'all background styles:\n';

for (key in comp)
  if (key.startsWith('background'))
    output += `${key} = ${comp[key]}\n`;
    
$('#output').val(output);
#test {
  background-image: url(https://cdn.sstatic.net/img/share-sprite-new.svg);
  background-position-x: 10px;
  background-position-y: -20px;
  background-color: black;
  width: 150px;
  height: 34px;
}

#output {
  width: 80ex;
  height: 30ex;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="test"></div>
<textarea id="output"></textarea>
SVSchmidt
  • 6,269
  • 2
  • 26
  • 37