# Position a CSS background like a block element

Percentages in the CSS background-position values “refer to the size of the background positioning area minus size of background image” (source). Chris Coyier illustrated it wonderfully on css-tricks.com and as he said, it’s a really clever and intuitive way of doing it.

Sometimes though, you may want to position the background as though it was an element with `position:absolute`. It’s trivial if the element has a fixed dimension. You just use pixels instead of percentages. But there’s a small arithmetic problem to solve if your layout is fluid.

I had to figure out that problem recently in a project which involved elements with a gradient progress bar as a background in a variable-width design. I didn’t want to just scale the background because I wanted to preserve the aspect of the gradient.

## Example

Consider the following:

…where:
100% is the width of the element,
w is the relative width of the progress bar’s gradient (30% in this example),
p is the percentage of progress so far(75% in this example).

You want to position the gradient `1 - p` from the right. At `right 100%` (p = 0%) you end up with the left end of the gradient aligned with the left border of the element.

0% (wrong)

## Formula

Now since the percentage position is calculated in relation to `1 - w`, you just need to bring that value back to 1 with a multiplicative inverse and calculate `p´ = (1 ÷ (1 - w)) × p`

For example, if the progress is 75% and you want to position the right edge of the gradient at exactly 25% of the right border, the `background-position` will be:
`(1 ÷ (1 - w)) × (1 - p)`
`(1 ÷ (1 - 0.3)) × (1 - 0.75)`
`(1 ÷ 0.7) × 0.25`
`1.43 × 0.25`
`0.36` or 36%

75% (positioned at 36% from the right)

0% (positioned at 143% from the right to get it right)

## Warning

Because of the way background image percentage positions are multiplied by `1 - w`, the multiplier is zero when the background is stretched to 100% of the width of the element. This is one of the reasons my gradient is scaled down to 30% with `background-size: 30%`.

## For Django templates

Here is a Django filter that will convert a progress percentage into the required right-positioning percentage. It take one argument, the relative width of the background as a floating point number.

``````from django import template

register = template.Library()

@register.filter
def relative_bg_pos(value, arg):
"""Calculates the % offset of the background like an absolutely positioned
block rather than the way browsers calculate the background-position.

https://css-tricks.com/i-like-how-percentage-background-position-works/
"""
from_right = 1 - value
bg_width = float(arg)
size_ratio = 1 / (1 - bg_width);
return "{:.2%}".format(size_ratio * from_right)</pre>
``````

Use it in a template like so. Suppose that the context variable `p` contains the progress as a floating point value between 0 and 1. Notice how the `background-size` is 30% and I passed 0.3 as a parameter to the `relative_bg_pos` filter.

``````<style>
.progressbar {
background: -moz-linear-gradient(left, rgba(86,88,137,0) 0%, rgba(86,88,137,0.24) 100%); <span class="comment">/* FF3.6+ */</span>
background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(86,88,137,0)), color-stop(100%,rgba(86,88,137,0.24))); <span class="comment">/* Chrome,Safari4+ */</span>
background: -webkit-linear-gradient(left, rgba(86,88,137,0) 0%,rgba(86,88,137,0.24) 100%); <span class="comment">/* Chrome10+,Safari5.1+ */</span>
background: -o-linear-gradient(left, rgba(86,88,137,0) 0%,rgba(86,88,137,0.24) 100%); <span class="comment">/* Opera 11.10+ */</span>
background: -ms-linear-gradient(left, rgba(86,88,137,0) 0%,rgba(86,88,137,0.24) 100%); <span class="comment">/* IE10+ */</span>
background: linear-gradient(to right, rgba(86,88,137,0) 0%,rgba(86,88,137,0.24) 100%); <span class="comment">/* W3C */</span> 