Cómo asignar la posición del mouse en CSS

Veamos cómo obtener la posición del mouse del usuario y asignarla a propiedades personalizadas de CSS: --positionXy --positionY.

Podríamos hacer esto en JavaScript. Si lo hiciéramos, podríamos hacer cosas como hacer que un elemento se pueda arrastrar o mover un fondo. Pero, en realidad, todavía podemos hacer cosas, ¡pero sin usar JavaScript!

Utilicé este método como parte de una demostración que hice para obtener un efecto de “hacer clic y arrastrar” con CSS puro. Utilicé los perspectiveconsejos de mi artículo anterior. Es un efecto bastante interesante hacer esto completamente en CSS, lo que podría tener mayor utilidad que mi demostración, así que echemos un vistazo.

La puesta en marcha

Nuestra primera demostración utilizará propiedades personalizadas para establecer el --positionXy de un elemento.--positionYwidthheight

Tenga en cuenta que aquí solo usamos SCSS por brevedad, pero todo esto se puede hacer en CSS puro.

Este es nuestro estado inicial. Tenemos aquí una 'envoltura' divcon una .contentclase que se extiende a lo ancho y alto del cuerpo. Esto divalojará el contenido de nuestro proyecto y los elementos que queremos controlar usando la posición del mouse, en este caso, el .squareelemento.

También agregamos las dos propiedades personalizadas al archivo content. Usaremos la posición del mouse para establecer el valor de estas propiedades y luego las usaremos para establecer el .squareelemento widthy heighten consecuencia.

Una vez que hayamos asignado las propiedades personalizadas para la posición del mouse, podemos usarlas para hacer prácticamente cualquier cosa que queramos. Por ejemplo, podríamos usarlos para establecer las propiedades top/ leftde un absoluteelemento posicionado, controlar una transformpropiedad, configurar background-position, manipular colores o incluso establecer el contenido de un pseudoelemento. Veremos algunas de estas demostraciones adicionales al final del artículo.

La cuadrícula

El objetivo es crear una cuadrícula invisible en la pantalla y utilizar la :hoverpseudoclase para asignar cada 'celda' a un conjunto de valores que asignaremos a las propiedades personalizadas. Entonces, cuando el cursor del mouse se mueve hacia el lado derecho de la pantalla, el valor de --positionXserá mayor; y cuando se mueve hacia la izquierda, baja. Haremos lo mismo con --positionY: el valor será menor cuando el cursor se mueva hacia arriba y mayor cuando se mueva hacia abajo.

Unas pocas palabras sobre el tamaño de la cuadrícula que estamos usando: De hecho, podemos hacer la cuadrícula del tamaño que queramos. Cuanto más grande sea, más precisos serán nuestros valores de propiedad personalizados. Pero eso también significa que tendremos más células, lo que puede provocar problemas de rendimiento. Es importante mantener el equilibrio adecuado y ajustar el tamaño de la cuadrícula a las necesidades específicas de cada proyecto.

Por ahora, digamos que queremos una cuadrícula de 10×10 para un total de 100 celdas en nuestro marcado. (Y sí, está bien usar Pug para eso, aunque no lo haré en este ejemplo).

div/divdiv/divdiv/div!-- 97 more cells --div  div/div/div

Probablemente te estés preguntando por qué los .cellelementos aparecen antes del .content. Eso es por la cascada.

Queremos usar la .cellclase para controlar .square, y la forma en que funciona la cascada (por ahora) es que un elemento solo puede controlar a sus hijos (o descendientes) y sus hermanos (o sus descendientes), pero solo mientras el hermano sea después del elemento de control.

Eso significa dos cosas:

  1. Cada uno .celldebe ir antes del elemento que queremos controlar (en este caso, el .square).
  2. No podemos poner esos .cells en un contenedor, porque si lo hacemos, ya .contentno es su hermano.

Posicionamiento de las celdas

Hay algunas formas de colocar la .cells. podemos position: absolutey compensarlos con las propiedades topy left. O podemos translatecolocarlos en su posición usando transform. Pero probablemente la opción más sencilla sea utilizar display: grid.

body {  background-color: #000;  height: 100vh;  display: grid;  grid-template: repeat(10, 1fr) / repeat(10, 1fr);}.cell {  width: 100%;  height: 100%;  border: 1px solid gray;  z-index: 2;}
  • Es bordersolo temporal, por lo que podríamos ver la cells en la pantalla. Lo eliminaremos más adelante.
  • es z-indeximportante, porque queremos que la cells esté delante de la content.

Esto es lo que tenemos hasta ahora:

Agregando valores

Queremos utilizar .cellpara establecer los valores --positionXy --positionY.

Cuando pasamos el cursor sobre a .cellque está en la primera columna (izquierda), el valor de --positionXdebería ser 0. Cuando pasó el cursor sobre a .cellen la segunda columna, el valor debería ser 1. Debería estar 2en la tercera columna y así sucesivamente.

Lo mismo ocurre con el eje y. Cuando pasó el cursor sobre a .cellque está en la primera fila (superior), --positionYdebería ser 0, y cuando pasó el cursor sobre a cellen la segunda fila, el valor debería ser 1, y así sucesivamente.

Los números en esta imagen representan los números de los elementos de la celda en la cuadrícula. Si tomamos solo uno .cellcomo ejemplo, digamos la celda 42, podemos seleccionarlo usando :nth-child():

.cell:nth-child(42) { }

Pero debemos recordar un par de cosas:

  1. :hoverSolo queremos que este selector funcione cuando pasemos el cursor sobre la celda, así que lo adjuntaremos.
  2. Queremos seleccionar el .contenten lugar de la celda en sí, por lo que usaremos el Combinador general de hermanos ( ~) para hacerlo.

Entonces, ahora, para configurar y --positionXcuando 1se --positionYdesplaza el 42, necesitamos hacer algo como esto:3.contentcell

.cell:nth-child(42):hover ~ .content {  --positionX: 1;  --positionY: 3;}

¿Pero quién quiere hacer eso 100 veces? Hay algunos enfoques para facilitar las cosas:

  1. Utilice un bucle Sass @forpara recorrer las 100 celdas y haga algunos cálculos para establecer los valores adecuados --positionXpara --positionYcada iteración.
  2. Separe los ejes xey para seleccionar cada fila y cada columna individualmente con :nth-childla notación funcional.
  3. Combine esos dos enfoques y utilice un @forbucle Sass y :nth-childnotación funcional.

Pensé detenidamente cuál sería el mejor y más fácil enfoque a seguir, y aunque todos tienen pros y contras, llegué al tercer enfoque. La cantidad de código a escribir, la calidad del código compilado y la complejidad matemática entraron en mi pensamiento. ¿No estás de acuerdo? ¡Cuéntame por qué en los comentarios!

Establecer valores con un @forbucle

@for $i from 0 to 10 { .cell:nth-child(???):hover ~ .content {    --positionX: #{$i};  }  .cell:nth-child(???):hover ~ .content {    --positionY: #{$i};  }}

Este es el bucle básico. Lo repasaremos 10 veces ya que tenemos 10 filas y 10 columnas. Y hemos separado los ejes xey para configurarlos --positionXpara cada columna y --positionYpara cada fila. Todo lo que tenemos que hacer ahora es reemplazar esas ???cosas con la notación adecuada para seleccionar cada fila y columna.

Empecemos con el eje x.

Volviendo a nuestra imagen de cuadrícula (la que tiene números), podemos ver que los números de todas las celdas en la segunda columna son múltiplos de 10, más 2. Las celdas en la tercera columna son múltiplos de 10 más 3. Y así en .

Ahora 'traduzcamos' a la :nth-childnotación funcional. Así es como se ve la segunda columna:

:nth-child(10n + 2)
  • 10nselecciona cada múltiplo de 10.
  • 2es el número de columna.

Y para nuestro bucle, reemplazaremos el número de columna con #{$i + 1}para iterar secuencialmente:

.cell:nth-child(10n + #{$i + 1}):hover ~ .content {  --positionX: #{$i};}

Ahora tratamos con el eje y.

Mire nuevamente la imagen de la cuadrícula y concéntrese en la cuarta fila. Los números de celda están entre 41 y 50. Las celdas de la quinta fila están entre 51 y 60, y así sucesivamente. Para seleccionar cada fila, necesitaremos definir su rango. Por ejemplo, el rango para la cuarta fila es:

.cell:nth-child(n + 41):nth-child(-n + 50)
  • (n + 41)es el comienzo del rango.
  • (-n + 50)es el final del rango.

Ahora reemplazaremos los números con algunos cálculos sobre el $ivalor. Para el inicio del rango obtenemos (n + #{10 * $i + 1})y para el final del rango obtenemos (-n + #{10 * ($i + 1)}).

Entonces el @forciclo final es:

@for $i from 0 to 10 { .cell:nth-child(10n + #{$i + 1}):hover ~ .content {    --positionX: #{$i};  }  .cell:nth-child(n + #{10 * $i + 1}):nth-child(-n + #{10 * ($i + 1)}):hover ~ .content {    --positionY: #{$i};  }}

¡El mapeo está hecho! Cuando pasamos el cursor sobre los elementos --positionXy --positionYcambiamos según la posición del mouse. Eso significa que podemos usarlos para controlar los elementos dentro del archivo .content.

Manejo de las propiedades personalizadas

Bien, ahora tenemos la posición del mouse asignada a dos propiedades personalizadas. Lo siguiente es usarlas para controlar los valores y .squaredel elemento.widthheight

Comencemos con widthy digamos que queremos que sea el widthmínimo (es decir, cuando el cursor del mouse esté en el lado izquierdo de la pantalla), y queremos que crezca por cada paso que el cursor del mouse se mueva hacia la derecha..square100px20px

Usando calc(), podemos hacer eso:

.square {  width: calc(100px + var(--positionX) * 20px);}

Y, por supuesto, haremos lo mismo con height, pero en --positionYsu lugar:

.square {  width: calc(100px + var(--positionX) * 20px);  height: calc(100px + var(--positionY) * 20px);} 

¡Eso es todo! Ahora tenemos un .squareelemento simple, con widthy heightque se controla con la posición del mouse. Mueva el cursor del mouse sobre la ventana y vea cómo squarecambia widthy heighten consecuencia.

Agregué un pequeño transitionpara suavizar el efecto. Por supuesto, eso no es necesario. Y también he comentado sobre la .cellfrontera.

Probemos un método alternativo.

Puede haber un caso en el que desee "omitir" --positionXy --positionYestablecer el valor final directamente dentro del @forbucle. Entonces, para nuestro ejemplo, se vería así:

@for $i from 0 to 10 { .cell:nth-child(10n + #{$i + 1}):hover ~ .content {    --squareWidth: #{100 + $i * 20}px;  }  .cell:nth-child(n + #{10 * $i + 1}):nth-child(-n + #{10 * ($i + 1)}):hover ~ .content {    --squareHeight: #{100 + $i * 20}px;: #{$i};  }}

Entonces .squareusaría propiedades personalizadas como esta:

.square {  width: var(--squareWidth);  height: var(--squareHeight);}

Este método es un poco más flexible porque permite funciones matemáticas (y de cadena) de Sass más avanzadas. Dicho esto, el principio general es absolutamente el mismo que ya cubrimos.

¿Que sigue?

Bueno, el resto depende de ti... ¡y las posibilidades son infinitas! ¿Cómo crees que lo usarías? ¿Puedes llevarlo más lejos? Intente usar este truco en su CSS y comparta su trabajo en los comentarios o hágamelo saber en Twitter. Será genial ver una colección de estos juntos.

A continuación se muestran algunos ejemplos para hacer girar la rueda de su hámster:

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir