Waarom is translateY(-50%) nodig om een ​​element te centreren dat bovenaan staat: 50%?

Ik zie dat deze code werkt om een ​​div verticaal uit te lijnen binnen het bovenliggende element:

.element {
  position: relative;
  top: 50%;
  transform: translateY(-50%);
}

De vraag is waarom? Mijn eerste gedachte was dat het bovenliggende element meer omvatte dan de viewport. Ik heb de hoogte van mijn bovenliggende viewport gelijk gemaakt aan 100vhen breedte 100%. Dat werkte niet. Ik had nog steeds de vertaling of een negatieve marge-offset nodig. Waarom heb ik een negatieve offset nodig als het bovenliggende element is ingesteld op margin: 0;? Komt het door een berekende marge waar ik geen rekening mee houd?


Antwoord 1, autoriteit 100%

top:0 (standaard)

Standaard staat uw element bovenaan de pagina en de bovenkant van het element op 0:

--------Top of Page--------
{element}
------Middle of  Page------
------Bottom of  Page------

top:50%

Als je het met 50% naar beneden verplaatst (50% van de hele pagina), bevindt de bovenkant van het element zich op het 50%-teken, wat betekent dat het element begint bij 50% en niet gecentreerd is.

--------Top of Page--------
------Middle of  Page------
{element}
------Bottom of  Page------

top:50%; transformeren:translateY(-50%);

Als de bovenkant van het element halverwege is, kunnen we het element met de helft van zijn eigen hoogte terug naar boven verplaatsen om het met de hele pagina te centreren. Dat is precies wat transform:translateY(-50%);doet:

--------Top of Page--------
{element}-Middle of Page---
------Bottom of  Page------

Maar waarom kunnen we niet gewoon top: 25%of iets dergelijks zeggen? Ik heb een kort fragment gemaakt om je het verschil met die implementatie te laten zien:

body {
  margin: 0;
}
.row {
  display: flex;
  justify-content: space-between;
}
.container {
  display: inline-block;
  margin: 5px;
  width: 200px;
  height: 200px;
  background: tomato;
}
.inner {
  position: relative;
  margin: 0 auto;
  height: 50%;
  width: 50%;
  background: #FFC4BA;
}
.inner.small {
  width: 25%;
  height: 25%;
}
.inner.big {
  width: 75%;
  height: 75%;
}
.percent {
  top: 25%
}
.transform {
  top: 50%;
  transform: translateY(-50%);
}
<b>First row </b>looks alright, but that's because the gap works well with the 25%
<div class="row">
  <div class="container">
    <div class="inner percent"></div>
  </div>
  <div class="container">
    <div class="inner transform"></div>
  </div>
</div>
<b>Second row </b>made the center square a bit smaller, and the 25% now is too high as we'd expect the bottom of the element to reach 75%
<div class="row">
  <div class="container">
    <div class="small inner percent"></div>
  </div>
  <div class="container">
    <div class="small inner transform"></div>
  </div>
</div>
<b>Third row </b>now I've made the center box big and it ends lower than 75% making 25% start too late
<div class="row">
  <div class="container">
    <div class="big inner percent"></div>
  </div>
  <div class="container">
    <div class="big inner transform"></div>
  </div>
</div>

Snippet uitvouwen


Antwoord 2, autoriteit 45%

Terwijl anderen het antwoord hebben gegeven dat de -50 het binnenste element terug tot de helft van zijn eigen hoogte verplaatst, dacht ik dat deze kleine animatie de beweging naar top: 50%;eerst laat zien, gevolgd door transform: translateY(-50%);ten tweede, zou kunnen helpen.

@keyframes centerMe {
  0% { top: 0%; transform: translateY(0%); }
  50% { top: 50%; transform: translateY(0%); }
  100% { top: 50%; transform: translateY(-50%); }
}
.outer {
  position: relative;
  border: solid 1px;
  height: 200px;
  width: 200px;
}
.inner {
  position: relative;
  background-color: red;
  height: 50px; width: 50px;
  margin: auto;
  animation: centerMe 5s;
  animation-fill-mode: forwards;
}
/* rules for example */
.hline,.vline{background:#000;position:absolute}.vline{height:100%;width:1px;left:calc(50% - .5px);top:0}.hline{width:100%;height:1px;top:calc(50% - .5px)}
<div class="outer">
  <div class="hline"></div>
  <div class="vline"></div>
  <div class="inner"></div>  
</div>

Snippet uitvouwen


Antwoord 3, autoriteit 18%

position: relative;
top: 50%;

… verplaatst het element een afstand die gelijk is aan de helft van de hoogte van het bovenliggende element.

Aangezien de standaardpositie de topvan het binnenste element op de topvan het buitenste element plaatst, plaatst dit de topvan het binnenste element in het middenvan het buitenste element.

transform: translateY(-50%);

Hiermee wordt het binnenste element terug verplaatst over een afstand van de helft van de hoogte van het binnensteelement.

Als je ze combineert, wordt het middenvan het binnenste element in het middenvan het bovenliggende element geplaatst.


Antwoord 4, autoriteit 7%

Waarom heeft de top 50% een vertaalcompensatie van -50% nodig?

In plaats van deze vraag rechtstreeks te beantwoorden, ga ik de meer algemene vraag beantwoorden:

Hoe werkt positieverankering in CSS?

Hopelijk begrijpt u bij het beantwoorden van de vraag in het algemeen de onderdelen die van toepassing zijn op uw specifieke geval.


Wat bedoel je met “positieverankering”?

Positieverankering is wanneer een DOM-knooppunt zo wordt gepositioneerd dat het in een bepaalde dimensie is “verankerd” aan het bovenliggende knooppunt. Als de linkerbovenhoek van het knooppunt is verankerd aan de linkerbovenhoek van het bovenliggende knooppunt, blijven de knooppunten uitgelijnd in hun linkerbovenhoek, ongeacht de grootte van beide elementen.

Hoe ziet positieverankering eruit?

Ik ga een sjabloon gebruiken voor alle verdere voorbeelden, dus het is belangrijk om het basisvoorbeeld te begrijpen.

.container {
  background-image: -webkit-linear-gradient(left, darkred 0, darkred 50%, goldenrod 50%, goldenrod 100%), -webkit-linear-gradient(left, darkgreen 0, darkgreen 50%, darkblue 50%, darkblue 100%);
  background-image: linear-gradient(to right, darkred 0, darkred 50%, goldenrod 50%, goldenrod 100%), linear-gradient(to right, darkgreen 0, darkgreen 50%, darkblue 50%, darkblue 100%);
  background-position: top, bottom;
  background-repeat: no-repeat;
  background-size: 100% 50.1%, 100% 50.1%;
  height: 70vh;
  margin: 15vh 15vw;
  position: relative;
  width: 70vw;
}
.box {
  background-image: -webkit-linear-gradient(left, red 0, red 50%, yellow 50%, yellow 100%), -webkit-linear-gradient(left, green 0, green 50%, blue 50%, blue 100%);
  background-image: linear-gradient(to right, red 0, red 50%, yellow 50%, yellow 100%), linear-gradient(to right, green 0, green 50%, blue 50%, blue 100%);
  background-position: top, bottom;
  background-repeat: no-repeat;
  background-size: 100% 50.1%, 100% 50.1%;
  height: 50vmin;
  position: absolute;
  width: 50vmin;
}
<div class="container">
  <div class="box"></div>
</div>

Other episodes