If you need to position a background-image
in CSS 20px from the left and 10px from the top, that’s easy. You can do background-position: 20px 10px;
. But what if you wanted to position it 20px from the right and 10px from the bottom?
Let’s also assume we don’t know the exact width and height of the element, which is likely, because fluid layouts and dynamic content. If we did, we could just do a little scratchpad math and use the normal background-position
syntax.
A perfectly reasonable request, as they say. Here’s some ways to go about it.
The four-value syntax for background-position
This is the easiest way. You combine length values with any of top/right/bottom/left keywords (not center). So for our example:
background-position: right 20px bottom 10px;
Using this, you can offset a background-image
from any of the four corners of an element.
Browser support, according to MDN: Chrome 25+, Firefox 13+, IE 9+, Opera 10.5+, Safari/iOS 7+. The biggest danger is Android.
I tested Android 4.0, 4.1, and 4.2 and it didn’t work. But Android 4.4 did support it.
Using calc()
You can continue to use the two-value syntax of background-position
, but do it using lengths created via calc()
. Like:
background-position: calc(100% - 20px) calc(100% - 10px);
The browser support is slightly better, with Chrome back to 19+, Firefox back to 4+, and Safari back to 6+ (all prefixed).
Android stock browser had the same support as the four-value syntax above.
Using JavaScript
If you’re needing perfect browser support, I imagine the only way is JavaScript. Measure the height/width of the element, know the size of the background-image
, then adjust the CSS as needed.
Using jQuery:
var el = $(".example"),
bgWidth = 20,
bgHeight = 20;
el.css({
"background-position": (el.width()-bgWidth+10) + "px " + (el.height()-bgHeight-10) + "px"
});
Demo
Here are all three ways:
IE9 will crash if you use a calc() background-position. Just ran into that one myself.
Yes mine also crashes in IE9 however when I tried the backward compatibility setting in IE6 it works perfect surprisingly!, which build of IE9 are you running?
Ok, I admit I didn’t know about the 4 values on the
background-position
property. Nice to know.And
calc
with background images has been a problem in the past. IE9 being more or less the sole reminder of that.So badicly the only wat to solve this probleem is by adding a container element and a seperate element for the background. None of the 3 solutions works on Android 4.3 btw. Or the correct solution should be a half star
Half star is correct.
Or slice the image. Not ideal… but works!
Well these are nice methods to set the offset of background images but because of the poor browser support I wouldn’t use it. Usually I slice the image in that way that I include also the spaces. The other way would be to absolutely position an element and set on that the background but this is too much fuss.
Also I very nice solution that I heard about is setting a transparent border to the element that has the background. For instance if we want the background to be on the right but with 10px offset we could set a border-right: 10px solid transparent to that element.
Note that transparent borders are not necessarily transparent – not because of old browsers, but because of user accessibility options.
When users disable author colours or apply a high-contrast theme (which all browsers can do), transparent borders adopt the foreground colour. So what they’d see in this example is a thick border down the right-hand side of the element.
If there’s text overlapping that region, then that would be a serious accessibility problem.
But if that’s not the case (which is more likely), then it’s not an issue, but probably not what you intended either. Ultimately it might not matter, but it’s worth being aware of.
However you can use that trick to your advantage. For example, if a region is shaded with a background to visually delineate it from surrounding content, then that shading – and the visual effect it creates – is lost in a high-contrast view. But if the whole element has a 1px transparent border, then the border will become visible and re-create a comparable effect :-)
Is safe to use the four-value with fallback to calc(), like this?
No. IE9 (if i’m correct, maybe it’s IE8) crashes when using calc() in background-position.
What if you rotate the image 180 deg? Might also not have great browser support but perhaps the top left would work?
Haven’t tried it, probably too Christmased out to think straight
Awesome article,
I really love to play with CSS these days
Thanks, keep writing and keep helping :)
I enjoy all your tidbits, but what would be that extra “something” would be if you could tell me why I might care to do something like offset a background image. Perhaps a couple practical examples that might make think “oh yea” or help me share it to someone I think could use it.
Oh! that’s simple yet saves a lot of headache.
Thanks a lot Chris! I totally had forgotten about the 4 value syntax.
Really a great tutorial for me. The four-value syntax is totally new for me. Thanks for your post.
damn! its really useful to use the 4 values on the background-position property. Thanks!
It makes the front-end dev in all of us shudder, but the other way to offset a background image from the right, is to add the desired padding to the actual image in an image editor, and specify ‘right’ as the horizontal position. Hopefully the next CSS spec allows for explicit right and bottom position like the current spec does for left and top… Would be very interested to know why it isn’t already.
If you have responsive design the JS solution would need to actively check window resizing or orientation change(some device/browser combinations change viewport width on orientation change, can be tested with http://www.matanich.com/test/viewport-width/). I have sometimes icons representing ‘yes’ and ‘no’ throughout the site so I just put them in separate files and often even encode them inside the css (since they’ll appear on many pages and will need to load anyway – why not load them with the css file). If I do have to load the background from a sprite or if I have this space from the right as percentage padding (as I often do in responsive) – then I just put it in :before or :after – who would want a real element if they can get away with pseudo.
I’m trying to imagine use case here, but I’d likely go with an inner element or larger image. It’s rare that I’m in a situation where I can add custom css, but not markup.