web-dev-qa-db-fra.com

Transitions CSS mélangeant positionnement absolu et relatif

Version courte et douce:

Est-il possible de combiner position: relative et position: absolute avec des transitions CSS fluides?

Version détaillée:

Je crée un petit widget (je l'appelle un Deck), que je ne pourrai pas avoir un état réduit et étendu. Très bien jusqu'à présent, cela fonctionne bien.

La commutation entre les deux états justifie naturellement une animation de transition. Cela fonctionne aussi, mais pas de la façon dont j'aimerais que cela se réalise. Ce que je voudrais faire, c'est utiliser la transition CSS, au lieu d'utiliser le positionnement absolu en utilisant JavaScript, comme je le suis maintenant.

Hélas, le scénario actuel est que, dans un état étendu, les cartes du deck sont toujours positionnées de manière absolue, leur position étant calculée à la volée au fur et à mesure de leur ajout au deck. Lors de l'effondrement, les quatre premiers sont empilés en cascade et le reste au-dessus de la quatrième carte. Imitant visuellement une pile.

Le problème avec cette approche est que je ne peux pas compter sur un flux de mise en page normal pour positionner les cartes, ce qui craint pour de nombreuses raisons. Si j'utilise position: relative pour les cartes à l'état étendu, elles coulent bien l'une après l'autre. Mais la transition vers l'état effondré n'est pas animée - il suffit de basculer d'une position à l'autre en un instant. Ceci est bien sûr logique car sans positionnement absolu en premier lieu, le navigateur ne sait clairement pas d'où passer.

Ce que j'ai jusqu'à présent, c'est ceci ( Fiddle ):

CSS (règles pertinentes uniquement):

div.deck-container {
    position: relative;
}
div.deck-container li {
    display: inline-block;
    position: relative;

    -webkit-transition: all 0.5s ease-in-out;
    -moz-transition: all 0.5s ease-in-out;
    -o-transition: all 0.5s ease-in-out;
    -ms-transition: all 0.5s ease-in-out;
    transition: all 0.5s ease-in-out;
}
div.deck-container.collapsed li {
    position: absolute;
    left: 9px;
    top: 6px;
}
div.deck-container.collapsed li:first-child {
    left: 0;
    top: 0px;
}
div.deck-container.collapsed li:nth-child(2) {
    left: 3px;
    top: 2px;
}
div.deck-container.collapsed li:nth-child(3) {
    left: 6px;
    top: 4px;
}

HTML (balisage pertinent uniquement):

<div class="deck-container">
    <ul>
        <li>Card 1</li>
        <li>Card 2</li>
        <li>Card 3</li>
        <li>Card 4</li>
        <li>Card 5</li>
    </ul>
</div>

Dans mon monde parfait, ajouter la classe collapsed à div.deck-container animerait les cartes dans leurs positions réduites et vice versa, mais il semble que ce ne soit pas possible. S'il vous plaît, quelqu'un me dit que je me trompe.

27
nikc.org

Non, vous ne pouvez pas animer la propriété position. Il n'y a qu'un certain nombre de propriétés css que vous pouvez animer, et la plupart d'entre elles ont des nombres ou des couleurs comme valeurs (à quelques exceptions près). Vous pouvez voir cette liste dans w3c css transitions especification .

Quoi qu'il en soit, puisque vous pouvez animer les propriétés top et left, vous pouvez modifier légèrement votre balisage pour obtenir l'effet, comme dans ce violon .

div.deck-container {
    position: relative;
}
div.deck-container li {
    background-color: #fff;
    position: absolute;
    border: 1px solid black;
    padding: 3px;
    display: inline-block;
    -webkit-transition: all 0.5s ease-in-out;
    -moz-transition: all 0.5s ease-in-out;
    -o-transition: all 0.5s ease-in-out;
    -ms-transition: all 0.5s ease-in-out;
    transition: all 0.5s ease-in-out;
}
div.deck-container li {
    left: 160px;
    top: 0px;
}
div.deck-container li:first-child {
    left: 0px;
    top: 0px;
}
div.deck-container li:nth-child(2) {
    left: 40px;
    top: 0px;
}
div.deck-container li:nth-child(3) {
    left: 80px;
    top: 0px;
}
div.deck-container li:nth-child(4) {
    left: 120px;
    top: 0px;
}
div.deck-container.collapsed li {
    left: 12px;
    top: 8px;
}
div.deck-container.collapsed li:first-child {
    left: 0;
    top: 0px;
}
div.deck-container.collapsed li:nth-child(2) {
    left: 3px;
    top: 2px;
}
div.deck-container.collapsed li:nth-child(3) {
    left: 6px;
    top: 4px;
}
div.deck-container.collapsed li:nth-child(4) {
    left: 9px;
    top: 6px;
}

Je viens de définir la position d'origine en absolu et de positionner ces éléments. Ensuite, lors du basculement de la classe, seuls les attributs topet left changent, de sorte que la transition fonctionne.

40
scumah

@ nikc.org Vous pourriez peut-être utiliser translate à la place:

    div.deck-container {
        position: relative;
    }
    div.deck-container li {
        background-color: #fff;
        position: relative;
        border: 1px solid black;
        padding: 3px;
        display: inline-block;
        -webkit-transition: all 0.5s ease-in-out;
        -moz-transition: all 0.5s ease-in-out;
        -o-transition: all 0.5s ease-in-out;
        -ms-transition: all 0.5s ease-in-out;
        transition: all 0.5s ease-in-out;
    }

    div.deck-container.collapsed li:first-child {
      -webkit-transform: translate(0, 0);
         -moz-transform: translate(0, 0);
          -ms-transform: translate(0, 0);
           -o-transform: translate(0, 0);
              transform: translate(0, 0);
    }
    div.deck-container.collapsed li:nth-child(2) {
        -webkit-transform: translate(-100%, 2px);
         -moz-transform: translate(-100%, 2px);
          -ms-transform: translate(-100%, 2px);
           -o-transform: translate(-100%, 2px);
              transform: translate(-100%, 2px);
    }
    div.deck-container.collapsed li:nth-child(3) {
        -webkit-transform: translate(-200%, 4px);
         -moz-transform: translate(-200%, 4px);
          -ms-transform: translate(-200%, 4px);
           -o-transform: translate(-200%, 4px);
              transform: translate(-200%, 4px);
    }

exemple de travail

15
nd_macias