
Digamos que tienes un elemento con un background-image
, donde solo se ve una parte de la imagen, porque la imagen es más grande que el propio elemento. El resto está recortado, fuera del elemento.
Ahora quieres mover eso background-image
de modo que esté enfocando el centro del elemento en un punto específico en él. También desea hacer eso con valores porcentuales en lugar de píxeles. Vamos a tener que ser inteligentes.
Esto va a implicar algunas matemáticas.
Usemos esto como nuestra imagen, que tiene marcadores para el tamaño:
Y aquí está nuestro elemento, con eso background-image
aplicado. Observe que solo podemos ver la parte superior izquierda de la imagen:
Vea el enfoque de fondo de la pluma: sin posición de Jay (@jsit) en CodePen.
Ahora digamos que queremos alinear un punto específico en la imagen con el centro de ese elemento. Digamos, el punto a 300 px desde la izquierda.
Dado que estamos solicitando esta posición en píxeles, es sencillo. Sin una posición definida, el background-image
“comienza” con el punto a 100 píxeles en el centro, por lo que debe moverlo hacia la izquierda 200 píxeles:
Vea el Enfoque de fondo del lápiz: posición de píxel de Jay (@jsit) en CodePen.
Vamos a formalizarlo.
El x
valor que estás usando para background-position-x
se calcula asi:
(0.5 × [bounding box width]) - [x-coordinate]
0.5 × 200px - 300px
100px - 300px = -200px
Se tarda un segundo en darse cuenta, pero no es nada demasiado exigente. Probablemente podrías haberlo descubierto intuitivamente sin necesidad de usar una fórmula.
Pero, ¿y si quisieras (o tuvieras que) expresar background-position-x
como un porcentaje? No debería ser demasiado difícil, ¿verdad? Intentemos usar un porcentaje para centrarnos nuevamente en 300px. Teniamos background-position-x
de -200px
, vamos a convertir eso a porcentaje: -200 / 800 = -25%, entonces:
Vea el enfoque de fondo del bolígrafo: porcentaje (primer intento) de Jay (@jsit) en CodePen.
Hm. Eso no funcionó en absoluto. ¿Tal vez necesitamos usar un valor positivo?
Consulte Pen Background Focus: porcentaje (segundo intento) de Jay (@jsit) en CodePen.
Eso es mejor, pero está centrado en, como… ¿250px? ¿Qué tal como un porcentaje del ancho del cuadro delimitador: 300/200 = 150%. Eso no puede estar bien…
Vea el enfoque de fondo de la pluma: porcentaje (3er intento) por Jay (@jsit) en CodePen.
Sí, eso no está bien.
Retrocedamos. ¿Qué pasa si hacemos esto?
Vea el enfoque de fondo de la pluma: porcentaje (4to intento) por Jay (@jsit) en CodePen.
Eso parece que tiene sentido; background-position-x: 100%;
hacer el background-image
alineado a la derecha y centrado en 700 px, o 7/8 del ancho de la imagen. Pero, ¿y si quisiéramos centrarlo al 100%? Supongo que tendríamos que hacer… 9/8?
Consulte Pen Background Focus: porcentaje (quinto intento) de Jay (@jsit) en CodePen.
En este punto, no me sorprende que no haya funcionado.
Esto no se siente como el camino correcto. Retrocedamos.
¿Qué dice la especificación?
Por ejemplo, con un par de valores de ‘0% 0%’, la esquina superior izquierda de la imagen se alinea con la esquina superior izquierda de, por lo general, el borde de relleno del cuadro. Un par de valores de ‘100% 100%’ coloca la esquina inferior derecha de la imagen en la esquina inferior derecha del área. Con un par de valores de ‘75% 50%’, el punto 75% transversal y 50% inferior de la imagen se colocará en el punto 75% transversal y 50% inferior del área.
Tal vez podamos aplicar ingeniería inversa a esto.
En ese último, 112,5%, estaba alineando el punto en 112,5% en todo el background-image
con el punto en 112,5% a lo largo del cuadro delimitador. Ese tipo tiene sentido. La especificación parece escrita para facilitar solo tres valores: 0%, 50% y 100%. Cualquier otro valor no es tan intuitivo.
Con background-position-x: 0;
, nos enfocamos en 100px, o 12.5%. Con background-position-x: 100%;
, nos enfocamos en 700px, o 87.5%. Cómo background-position-x: 50%;
mira, exactamente?
Vea el enfoque de fondo de la pluma: porcentaje (sexto intento) de Jay (@jsit) en CodePen.
El 50% es algo así como nuestro “ancla” aquí; es el punto en el que nuestro punto focal deseado y el correspondiente background-position-x
los valores son iguales.
Supongamos que queremos centrarnos en 700 px o 87,5 %. Recorremos el 100% del camino desde el centro: 50% + 50%.
Vea el enfoque de fondo de la pluma: porcentaje (4to intento) por Jay (@jsit) en CodePen.
Con background-position-x
ajustado a 100%
, el centro de nuestro cuadro de unión se ha “panoramizado” desde el centro de la imagen, 3/4 del camino hacia el borde más a la derecha (de 400 px a 700 px). Si queremos “desplazarnos” hacia el borde más a la derecha, debemos ir ese 1/4 extra, o 200 px. 1/4 es 1/3 de 3/4, por lo que necesitamos avanzar un tercio más que hace un momento, o un total de 66,667 % desde el centro:
Vea el enfoque de fondo de la pluma: porcentaje (7º intento) de Jay (@jsit) en CodePen.
¡Uf! Entonces, para enfocarse en el borde más a la derecha de un background-image
que es 4 veces el tamaño de nuestro cuadro delimitador, necesitamos establecer background-position-x: 116.667%;
.
¿Cómo diablos se supone que vamos a averiguar eso?
Es una diferencia del 16,667% del 100% que podríamos esperar. Entonces, si quisiéramos centrarnos en nuestro objetivo original de 300 px (o 37,5 %), agregaríamos 16,667 %. No hay forma de que esto funcione:
Vea el enfoque de fondo de la pluma: porcentaje (8vo intento) por Jay (@jsit) en CodePen.
No.
Si quisiéramos centrarnos en el borde más a la izquierda, probablemente restaríamos 16,667 % del 0 %, ¿verdad? Eso suena como que podría ser correcto.
Vea el enfoque de fondo de la pluma: porcentaje (noveno intento) de Jay (@jsit) en CodePen.
¡Frio!
Para enfocar al 100 % o al 0 %, debe “sobrepasar” esos valores en cierta cantidad, cuando se mide desde el centro.
Entonces, si queremos enfocarnos en el 0%, o “100% del camino a la izquierda del centro”, tenemos que restar 66,667% del 50%. Si queremos centrarnos en el 100 %, o “100 % del camino a la derecha del centro”, tenemos que sumar 66,667 % al 50 %.
Podría haber esperado tener que sumar o restar un 50 % al 50 % o del 50 % para llegar a esos bordes: una proporción de 1:1 de “cuán lejos quiero ir del centro” a “cuál es mi background-position-x
el valor debe ser.” Pero en su lugar, tenemos que usar una proporción de 4:3. En otras palabras, tenemos que usar un valor cuatro tercios más “alejado del centro”.
Las cosas se están poniendo un poco difíciles aquí, así que introduzcamos algunos términos:
- c: punto focal deseado (en porcentaje) desde el borde izquierdo de la imagen de fondo
- z: factor de zoom (ancho de fondo ÷ ancho del cuadro delimitador)
- pags:
background-position-x
, para centrarse en c, dado z
Así que tomamos la distancia de un punto focal desde el centro (c − 50), la multiplicamos por 4/3 y luego sumamos ese resultado a “el centro”, o 50.
Si quisiera enfocarse en el punto a 600px (o 75%), mi background-position-x
el valor debe ser:
(75% − 50%) × 4/3 + 50% = 83.333%
¡Sí, parece que podría funcionar! Por favor por favor por favor:
Vea el enfoque de fondo del lápiz: porcentaje (décimo intento) de Jay (@jsit) en CodePen.
¡Impresionante!
Y si quisieras enfocarte en 200px, o 25%, harías:
(25% − 50%) × 4/3 + 50% = 16.667%
Vea el enfoque de fondo del bolígrafo: porcentaje (intento 11) de Jay (@jsit) en CodePen.
Guau.
Generalicemos esto:
(c − 50%) × 4/3 + 50% = p
Entonces, ¿por qué 4/3? 4 es la razón de nuestro background-image
ancho al ancho de nuestro cuadro delimitador; y 3 es… 1 menos que 4. ¿Será así de sencillo? Probemos con uno más grande background-image
, esta vez de 1000 px de ancho, o 5 veces el ancho de nuestro cuadro delimitador. Y tratemos nuevamente de enfocarnos en el punto a 200px. Aquí nuestra ecuación sería:
(20% − 50%) × 5/4 + 50% = 12.5%
Vea el enfoque de fondo de la pluma: porcentaje (intento número 12) por Jay (@jsit) en CodePen.
Oh Dios mío. ¡Funciona!
Entonces, para revisar nuestra ecuación, con una proporción variable de fondo a cuadro delimitador:
(c − 50%) × z/(z − 1) + 50% = p
Vamos a convertir esto en inglés:
Dado un punto en un background-image
en la ubicación c…
- con c expresado como un porcentaje del ancho de la imagen
- donde c está destinado a estar en el centro horizontal del cuadro delimitador de la imagen de fondo
- y donde el
background-image
es z veces más ancho que su cuadro delimitador
lo correcto background-position-x
p (expresado como porcentaje) viene dado por la siguiente fórmula:
(c − 50%) × z/(z − 1) + 50% = p
¿Podemos generalizar esto aún más?
¿Qué pasaría si quisiéramos alinear el punto al 25% de la background-image
con el punto en el 75% del cuadro delimitador? ¡Ay!
Repasemos nuestra fórmula original:
(c − 50%) × z/(z − 1) + 50% = p
Ahora introduzcamos algunos términos nuevos:
- b: punto focal deseado (en porcentaje) desde el borde más a la izquierda del cuadro delimitador. Anteriormente habíamos asumido que esto siempre era 50% para que el centro del cuadro delimitador se enfocara en nuestro objetivo en el
background-image
. - D:
background-image
punto focal (en porcentaje) para alinearlo con el punto medio del cuadro delimitador para que c se alinee con b en el cuadro delimitador; si d de labackground-image
se alinea con el 50% del cuadro delimitador, entonces c delbackground-image
se alineará con b del cuadro delimitador.
Pensémoslo de esta manera
Para querer alinear la posición c de a background-image
con la posición b de un cuadro delimitador es querer alinear alguna otra posición, d, de un background-image
con el centro del cuadro delimitador, y ya sabemos cómo hacerlo. Entonces, ¿podemos encontrar una manera de derivar d, el lugar en el que debemos estar al 50%, de c, b y z? ¡Seguro!
Con nuestro 800px de ancho background-image
, en un cuadro delimitador de 200 px de ancho (z = 4), si queremos enfocar el borde más a la derecha del cuadro delimitador (b = 100 %) en la posición de 600 px (c = 75 %) en la imagen, nos gustaría el centro del cuadro delimitador se enfocará en el punto a 500 px (d = 62,5 %).
¿Cómo pasamos de c (75%) a d (62,5%)? ¿De dónde viene esa diferencia de -12,5%?
Bueno, nuestra b era 100%, 50% mayor que nuestra antigua b “predeterminada” de 50%. Y 12,5% es 1/4 de eso; 1/4 es el inverso de nuestra z de 4. ¿De ahí viene nuestra d? Eso sería:
d = c + (50% - b)/z
Parece prometedor. Ahora podemos sustituir d por c en la fórmula original:
(d − 50%) × z/(z − 1) + 50% = p
O:
(c + (50% − b)/z - 50%) × z/(z − 1) + 50% = p
¡Uf! Probemos esto. Tratemos de alinear la posición al 25% en nuestro background-image
(200px) con la posición al 75% en nuestro cuadro delimitador. Esto sería:
p = (25% + (50% - 75%)/4 - 50%) × 4/(4 - 1) + 50%
p = -31.25% × 1.333 + 50%
p = 8.333%
Consulte Pen Background Focus: porcentaje (intento número 13) de Jay (@jsit) en CodePen.
¡Increíble! Comprobemos dos veces. ¿Qué tal el punto en 87.5% en nuestro background-image
(700px) alineado con la posición en 33.333% en nuestro cuadro delimitador:
p = (87.5% + (50% - 33.333%)/4 - 50%) × 4/(4 - 1) + 50%
p = 41.6667% × 1.333 + 50%
p = 105.555%
Consulte Pen Background Focus: porcentaje (intento 14) de Jay (@jsit) en CodePen.
¡Me parece lo suficientemente bueno!
Estoy seguro de que hay algo intuitivo en esto para ciertos tipos de personas, pero yo no soy una de esas personas.
Construyamos una función Sass que hará todas estas matemáticas ridículas por nosotros.
Consulte Pen Background Focus: porcentaje (función Sass final) de Jay (@jsit) en CodePen.
Mi cabeza da vueltas.
Cuando comencé a abordar este problema, no esperaba que fuera tan difícil, pero qué viaje. Espero que guiarlo a través de mi proceso de pensamiento haya sido esclarecedor, y que en algún momento pueda encontrar valor en nuestra pequeña función Sass.
Todos los bolígrafos incluidos en este artículo se pueden encontrar en esta colección.