the problem
Hi, i'm working with sprites and got some interesting behavior of firefox and Chrome. When my sprite have 655 images or less, my sprite works fine. But when it goes furter (656 or more) it doesn't get displayed (just become invisible). I'm guessing the problem is not in my code since it works fine in Opera and IE. How come?
details
I'm using PHP to generate the sprites on-the-fly. The generated html goes like this:
<span class="_sprite_images _sprite_images_1"></span>
<span class="_sprite_images _sprite_images_0"></span>
<span class="_sprite_images _sprite_images_2"></span>
<span class="_sprite_images _sprite_images_3"></span>
<span class="_sprite_images _sprite_images_4"></span>
<span class="_sprite_images _sprite_images_5"></span>
[...]
and the CSS looks like this:
._sprite_images{background:url("../sprite_images/sprite.jpg");display:inline-block;}
._sprite_images_0{width:50px;height:50px;background-position:0 0px;}
._sprite_images_1{width:50px;height:50px;background-position:0 -50px;}
._sprite_images_2{width:50px;height:50px;background-position:0 -100px;}
[...]
Each image of my sprites have the size 50x50 (px) and are about 2 to 6 KB. I have tested them with the types jpg, png and gif. All got the same results.
screenshots
655 images
656 images
Source: Tips4all
Edit: If the cause of the issue is not the CSS length integer value, then it's the maximum image size the browser(s) in question can process. This probably is more the case here re-reading your question.
ReplyDeleteSee Firefox Bug 591822: Images taller or wider than 32767
I used the value calculated below to look up that ticket quickly via google ;)
If you want it to work, help with cairo, the underlying image library.
What you can do as well is to not spread your sprites on one axis (y in your case) only, but on both (x and y):
0: 0 0
...
654: 0 -32700
655: -50 0
and so on. PHP:
$offset = -50;
$x = (int)($n/655) * $offset;
$y = $n % 655 * $offset;
You have an offset of -50 pixels per sprite.
The first sprite has an offset of 0 ((1-1) * -50).
For the sprite #655 the offset is 654 * -50 which is -32,700.
The sprite #656 has the offset 655 * -50 which is -32,750.
The sprite #657 has the offset 656 * -50 which is -32,800.
A 16 bit, unsigned integer Wikipedia (halfword, word, short) ranges from 0 to 65535, it's signed counterpart from -32,768 to 32,767.
Just comparing these values show, that if the browser in question uses that data-type to store the integer value of the pixel unit, it won't be able to:
-32,800 is lower than -32,768
What can happen in this case is, that it's getting a round-trip:
-32,800 => 32
If you would place a sprite on your sprite pane on the (relative) coordinate -32 (which is not possible), you might be able to see it.
This is only an assumption, I have not the source codes of the browsers in question checked, so take it with a grain of salt.
However this might lead to some quick solving strategy which is fair if it turns out working fast:
How to solve?
You can try (as long as the rendering algorithms are not affected by this), to use another unit. Put all your sprites into a parent element, e.g. a <div>:
<div class="sprites">
<span class="img-1"></span>
<span class="img-2"></span>
<span class="img-3"></span>
...
<span class="img-656"></span>
</div>
CSS:
div.sprites {font-size:50px;}
div.sprites span {background: ... ; height: 1em; width: 1em;} /* default sprite definition*/
div.sprites span.img-1 {background-position:0 0;}
div.sprites span.img-2 {background-position:0 -1em;}
div.sprites span.img-3 {background-position:0 -2em;}
...
div.sprites span.img-656 {background-position:0 -655em;}
This might be more cross-browser compatible, as the integer length of each unit is not much smaller.
Let me know if it works, you didn't post any code in your question as a demo example, so I didn't compile a demo as well, but I hope the idea behind the solution suggestion is clear.