3

So, I'm looking to do a background image in CSS using a sprite sheet. And just to be clear, no I am not going for this effect. I have a full sprite sheet, and I would like to take a 16px by 16px square on the sheet and set it as the background that will be repeated.

At some point in the future, I hope to be able to do this via spacial dimensions using media fragments in the URL parameter, but since this isn't supported yet I'm looking for an alternative. Is there any way to get this same effect via modern CSS techniques or hacks?

Some notes:

  • I don't need to support old browsers, just the latest FF or Chrome will do.
  • I would prefer pure CSS solutions. I can and will create a JS/Canvas solution with data:URI's if I need to but considering how many elements I may need this for, I would prefer to not have to do that if I can get better results via pure CSS.
  • Need to repeat in both x and y directions
  • Looking for solution that takes advantage of a single image in memory/cache so that I don't have to load the sprite-sheet for every sprite I want to insert
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
LoveAndCoding
  • 7,857
  • 2
  • 31
  • 55
  • You've mentioned Data URIs, but only in terms of Javascript - you can use Data URIs and have a "pure CSS" solution. http://jsfiddle.net/47CMr/ - this *should* meet most of your goals. Specifically there would be no additional files to download, and you can cache it so they only have to download the file once. – SpoonNZ Jan 18 '12 at 21:11
  • 1
    @SpoonNZ: My eyes! The goggles, *they do nothing!* But in all seriousness, data URIs won't be *particularly* useful in CSS here since you would have to generate them manually anyway. – BoltClock Jan 18 '12 at 21:14
  • @SpoonNZ That's not quite what I'm looking for. I have a sprite sheet as a PNG. That would increase the file size of any CSS styles (unless I do a class for *every* sprite I have, including ones that can span more than one sprite location) and would mean I would need to convert each of the sprites to a data url. My goal with this is to be able to, given an x and y, as well as a width and height, get an image dynamically, which that method isn't really good for. – LoveAndCoding Jan 18 '12 at 21:16
  • Yes, I realise it's awful! It does work in most browsers though, and if you're not changing the sprite often it could be a "set and forget" thing. I'd probably put the images in a separate stylesheet and use classes (or a CSS preprocessor to make it readable). Still not a good solution though. – SpoonNZ Jan 18 '12 at 21:25

2 Answers2

2

Here's a pure CSS solution that works in Firefox only, but seems to meet all your requirements.

body{ background-image: -moz-image-rect(
    url('http://placekitten.com/500/500'),
    0,100,100,0
); }

Example at http://jsfiddle.net/47CMr/2/

SpoonNZ
  • 3,780
  • 1
  • 20
  • 25
  • Exactly what I was looking for. And even the potential for webkit support. Though, it looks like it isn't in the spec any more, so we will see if it lasts. Will award the bounty when I can (I have to wait for it). – LoveAndCoding Jan 18 '12 at 21:33
  • My googling suggested there was something in the spec for CSS in the future - I tried it in a fiddle, but it didn't work in FF or Chrome so not much use today... – SpoonNZ Jan 19 '12 at 00:45
  • Hmm, do you mean something other than the media fragment URI specification? Because I didn't see anything background related that would seem to support it... – LoveAndCoding Jan 19 '12 at 01:50
  • Have a look in section 3 of http://www.w3.org/TR/2012/WD-css3-images-20120112/ - I didn't notice when I first stumbled across it, but it's only a week old, which could be why it's not too prevalent. Wouldn't be surprised to see Chrome/FF/Opera take this and run with it soon. Also wouldn't be surprised to see it die. – SpoonNZ Jan 19 '12 at 19:41
  • Haha, I assume you mean the examples like `('sprites.svg#xywh=40,0,20,20')`? That is a media fragment URI, which is what I was looking for an alternative for ;) – LoveAndCoding Jan 19 '12 at 19:43
  • Ahh, so it is! I didn't bother reading the bit around it, just the syntax. #smart – SpoonNZ Jan 19 '12 at 19:45
1

There is only one method that falls under your conditions (the hardest one is the need to repeat): using the border-image.

The dabblet with the demo: http://dabblet.com/gist/1635890

The point is: you can mark the part that you want to use using the border-image-slice part of the border-image property. The syntax is a bit tricky, but using it you could create different repeating paterns from border-images. Also, when the needed parts are not on the edge, or when you need to repeat the image both on X and Y, you'll need a clip property, so you'll need a block to be absolute positioned. All these things work even in Opera.

But, there is one bad, bad thing: the rendering of central part of border-image is a kelly hell: there is a difference not only between webkit and mozilla, but even between the Safari and Chrome, so I added a lot of hacks there.

In conclusion: the goal can be achieved, but with a hell of a hacks.

So, I'd advice you to use the data:uri, 'cause there are no other ways to do this in webkits and Fx both (in Fx-only you could use the -moz-image-rect as mentioned above).

kizu
  • 42,604
  • 4
  • 68
  • 95
  • Using one giant border and border image isn't something that I'd considered. And I really only need to support one browser. It is for a HTML5 game, and either browser would work. Basically I'm using it to test/show off new technologies, so for some things, the more forward looking the better. Thanks for the suggestions though :) – LoveAndCoding Jan 19 '12 at 01:48
  • Yep, for new technologies showing-off the `image-rect` is better. My version is just a hack :) – kizu Jan 19 '12 at 07:23