So verwenden Sie transform:translateX, um ein untergeordnetes Element zu 100 % horizontal über das übergeordnete Element zu verschieben

Lesezeit: 7 Minuten

Benutzer-Avatar
mattstühler

Alle,

Ich möchte verwenden können translateX um ein untergeordnetes Element zu 100 % über das übergeordnete Element zu animieren (dh vom linken Rand zum rechten Rand).

Die Herausforderung besteht darin, dass Prozente in translateX beziehen sich auf das Element selbst, nicht auf das übergeordnete Element.

Also, zum Beispiel, wenn mein HTML so aussieht:

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

Und mein CSS so (Vendor-Präfixe weggelassen):

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

Das funktioniert nicht – das Kind bewegt sich nur 20 Pixel (100 % von sich selbst), nicht ganz über das Elternteil. (Sie können dies auf sehen jsfiddle):

Geben Sie hier die Bildbeschreibung ein

Ich kann dies tun:

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

Das funktioniert (s hier nochmal auf jsfiddle), weil es zuerst das untergeordnete Element um 300 Pixel (die volle Breite des übergeordneten Elements) minus 20 Pixel (die Breite des untergeordneten Elements) verschiebt. Dies hängt jedoch davon ab, dass der Elternteil eine feste, bekannte Pixelabmessung hat.

Geben Sie hier die Bildbeschreibung ein

In meinem responsiven Design kenne ich jedoch die Breite des übergeordneten Elements nicht und sie wird sich ändern.

Ich weiß, dass ich verwenden kann left:0 und right:0aber die Animationsleistung von left/right ist viel schlechter als translateX (Danke Paul Irish!).

Gibt es eine Möglichkeit, dies zu tun?

Danke im Voraus.

  • Die einzige Möglichkeit, die mir einfällt, wäre, das Kind mit einer Breite von 100 % zu umhüllen und es anstelle des Kindes zu animieren

    – Wert

    4. Februar 2014 um 18:00 Uhr

  • @vals Animieren der width würde wahrscheinlich die gleichen Performance-Fallstricke erleiden wie die Animation leftnein?

    – Murray Rowan

    11. Februar 2014 um 4:34 Uhr


  • @MurraySmith Richtig, Rand/Breite/Links sind nicht GPU-beschleunigt und beeinträchtigen die Leistung. Gehen Sie für Transformationen.

    – BlueSix

    29. Juli 2014 um 3:21 Uhr

Benutzer-Avatar
Wert

Ich habe meine Idee ursprünglich nicht gepostet, weil sie das Erstellen einer zusätzlichen HTML-Ebene beinhaltet und erwartete, dass bessere Lösungen kommen würden.

Da dies nicht geschehen ist, erkläre ich meinen Kommentar. Was ich meinte war folgendes:

#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%);
}

Da der Wrapper zu 100 % die Breite des übergeordneten Elements hat, funktioniert die Übersetzung zu 100 % wie erwartet.

Geige

Beachten Sie, dass der Wrapper zu 100 % übersetzt wird, wie Sie es angegeben haben. Es scheint jedoch, dass Sie das Element wirklich um 100% verschieben möchten – Breite. Um dies zu erreichen, müssen Sie das Kind auch zu 100% (das gilt jetzt für die Kindbreite) in die entgegengesetzte Richtung übersetzen.

Korrektur: Das Kind sollte die Übergangseigenschaft des Wrappers teilen:

#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>

  • Vals – das ist ein Ja wirklich clevere Lösung. Ich habe dem untergeordneten Element einen Übergang hinzugefügt, sodass sich das untergeordnete Element zu 100 % nach links bewegt hat, wenn die Hülle zu 100 % rechts ist. (Siehe hier: jsfiddle.net/Nprs7/1). Es funktioniert perfekt. Vielen Dank!

    – mattstühler

    11. Februar 2014 um 14:21 Uhr

  • Tolle Lösung! Aber um das umständliche Herausbewegen aus dem übergeordneten Element zu Beginn des Übergangs zu vermeiden, sollten Sie dem untergeordneten Übergang möglicherweise eine Verzögerung hinzufügen, um immer innerhalb des übergeordneten Elements zu sein.

    – gigaDIE

    6. Januar 2015 um 11:32 Uhr


  • @gigaDIE Guter Punkt, ich habe dieses Problem in meiner ursprünglichen Antwort nicht bemerkt. Gelöst, dass das Kind die Übergangseigenschaft erbt (siehe Ausschnitt)

    – Wert

    6. Januar 2015 um 19:35 Uhr

  • Toll, hat aber noch einen Bug, die Animation hängt sich dabei auf #child schwebt. Sie müssen angeben :hover auf der #parent Um alle Probleme zu vermeiden: jsfiddle.net/Nprs7/65

    – István Ujj-Mészáros

    25. Juli 2015 um 10:36 Uhr

  • Ich liebe diesen Tipp

    – CKGrafico

    26. Juni 2017 um 17:08 Uhr

Es gibt eine ziemlich coole Lösung für dieses Problem mit Flexbox. Der Schlüssel ist, die Vorteile zu nutzen Flex-Wachstum Eigentum.

Angenommen, Sie haben HTML, das so aussieht:

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

Geben Sie zunächst .flex-container die Basis Anzeige: flex Eigenschaft, und setzen Sie seine Flex-Richtung zu die Zeile. Stellen Sie die Positionierung der untergeordneten Elemente auf ein relativsodass sie im .flex-Container nebeneinander sitzen.

Standardmäßig ist die Flex-Wachstum Eigenschaft eingestellt ist 0, das ist genau das, was wir am Anfang wollen. Das bedeutet, dass .flex-spacer und .slider zunächst nur ihre normalen Abmessungen haben. Wir lassen einfach .flex-spacer leer, und es wird ein haben Breite von 0.

Nun zur Animation. Wir brauchen nur zwei CSS-Regeln, damit es funktioniert: a hinzufügen Überleitung zu .flex-spacer und setzen Flex-Wachstum zu 1 auf .flex-spacer während eines Events. Die zweite Regel gibt alle ungenutzten an Breite innen .flex-Container zum Breite von .flex-spacer, und die erste Regel animiert die Breitenänderung. Das .slider-Element wird an den Rand des .flex-Containers geschoben.

Das CSS sieht ungefähr so ​​aus – ich habe .flex-spacer einen Hintergrund hinzugefügt, um seine Präsenz ein wenig deutlicher zu machen, und gesetzt Flex-Wachstum zu 1 wenn der Benutzer über .flex-container schwebt:

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 macht dies auch ziemlich konfigurierbar. Angenommen, wir möchten stattdessen, dass sich .slider von rechts nach links bewegt. Alles, was wir tun müssen, ist die zu wechseln Flex-Richtung Eigenschaft in .flex-Container zu Zeilenumkehrungund wir sind fertig!

Fühlen Sie sich frei, damit zu spielen Stift.

Denken Sie daran, dass die Dinge etwas kniffliger werden können, wenn wir Animationen für verschiedene Arten von Ereignissen wünschen. Ich bin beispielsweise auf dieses Problem gestoßen, als ich versuchte, eine Beschriftung zu animieren, wenn ein Benutzer ein Eingabeelement eingibt. Ein wenig mehr HTML und CSS sind erforderlich, damit es funktioniert (ich habe auch etwas JS verwendet), aber das Konzept ist dasselbe.

Hier ist ein anderes Stiftdiesmal im Kontext eines Formulars mit Eingabe.

  • Das Problem dabei ist, dass es ein Aufblitzen der Farbe auslöst, also nicht wirklich glatt / effizient ist.

    – XCS

    1. Juni 2018 um 9:47 Uhr

  • Dies funktioniert leider nicht auf IE11, da IE11 anscheinend kein Flex-Grow animiert.

    – Rick Doesburg

    9. Oktober 2018 um 9:06 Uhr

  • Gute Lösung, wenn die Breite der Schieberegler variabel ist, z. B. wenn es sich um benutzerdefinierten Text handelt.

    – piotr_cz

    22. Januar 2019 um 9:11 Uhr

Ich habe dies mit Wrapper und flex-grow:1 implementiert.
Hier sind zwei Animationen zur gleichen Zeit mit der gleichen Dauer: 1) der Container (grün) bewegt sich mit dem Auto auf 100 % der Elternbreite; 2) Das Auto bewegt sich um -100 % seiner Breite zurück (um an der Ziellinie auf der Strecke zu bleiben). Die Dauer kann separat genommen und auf den Container (.track-inner) und das Auto (.car) verteilt werden

 const goBtn = document.querySelector('.go');
    const inner = document.querySelector('.track-inner');
    const car = document.querySelector('.car');
    const durationFromServerMS = '3000ms'; 
    
    goBtn.addEventListener('click', ()=>{
      inner.classList.add('drive');
      inner.style.animationDuration = durationFromServerMS;
      car.classList.add('backShift');
      car.style.animationDuration = durationFromServerMS;
    })
    
    const backBtn = document.querySelector('.back');
    backBtn.addEventListener('click', ()=>{
      inner.classList.remove('drive');
      car.classList.remove('backShift');
    })
html, body {
      padding: 2rem;
    }
    
    .track{
      width: 50%;
      display:flex;
      position: relative;
      background-color: gray;
      width: auto;
      margin-bottom: 1rem;
      border: 5px dashed blue;
      overflow:hidden;
    }
    
    .track-inner{
      width: 100%;
      border: 5px dotted green; 
    }
    
    .car{
      width: 3rem;
      height: 1.5rem;
      border: 1px solid black;
      background-color: salmon;
    }
    
    .finish-line{
      position:absolute;
      top:0;
      right: 0.5rem;
      width: 3rem;
      height: 1.5rem;
      border-left: 6px dotted yellow;
    }
    
    button{
      padding: 0.5rem 1rem;
      background-color: lightblue;
      outline: none;
      border:none;
      margin: 0.2rem
    }
    
    button:hover{
      pointer:cursor;
      background-color: salmon;
    }
    
    
    .backShift {
      animation-name: car-back;
      /* animation-duration: 5s; */
      animation-timing-function: ease-in;
      animation-fill-mode: forwards;
    }
    
    .drive {
      animation-name: driving;
      /* animation-duration: 5s; */
      animation-timing-function: ease-in;
      animation-fill-mode: forwards;
    }
    
    
    @keyframes driving {
      0% {
        transform: translateX(0%);
      }
      100% {
        transform: translateX(100%);
      }
    }
    
    @keyframes car-back {
      0% {
        transform: translateX(0%);
      }
      100% {
        transform: translateX(-100%);
      }
    }
    
    p{
      padding:0;
    }
<div class="track">
        <div class="track-inner">
          <div class="car ">car</div>
        </div>
        <div class="finish-line">finish</div>
      </div>
    
    <div>
      <button class="go">Go</button>
      <button class="back">Back</button>
    </div>
    
    
    
    
    
   

1204720cookie-checkSo verwenden Sie transform:translateX, um ein untergeordnetes Element zu 100 % horizontal über das übergeordnete Element zu verschieben

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy