Search code examples
cssmathcoordinatesbackground-position

Reverse-engineer CSS `background-position` from two overlapping HTML elements


I have a project in which the user may specify an arbitrary image for use as a background image of an element later on. The user must be able to position the image within the host element to which it will be applied in order to ensure the portion of the image desired for display is, in fact, the portion visible.

SitePoint notes the following regarding the behavior of the CSS background-position property:

Note that when the background-position is defined with a percentage value, that position refers to both the element itself and the corresponding point on the background-image. For example, a background-image with background-position values of 50% 50% will place the point of the image that’s located at 50% of the image’s width and 50% of the image’s height at a corresponding position within the element that contains the image. In the above case, this causes the image to be perfectly centered. This is an important point to grasp—using background-position isn’t the same as placing an element with absolute position using percentages where the top-left corner of the element is placed at the position specified.

Say you have two HTML elements. The first is a large element representing an image to be used as a background position later. The second is a smaller element layered above the first element, and representing the element upon which the background image will be applied in the future.

+-----------------------+ <-- Y1
| Image Placeholder     |
|                       |
| +-----------------------+ <-- y1
| | Container Placeholder |
| +-----------------------+ <-- y2
|                       |
|                       |
|                       |
|                       |
|                       |
|                       |
+-----------------------+ <-- Y2

Given the y coordinates of the top and bottom of each of these elements, how can the correct percentage be calculated so as to preserve the correct portion of the image being visible within the final element with its background image applied?


Solution

  • Let's take the original visualization, adding variables for the two points the percentage position of which we are seeking:

          +-----------------------+ <-- Y1
          | Image                 |
          |                       |
          |         +-----------------------+ <-- y1
    Y3 -->|   y3 -->| Container             |
          |         +-----------------------+ <-- y2
          |                       |
          |                       |
          |                       |
          |                       |
          |                       |
          |                       |
          +-----------------------+ <-- Y2
    

    By definition, these two points (the one on the image and the one on the container) must be at the same location. The two percents must equal. Therefore:

    Y_3 = y_3

    The next step appears to be defining these two target points. This proves to be easier for the larger of the two elements, assuming that its top-left corner is positioned at coordinates [0,0]:

    Y_3=pY_2

    where p denotes the percentage we're seeking.

    This equation looks as if it would almost work for the smaller element, except that this element does not start at point [0,0]. Instead, it begins at point [x1,y1]. (We can safely ignore its x origin as we are only concerned with the y percent.)

    Correcting for this offset leads us to this equation:

    y_3=p(y_2-y_{1}) + y_{1}

    Substituting into our original equation, we get this:

    pY_2=p(y_2-y_1) + y_1

    Now all that remains is to solve for p; which, when done, leaves us with this final equation:

    p=\frac{y_1}{Y_2 - (y_2-y_1)}

    Here is a jsfiddle example of this equation in action. Drag the yellow element up and down to see the percentage (outputted below the image) dynamically calculated. The red tick mark is a visual indicator of the same percentage.