In this article, I'm going to guide you through a concrete problem I had to solve. Eventually, we'll see how to use percentage values in the background-position
CSS property and how it solves a lot of tough issues.
Usual way
Positioning the image
The usual way to position images inside a container is to specify where the top left of the image is going to be compared to the top left of the container.
Both are really easy to implement in CSS. On the left you can see the code using a <img>
tag inside a container, the other one is a container with a background-image
attribute.
|
|
Moving inside container
Now let's say you want to be able to drag the image inside the container and make sure it doesn't go outside of the bounds. You are going to start doing some basic maths to compute the maximum values for top and left.
The left position is going to go from 0
to container_width - image_width
. Apply the same formula to calculate the maximum top position.
Image is bigger than container
So far so good. Now let's say our image is bigger than the container. We're going to extend our definition of inside the container. All the container must be filled with the image.
Again, using simple math we can compute the bounds of the left offset. Again, it is 0
and container_width - image_width
. Except that container_width - image_width
is negative this time.
You are now going to handle positive and negative values. The values now also get really counter intuitive. When you see 12px 20px
you have a rough idea of how the image will be positioned. -12px -20px
is really harder to conceptualize.
Invariants
So great, now you have written all your reposition interface and have stored the perfect position the user entered. Now, for some reason, instead of a rectangular container, you want a square one. You are in a not so comfortable position.
The values we computed can no longer be used because they no longer have the same meaning. The within bound constraint no longer holds true and the position is completely off. It is the same if you attempt to scale the image and container.
Background Image Percentage
Definition
Instead of using the previous definition of the image position, we can use another one. When the left border of the image is on the left border of the container, left is equal to 0%. When the right border of the image is on the right border of the container, left is equal to 100%.
Here's what the two values 0% and 100% looks like in the two examples:
To find the intermediate steps, we just do a linear interpolation between the two values.
left = (container_width - image_width) * percentage
Bound check
The first obvious advantage is that we no longer have to do math to compute if an image is within the bounds of the container. It is if and only if the value is between 0 and 100.
Invariants
Another way to think about this positioning is to draw two axis, one for the image on for the container. If we set the value to be 60%
, then the position is going to be where the 60%
mark on the two axis is the same point.
As you can see, this new definition works well with different ratios and scaling.
Horizontal and Vertical
If you pay close attention, you notice that if the image is the same size of the container, the value is ignored. The two axis will be perfectly aligned so all the points will match. Setting 30% or 80% doesn't matter.
If you don't believe the picture, just look at the math.
left = (container_width - image_width) * percentage
left = 0 * percentage
left = 0
The takeaway here is that you need the user to set two values. One when the image is going to scroll vertically. One when the image is going to scroll horizontally.
Conclusion
At first, I didn't understand how percentage values for the background position were working. I was really confused because this is not the way intuitively you would have used percentage.
However, once I tried to implement a robust reposition tool, I realized that this definition of percentage was convenient. It solves in an elegant way many of the issues we had with the usual positioning method.
I hope that you learned something here 🙂