• 200916 Oct

    One of the requests that came in during the WASP feedback discussions was for image “sprites”: for the ability to take a slice of an image and use it, e.g., as a background image. This would allow lots of decorative graphics to be placed in the same file. Image slices like this are actually on the CSS Working Group’s radar; the idea’s been floating around for quite awhile, and we’ve added a placeholder for them in the new CSS3 Image Values draft.

    So I wanted to gather some feedback on what syntax would be most useful to you. :) The restriction is: the syntax must be usable as a value for any property that takes images. That is, you can’t suggest new properties. It has to be something that can be used as the value for any of background-image, list-style-image, content, border-image, etc. Bonus points for explaining why your proposed syntax is more convenient than any others.

    A few ideas to start (feel free to add your opinion on these):

    • image-slice("image.png", X, Y, W, H) Advantage: dead simple.
    • url("image.png#xywh=X,Y,W,H") Advantage: can be used other places like <img src="...">, browser address bar, etc.

    You can skip to the end and leave a response.


  • Comments

    • 01.

      I want something like this:
      a{
          image-slice:
              (“image.png”,
              (X, Y, W, H, name1),
              (X, Y, W, H, name2),
              (X, Y, W, H, name3));
          background:slice(name1);
      }
      a:hover{background:slice(name2);}
      a:active{background:slice(name3);}

    • 02.

       I like image-slice(“image.png”, X, Y, W, H) most, as it seems most consistent with the established rules and way of writing CSS.

    • 03.

      I am still not convinced sprites aren’t just a horrific hack which should be tackled by fixing whatever is keeping HTTP solutions from being effective, rather than endorsing this by codifying it. I guess having robust and reusable CSS tools to construct solutions like this can’t necessarily be bad, but… ewww.

    • 04.

      How about having something like:
      @slices {
      myBG: url(image) top left [bottom right];
      }
      *(bottom and right are optional)

      so we can use something like:
      selector {background: myBG;}

      We can reuse it, we don’t need to change the offsets (if we modify the image for example) in every selector that we’ve used the slice. And, it’s syntax is just like the old css :)

    • 05.

      I have in mind something like:

      @image-slice {
      name: myslice;
      src: url(‘my-image.png’);
      top: px;
      left: px;
      width: px;
      height: px;
      }

      .selector {
      background-image: myslice;
      }

    • 06.
    • 07.

       @Chris, Well if you forget that *maybe* you’ll get an performance enhancement from using one big image (or several big-ish images) — consider instead: What about workflow? Designers tend to have related images all in one workfile anyway, and then have to go through a step to cut them up. Wouldn’t sprites eliminate this step? I think that’s a big win right there. As for syntax, I would really prefer two versions, one that I can use anywhere (i.e. works as a url), and more importantly a named one like @ant’s example. (Though, ant has defined his names scoped to an a tag, I think maybe we can afford a global scope, like font-face).

    • 08.
      Michael "URL" Howell says:Comment » October 17th, 2009 at 6:21 am

      I prefer the second one that’s based on urls url(“image.png#xywh=X,Y,W,H”). It can be reused elsewhere.

    • 09.

      I don’t like the second way to propose image.png#xywh… since it would hijack a part of some URL:s that are possible to use today. Are there other URL hashes that do other things? image.png#reverse=1 ? No, that’s not the right way forward…

      I’m pro Shazdeh and pdarkos suggestions of separating it out to a separate @-rule. That would make backwards compatibility easier by just referencing a regular image first, and then try to load the slice.

    • 10.

       I am in favor of an at-keyword type of solution. Something along these lines of the example below will allow fallback and functionality that easily can be used for al browsers even if they do not support image slices.

      @image-slice
      {
      src: url(“/support/image.png”);
      slices: x y h w name, 0 0 16 16 “/support/icon.png”, 0 17 16 16 smallslice.png;
      }

      Usage of the slice is trivial and actually looks exactly like you have always referenced and image. With this type of technique if the browser does not support the image slice functionality you can have a nice fallback like you have always used. Supporting browsers basically hijack the references to images and redirect them to the slice if there is a matching slice reference otherwise the typical request is made for the image.

      div
      {
      background: url(“/support/icon.png”);
      }

      The trick is for browsers that do not support this slice functionality you have to create individual images for every small slice. It’s a bit of extra work but its something you would have most likely done to begin with.

    • 11.

      What I basically think is needed is a good fallback for other browsers. So the syntax should be somehow in a way that all non-supporting browsers use single images for every style e.g.:

      .elem1{background-image: url(single1.png) sprite(“combined.png#0,0,16,16″); 
      .elem2{background-image: url(single2.png) sprite(“combined.png#16,16,16,16″);

    • 12.

      This does seem to be covered by the image-rect property that’s landing in Firefox 3.6, and that syntax seems to work fine.

    • 13.

      The problem with url(“image.png#xywh=X,Y,W,H”) is there’s no backwards compatibility. If an author uses this syntax and a browser that supports url() (all currently) and doesn’t support #xywh (all currently) then the user will see the full sprite which is not acceptable. A separate functional notation like image-slice() or image_rect() allows browsers to recognize a feature that is not supported and fallback to a separate author-supplied url() declaration.

      Having an @-notation for centralizing the slice definitions for an image would be a large productivity boost for authors in both developing and maintaining sprite-using web sites as individual slices get added, dropped, moved around, and moved between sprites used for different sections of a site. CSS could use an injection of Don’t Repeat Yourself for sprites. The working group would need to address the inheritance model for an @-notation, if a later definition simply overrides for all instances or not, and also if one sprite definition can reference another or only urls. Nested sprites is an interesting tool for evolving a site, but browsers would need definition for how to handle circular references.

    • 14.

      @Chris H: The fact that many tiny images need much more size (resp. bandwidth) is not a limitation of http. So the image sprites are a good idea regardless of the quality of the protocoll.

    • 15.

      The image-rect syntax looks pretty decent and does the job, although the image-slice syntax is even more simple. If backwards compatibility is not crucial, one of these is fine with me.

      For simplicity and maintenance an @-style keyword is not needed – I currently work with a huge sprite with dozens of icons, and I keep all these rules together in one place without too much hassle or cruft. If backwards compatibility is a must though, it may be unavoidable.

      What I wonder is if those image-rects or image-slices allow repetition, that would really enable cool things that are impossible to do with sprites today.

    • 16.

      Sebastian, this is the advantage of the image-rect syntax. Older browsers will ignore it and use a previous rule that uses the old url syntax. I do this often with RGBA background color values, having an image fallback for older browsers.

      .elem1 { background-image: url(single1.png); background-image: image-rect(”combined.png”,0,0,16,16); }
      .elem2 { background: url(background.png); background: rgba(0,0,0,0.8); }

    • 17.

       @Lensco What do you mean by repetition?

    • 18.

      repeat-x and repeat-y. Currently it’s not possible to do both in one sprite image.

    • 19.

      @Ant Oh, ok. That’s a given. :) If we add native image sprite support to CSS that will effectively clip out the selected region and treat it as a standalone image.

    • 20.

      It sounds that adding just another background property would solve the problem (syntax and implementation).

      div{
      background: red url(‘image.png’) repeat-x left bottom;
      background-slice: 0 0 15px 15px; /*x y w h*/

      Or

      div{
      background: red url(‘image.png’) repeat-x left bottom slice(x, y, w, h);
      }

      This seems a easy solution for browsers to implement. Also we’d keep the syntax simple and following the current standard (all background properties together).
      We have to remember that most of the time we put different icon states into a single image, so, we’d have to change the ‘background position’ of the slice very easy.

      div:hover{
      background-slice: 0 20px 15px 15px; /*x y w h*/
      }

    • 21.

      I Agree with André Cassal.
      The slice Property should be seperate from the url Propperty.
      This would avoid the need to reenter the URL of the Image again and again, espeacially if you use combine more then one class:

      Example:
      HTML:


      CSS:
      .red-icon{background-image: url(/red-sprite.png)}
      .blue-icon{background-image: url(/blue-sprite.png)}

      .icon1{background-slice(0,0,10px,10px);}
      .icon2{background-slice(0,11px,10px,10px)}

    • 22.

      I agree with André to, but there’s just one thing that “disturb” me. We need to call a different image for the “sliced version”, instead of that, it seems that we’ll use the old way, one image for one icon….

      We can mix André’s proposition (#20) and Matt’s(#16) :

      div{
      background: red url(‘single.png’) repeat-x left bottom slice(‘combined.png’,x, y, w, h);
      }

      On one hand, modern browsers must give priority to the slice value and ignore url property. And on the other, old browsers will not understand slice and will get the url property only.

    • 23.

       But if you combine the URL of the image and the slice into one single property, you end up typing the URL again and again. This gets especiall annoying when you want to combine classes to switch sprite, e.g. if you want to use different themes:

      Example:
      see there two sprites:
      http://www.gehrmann-design.com/img/mint.png
      http://www.gehrmann-design.com/img/strawberry.png

      now imagine you do a div.mint for the green theme. And a div.strawberry for the pink theme.

      with your syntax you would end up typing:

      .mint .icon1{background: slice(‘/img/mint.png’ 0 0 15px 15px)}
      .mint .icon2{background: slice(‘/img/mint.png’ 0 15px 15px 15px)}
      .mint .icon3{background: slice(‘/img/mint.png’ 0 30px 15px 15px)}

      (…)

      .strawberry .icon1{background: slice(‘/img/strawberry.png’ 0 0 15px 15px)}
      .strawberry .icon2{background: slice(‘/img/strawberry.png’ 0 15px 15px 15px)}
      .strawberry .icon3{background: slice(‘/img/strawberry.png’ 0 30px 15px 15px)}

      (…)

      ———–
      And you would have to repeat this for every skin you later introduce.

      Seperating the properties for the image and the slice would save you a ton of code:

      .mint {background-image:url(/img/mint.png)}
      .strawberry {background-image:url(/img/strawberry.png)}

      .icon1{background-slice:slice(0 0 15px 15px)}
      .icon2{background-slice:slice(0 15px 15px 15px)}
      .icon3{background-slice:slice(0 30px 15px 15px)}

      —–
      Introducing a new color sceme would simplay be one line of code:
      .blueberry {background-image:url(/img/blueberry.png)}

      —–
      to keep old browsers happy you could use instead of the simple url() for the background image property a new one like slice-url:

      background: slice-url(/img/blueberry.png) slice(0 30px 15px 15px)

    • 24.

       sorry: there was an error in my second expample it should say:

      .mint a{background-image:url(/img/mint.png)}
      .strawberry a{background-image:url(/img/strawberry.png)}

      a.icon1{background-slice:slice(0 0 15px 15px)}
      a.icon2{background-slice:slice(0 15px 15px 15px)}
      a.icon3{background-slice:slice(0 30px 15px 15px)}

      -or-

      .mint .icon{background-image:url(/img/mint.png)}
      .strawberry icon{background-image:url(/img/strawberry.png)}

      .icon.icon1{background-slice:slice(0 0 15px 15px)}
      .icon.icon2{background-slice:slice(0 15px 15px 15px)}
      .icon.icon3{background-slice:slice(0 30px 15px 15px)}

    • 25.

       This does seem to be covered by the image-rect property that’s landing in Firefox 3.6, and that syntax seems to work fine.

    • 26.

      That’s true, perhaps this would be the short syntax :

      background: red url(‘single.png’) repeat-x left bottom slice(‘combined.png’,x, y, w, h);
      }

      and this the detailed version :

      background-color:red;
      background-image:url(‘single.png’);
      background-repeat:repeat-x;
      background-position:left bottom;
      background-slice:url(‘combined.png’) x y w h;

      or more detailed for the latest element :

      background-slice-image:url(‘combined.png’);
      background-slice-coords:x y w h;

    • 27.

      It’s too bad that new properties can’t be used, because I can see situations where it would be very useful to animate these properties via script, and having a single combined property does not fit with the animation model used by major JavScript libraries.

      For example, using jQuery you could simultaneously animate various proprties like ‘background-slice-x’ and ‘background-slice-y’, but you couldn’t handle the more generic ‘background-slice’ without the library itself being rewritten to accommodate it.

    • 28.

      http://www.css3.info/image-sprites-syntax/

      I was thinking, why is everybody defining each slice separately? Sprites are most commonly used with icons, which often have the same dimensions. So it would be easier/more elegant to just describe how the images are sliced. If you have an image file with, say, 8 icons horizontally in 4 states vertically, just slice it 8 by 4, and then just reference the slice number or slice position. Obviously, this wouldn’t allow for sprites in different dimensions in a single image file. But, we could reuse rect from css2 clip for that.

      I like the @-rule proposed by others, but it isn’t consistent with the css grammar, because it doesn’t take arbitrary rules, but keywords defined by the W3C. So, if we’re gonna go that way, we’ll have to define just one new @-rule. And while we’re busy, a generic one that we could also use for other resources, like audio, would seem better. It could even replace the @font-face rule; it just seems more sensible to have just one flexible @resource rule, instead of one for each resource type like @font-face, @image, etc.

      Anyway, I gave it some thought, mixed some propositions, added a twist of my own and came up with the following:

      @resource {} /* create a named resource */

      slice-image: url(“image.png”); /* which image file to slice */

      slice-by-x: n; /* slice the image horizontally in n slices */
      slice-by-y: n; /* slice the image vertically in n slices */
      slice-by: x y; /* shorthand for slice-by-x and slice-by-y */

      slice-x: n; /* which slice to use horizontally */
      slice-y: n; /* which slice to use vertically */
      slice: x y; /* shorthand for slice-x and slice-y, or */
      slice: n; /* use slice n (counting horizontally, then vertically) or */
      slice: rect(x, y, width, height); /* to allow for different sprite dimensions */

      And of course, the same goes for background-image and list-style-image: background-slice-image, list-style-slice etc.

      In shorthand properties like background and list-style:

      slice(“image.png”, rect(x, y, width, height));
      slice(res, rect(x, y, width, height));
      slice(res, n); /* use sprite n from named resource res or */
      slice(res); /* just use the first sprite or */
      slice(res, x, y); /* use sprite at x, y */

      An example:

      a.icon {
      slice-image: url(images/icons.png);
      background-slice-by: 8 4;
      }

      a.icon:link, a.icon:visited { background-slice-y: 0 }
      a.icon:hover { background-slice-y: 1 }
      a.icon:active { background-slice-y: 2 }

      a.icon#home { background-slice-x: 0 }
      a.icon#news { background-slice-x: 1 }
      a.icon#about { background-slice-x: 2 }

      Another example, using named resources:

      @resource {
      resource-name: buttons;
      src: url(image/buttons.png);
      slice-by: 8 4;
      }

      ul.nav#home { list-style-image: slice(buttons, 0) }
      ul.nav#news { list-style-image: slice(buttons, 1) }
      ul.nav#about { list-style-image: slice(buttons, 2) }

      For backward compatibility, use both url() and slice():

      @resource {
      resource-name: backgrounds;
      src: url(images/backgrounds.png);
      slice: rect(0, 0, 10, 10) rect(10, 0, 50, 50);
      }

      #header {
      background: red url(“red.png”) repeat slice(backgrounds, 0);
      }

      #content {
      background: white url(“white.png”) repeat slice(“backgrounds.png”, rect(10, 0, 10, 10));
      }

      Obviously, we’re trying to save bandwidth and http overhead, so user agents should only use url() as fallback, ie. they should not try to load url() if slice() is successfully loaded.

      With named resources, we could also cascade them (slice sprites again). Imagine an image sliced in 4 sprites, one for top, bottom, left and right; and then slice them up again in 1×10 horizontally or 10×1 vertically. Like this:

      @resource { resource-name: gradients; src: url(images/gradients.png); slice-by: 4 4 }
      @resource { resource-name: topgradients; src: slice(gradients, 1); slice-by: 1 10 }
      @resource { resource-name: bottomgradients; src: slice(gradients, 2); slice-by: 1 10 }
      @resource { resource-name: leftgradients; src: slice(gradients, 3); slice-by: 10 1 }
      @resource { resource-name: rightgradients; src: slice(gradients, 4); slice-by: 10 1 }

      Anyway, this solution would create quite a lot of new css properties, but otherwise I think it’s an elegant and flexible solution, it allows for repetition and position, and it’s consistent with css grammar. What do you think, does it make sense?

      PS: Sorry for the long post, I was going for the bonus points ;)

    • 29.

      This is stockholm syndrome of the highest order.

      Either fix http or come up with a sensible image format container.

    • 30.

      I can only see this being of use if it will also work alongside other well established properties – position, repeat, etc. What I find so clumsy about using sprites is having to group them by application (e.g. icon, background, etc) because they serve images by type, rather than by relevancy to the page.

       

    • 31.

      I have another approach, i got it when i saw the aPng (animated png) could also work with animate webp
      basically it would be like setting a animated background image but you would freeze the frame at one point

      .email{
      background: url(/img/animation.png);
      background-frame: 2;
      width: 16px;
      height: 16px;
      }

      .logo{
      background: url(/img/animation.png);
      background-frame: 3;
      width: 120px;
      height: 50px;
      }

      .bg{
      background: url(/img/animation.png) repeat;
      background-frame: 4; /* forth frame is as big as the biggest frame, otherwise we would have to come up with a new image format that can say that each frame has different width,height */
      }

      but i ratter see -webkit-canvas become wildy supported, demo : http://html5-demos.appspot.com/static/css/webkit-canvas.html
      so you would do something like

      logo{
      background: -webkit-canvas(email)
      }

      Then you could write your own javascript:
      var img = new Image()
      [
      {n:"email", w:16, h:16}
      {n:"logo", w:120, h:50}
      {n:"bg", w:16, h:16}
      ].forEach(function(img){
      var ctx = document.getCSSCanvasContext(“2d”, img.n, img.w, img.h);
      ctx.drawImage(img, x, y);
      })

      then you can animate and do other things

Hosting by: