11

Is it possible to use CSS sprites for "foreground" images -- i.e. images that users are supposed to click on and interact with and maybe even print?

Instead of using the CSS background-image property. What would you use?

Armen Michaeli
  • 8,625
  • 8
  • 58
  • 95
Summer
  • 2,488
  • 3
  • 23
  • 32

6 Answers6

17

You can use a standard <img /> tag and put it in a container (like a <div />) with a limited height/width. Then use relative positioning or negative margins to control the position of the image.

Josh Stodola
  • 81,538
  • 47
  • 180
  • 227
  • 1
    This is overkill IMO, you can just set the input to display block and remove the div/wrapper out of the equation all-together, it's a much simpler approach. – Nick Craver Mar 11 '10 at 19:42
  • @Nick That does not make any sense. How would you apply a sprite without using the container? – Josh Stodola Mar 11 '10 at 19:45
  • @Josh - Just using the background-position property, I do this all the time and it's **much** simpler and still valid CSS in every browser. For example on a button: `.myImg { background: url(../Images/Sprite.png) no-repeat; height: 20px; width: 40px; background-position: -40px 0; display: block; } .myImg:hover { background-position: -40px -20px; }` That's a image and a hover with much less code and markup, just need a `` and you're done. – Nick Craver Mar 11 '10 at 19:49
  • 2
    @Nick - but then it's really a background image, isn't it? – Summer Mar 11 '10 at 19:49
  • 2
    Better yet, use the div wrapper but remove the img out of the equation all-together. Use CSS background-image property instead! What is important is that the div is in the "foreground", meaning the topmost element. Not the technique used. – slebetman Mar 11 '10 at 19:52
  • @Summer: Yes it's a background image but a "foreground" div. Just imagine that the div as a virtual img in your mind. The problem is only in your mind, not on the page. – slebetman Mar 11 '10 at 19:53
  • @Summer - I added an answer to explain this a bit better, formatting in comments is....lacking. – Nick Craver Mar 11 '10 at 19:59
  • 1
    @slebetman I don't want images to be in the background, in part because it's a page that people are likely to print, and most browsers don't print background images by default. – Summer Mar 11 '10 at 20:27
  • @slebetman Yeah just remove everything and make your whole site out of DIVs with background images! Do semantics mean anything to you?! How about the default behavior of submitting the form when an input type="image" is clicked? How about alternate text for the blind? – Josh Stodola Mar 11 '10 at 20:38
  • @Josh - Who said you can't have title="" on any element? screen readers find this as well. @Summer - That's not true in most cases, just try print preview on youtube, it's mostly one big image map using background just like we're talking about: http://s.ytimg.com/yt/img/master-vfl149944.png – Nick Craver Mar 11 '10 at 20:40
  • @Nick So what? The bottom line: the reader has NO WAY to tell that the purpose of the element is to display an image! What about Images off scenario? What about default behavior/styling of input elements? There is no point of throwing all that away just to say that you used a background image. Now please quit beating this dead horse, the asker has the solution they are looking for. There are legitimate reasons to avoid background images, and I've provided a solution to work around it because I have had to do it for clients in the past. We can move on now. – Josh Stodola Mar 11 '10 at 20:46
  • 1
    @Josh - You can do as you please of course, just letting you know there's a less css, less markup, fully screen-reader and printer compatible way of doing this. Refusing to believe there is more than 1 way to do something (and correctly at that) is not a great attitude to have in the programming world. – Nick Craver Mar 11 '10 at 21:05
  • Cool, this works when creating html map circles and polygons (and don't want to approximate with positioned squares using more common css only techniques) – tovare Jul 27 '10 at 22:58
  • This also helps for an accessibility issue that came up for a client; they had to cater for people who use extensions which change the background; using CSS sprites in that case would make the image disappear; using the method described by @JoshStodola makes sure the image stays there. Thanks! – Yusuf Jan 28 '15 at 02:08
  • For a working implementation of @JoshStodola 's answer, please checkout my fiddle: https://jsfiddle.net/sayanb/uf7hqko3/14/. I have set a fixed height and width to the container div and set its overflow to hidden. Then I have shifted the child image to display parts of it. – WaughWaugh Jun 06 '18 at 13:33
3

I have solved this problem using img tags and using the object-fit and object-position properties in my css. Here's a sample of the html and css I used:-

HTML

<img src="<your image source>" class="sprite-icon sprite-icon-1 " />

CSS

.sprite-icon {
  height: 20px;
  width: 20px;
  object-fit: none;
}

.sprite-icon-1 {
  object-position: 0 0;
}

.sprite-icon-2 {
  object-position: -20px 0;
}

Obviously, you need to change the position and the size parameters according to the sprite you are using. For a full working example, check out this fiddle

WaughWaugh
  • 1,012
  • 10
  • 15
  • Won't work in IE (if that's still relevant for your project), otherwise a great solution. – wortwart Sep 01 '21 at 07:45
  • This requires that the width and height of the icon exactly match the spritesheet. What if you want to scale the image smaller or larger without regenerating the spritesheet? – jjxtra Jan 24 '23 at 18:21
0

You can do this with less CSS like this:

.myClass { background: url(../Images/Sprite.png) no-repeat; 
           height: 20px; 
           width: 40px; 
           background-position: -40px 0; 
           display: block; } 
.myClass:hover { background-position: -40px -20px; }

Whatever has the class class="myClass" will have just the image in it, nothing else. This can be a <a> an <input> or a normal <div>, whatever you want.

It's a background image...but it's the element you're looking at, nothing's in front of that background. Just because you're using background-image for the property doesn't mean it's not a foreground element...like a button you can click on. You can do that like this:

<input type="button" class="myClass" />
Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • 2
    That's background image based solution, no matter how you spin this. The question explicitly asks for something else. And I sort of understand why -- there is obviously *fundamental* difference between images that are part of document content and those that are part of its layout and style. – Armen Michaeli May 05 '17 at 17:40
0

One primary requirement that cannot be handled by background images is for ARIA. All ARIA requirements will reject the use of background images for meaningful, navigational, and other 'informative' uses that a screen reader must interpret on behalf of a user with a disability. Being able to swap out a background image css statement for an img tag and some ARIA tagging whenever necessary is a critical feature in the current regulated development environment.

The answer to the original question is yes! It is possible to use the image that is displayed in a css background statement. But you must open the sprite image in an image editor and select out the portion that represents the sprite you want and save it as a separate image and reference it in an img tag.

The challenge is that often, these situations arise in a pre-built control library. Finding and altering the code in the library that selects and displays the background image is a little difficult, changing out the code is hard!

Stato Machino
  • 1,120
  • 3
  • 13
  • 22
0

@Waughwaugh's answer https://stackoverflow.com/a/50715682/2733244 using object-fit and object-position is a simple and solid solution for this problem. Its only downside is that it won't support some older browsers. If you still need to target IE11 you can instead work with clip-path and negative margins:

.sprite {
    width: 240px;
    height: 20px;
}
.sprite-1 {
    clip-path: polygon(60px 0, 80px 0, 80px 20px, 60px 20px);
    margin-left: -60px;
    margin-right: -160px;
}

Full demo: https://jsfiddle.net/wortwart/8omfcyxb/10/

Using "real" images instead of background is often semantically better (e.g. for icons) and can have benefits for accessibility: If the image has not loaded or was blocked by the user we still have <img>'s built-in alt description. Accessibility is more than just screenreaders ...

The best approach of course is to ditch CSS sprites and simply load the images separately with HTTP/2.

wortwart
  • 3,139
  • 27
  • 31
-1

You can do this, but you have to use background images for sprites as you have to be able to set position. This can be used for links or whatever you want. Look at Googles sprite, they use it for there buttons on iGoogle: http://img0.gmodules.com/ig/images/v2/sprite0_classic.gif

Dustin Laine
  • 37,935
  • 10
  • 86
  • 125
  • -1 You can control the position of any element using `position` in CSS in combination with `top, left, right, bottom`. Alternatively, you can use negative margins. – Josh Stodola Mar 11 '10 at 19:40
  • I never said you could;t control position in any element. However, you can make it work with background images on any element. – Dustin Laine Mar 11 '10 at 19:44
  • 5
    Well of course you can, but they are specifically asking how to do it *without* background images! – Josh Stodola Mar 11 '10 at 19:48