Cómo usar transform: translateX para mover un elemento secundario horizontalmente al 100% a través del elemento primario


Todos,

Me gustaría poder usar translateX para animar un elemento hijo 100% del camino a través de su padre (es decir, desde el borde izquierdo hasta el borde derecho).

El desafío es que los porcentajes en translateX se refieren al elemento en sí, no al padre.

Así que, por ejemplo, si mi html se ve así:

<div id="parent">
    <div id="child">
</div>

Y mi CSS como este (prefijos de proveedor omitidos):

#parent {
    position: relative;
    width: 300px;
    height: 100px;
    background-color: black;
}
#child {
    position: absolute;
    width: 20px;
    height: 100px;
    background-color:red;
    transform: translateX(100%);
}

Esto no funciona-el niño solo se mueve 20px (100% de sí mismo), no todo el camino a través de la padre. (Puedes ver esto en jsfiddle):

introduzca la descripción de la imagen aquí

Puedo hacer esto:

#child {
    position: absolute;
    width: 20px;
    height: 100px;
    background-color:red;
    -webkit-transform: translateX(300px) translateX(-100%);
    transform: translateX(300px) translateX(-100%);
}

Esto funciona (visto aquí de nuevo en jsfiddle), porque primero mueve el hijo 300px (el ancho completo del padre), menos 20px (el ancho del hijo). Sin embargo, esto depende de que el padre tenga una dimensión de píxel fija y conocida.

introduzca la descripción de la imagen aquí

Sin embargo, en mi diseño responsivo - no conozco el ancho del padre, y cambiará.

Sé que yo puede usar left:0 y right:0, pero el rendimiento de animación de left / right es mucho peor que translateX (Gracias Paul Irish!).

¿Hay alguna manera de hacer esto?

Gracias de antemano.

Author: isherwood, 2014-02-04

3 answers

No publiqué mi idea originalmente, porque implica crear una capa HTML adicional, y esperaba mejores soluciones por venir.

Como eso no ha sucedido, explico mi comentario. Lo que quise decir fue esto:

#parent {
    position: relative;
    width: 300px;
    height: 100px;
    background-color: black;
}
#wrapper {
    position: absolute;
    width: 100%;
    height: 100px;
    border: solid 1px green;
    transition: all 1s;
}
#wrapper:hover {
    -webkit-transform: translateX(100%);
    transform: translateX(100%);
}
#child {
    position: absolute;
    width: 20px;
    height: 100px;
    background-color:red;
}
#wrapper:hover #child {
    -webkit-transform: translateX(-100%);
    transform: translateX(-100%);
}

Dado que el wrapper tiene un ancho del 100% del padre, traducirlo al 100% funciona como se espera.

Fiddle

Tenga en cuenta que la envoltura se está traduciendo 100% como usted ha indicado. Sin embargo, parece que lo que realmente quieres es mover el elemento 100% - ancho. Para lograr esto, usted tiene que traducir el niño también 100% (ahora esto se aplica a la anchura del niño) en la dirección opuesta.

Corrección: el hijo debe compartir la propiedad transition del wrapper:

#parent {
    position: relative;
    width: 300px;
    height: 100px;
    background-color: black;
}
#wrapper {
    position: absolute;
    width: 100%;
    height: 100px;
    border: solid 1px green;
    transition: all 5s;
}
#wrapper:hover {
    transform: translateX(100%);
}
#child {
    position: absolute;
    width: 50px;
    height: 100px;
    background-color:red;
    transition: inherit;
}
#wrapper:hover #child {
    transform: translateX(-100%);
}
<div id="parent">
    <div id="wrapper">
        <div id="child"></div>
    </div>
</div>
 27
Author: vals,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-23 02:39:18

Hay una solución bastante buena para este problema usando Flexbox. La clave es aprovechar la propiedad flex-grow .

Digamos que tienes algo de HTML que se parece a esto:

<div class="flex-container">
  <div class="flex-spacer"></div>
  <div class="slider"></div>
</div>

Primero, dar .flex-container la propiedad básica display: flex, y establece su flex-direction a row. Establezca la posición de los elementos secundarios en relative , por lo que se sentarán uno al lado del otro dentro .flex-contenedor.

Por defecto, el la propiedad flex-grow está establecida en 0, que es exactamente lo que queremos al principio. Esto significa eso .flex-espaciador y .slider solo tendrá sus dimensiones normales para empezar. Simplemente nos quedamos .flex-espaciador vacío, y tendrá un ancho de 0.

Ahora para la animación. Solo necesitamos dos reglas CSS para que funcione: add a transition to .flex-espaciador y establecer flex-crecer a 1 on .flex-espaciador durante algún evento. La segunda regla da todo el ancho no utilizado dentro .flex-contenedor a la anchura de .flex-espaciador, y la primera regla anima el cambio de ancho. El .elemento deslizante se empuja a lo largo del borde de .flex-contenedor.

El CSS se ve algo como esto - he añadido un fondo a .flex-spacer para hacer su presencia un poco más obvia, y establecer flex-grow para 1 cuando el usuario pasa el cursor sobre .contenedor flexible:

body * {
  box-sizing: border-box;
}

.flex-container {
  cursor: pointer;
  display: flex;
  flex-flow: row nowrap;
  width: 100%;
  border: 2px solid #444;
  border-radius: 3px;
}

.flex-spacer,
.slider {
  flex-grow: 0;
  position: relative;
}

.slider {
  padding: 25px;
  background-color: #0DD;
}

.flex-spacer {
  background-color: #DDD;
  transition: all .4s ease-out;
}

.flex-container:hover .flex-spacer {
  flex-grow: 1;
}
<div class="flex-container">
  <div class="flex-spacer"></div>
  <div class="slider"></div>
</div>

Flexbox hace esto es bastante configurable, también. Por ejemplo, digamos que queremos .deslizador para moverse de derecha a izquierda, en su lugar. Todo lo que tenemos que hacer es cambiar la propiedad flex-direction in .flex-container to row-reverse , y hemos terminado!

Siéntete libre de jugar con él en este bolígrafo.

Tenga en cuenta que las cosas pueden ponerse un poco más complicadas si queremos animaciones para diferentes tipos de eventos. Por ejemplo, me encontré con este problema al intentar animar una etiqueta cuando un usuario escribe un elemento de entrada. Se necesita un poco más de HTML y CSS para que funcione (también usé algunos JS), pero el concepto es el mismo.

Aquí hay otro pen, esta vez en el contexto de un formulario con entrada.

 6
Author: Brady Lambert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-29 01:56:09

Si usa la solución wrapper (como en el enfoque de user vans) prefiero hacer referencia al 1% en lugar del 100% del ancho padre y multiplicar el valor traducido por 100. De esta manera se evitan problemas con los elementos en los que se puede hacer clic junto al elemento secundario.

Por ejemplo, si desea traducir su elemento hijo al centro del elemento padre:

#wrapper {
  position: absolute;
  left: 0;
  top: 0;

  width: 1%;
  overflow: visible;

  transform: translateX(5000%);
}

#child {
  transform: translateX(-50%);
}

Html

<div id="parent">
  <div id="wrapper">
    <div id="child">

    </div>
  </div>
  <a onclick="alert('im still clickable')">
    click me
  </a>
</div>

Http://codepen.io/anon/pen/BLxYXO

 2
Author: Martin Cremer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-11 16:41:55