Faire div div positionné absolu étendre la hauteur div div

204

Comme vous pouvez le voir dans le CSS ci-dessous, je veux me child2positionner avant child1. En effet, le site que je suis en train de développer devrait également fonctionner sur des appareils mobiles, sur lesquels il child2devrait être en bas, car il contient la navigation que je souhaite en dessous du contenu sur les appareils mobiles. - Pourquoi pas 2 pages maîtres? Ce sont les 2 seuls divsqui sont repositionnés dans tout le code HTML, donc 2 pages maîtres pour ce changement mineur sont une exagération.

HTML:

<div id="parent">
    <div class="child1"></div>
    <div class="child2"></div>
</div>

CSS:

parent { position: relative; width: 100%; }
child1 { width: auto; margin-left: 160px; }
child2 { width: 145px; position: absolute; top: 0px; bottom: 0px; }

child2 a une hauteur dynamique, car différents sous-sites peuvent avoir plus ou moins d'éléments de navigation.

Je sais que les éléments positionnés absolus sont supprimés du flux, donc ignorés par les autres éléments.
J'ai essayé de régler overflow:hidden;le div parent, mais cela n'a pas aidé, ni le clearfix.

Mon dernier recours sera JavaScript pour repositionner les deux en divsconséquence, mais pour l'instant je vais essayer de voir s'il existe une façon non JavaScript de le faire.

Micha Wiedenmann
la source
3
Je ne suis pas sûr à 100% mais je pense que vous devrez probablement opter pour une solution JS qui calcule la taille de child2 et déplace child1 en conséquence.
Billy Moat
2
Cela peut être fait en définissant la position du parent sur relative et l'enfant sur absolu.
fungusanthrax
1
Consultez cette solution de contournement, cela peut peut-être vous aider.
Az.Youness

Réponses:

153

Vous avez répondu vous-même à la question: "Je sais que les éléments positionnés en absolu sont supprimés du flux, donc ignorés par les autres éléments". Vous ne pouvez donc pas définir la hauteur des parents en fonction d'un élément absolument positionné.

Vous utilisez des hauteurs fixes ou vous devez impliquer JS.

feeela
la source
1
Je marque cela car c'est techniquement la bonne façon, bien que j'ai trouvé une autre solution à mon problème, qui consiste pratiquement à imbriquer le CSS requis sur les pages spécifiques qui doivent se différencier (2 sur 40 pour le moment).
16

Bien que l'étirement aux éléments position: absolutene soit pas possible, il existe souvent des solutions où vous pouvez éviter le positionnement absolu tout en obtenant le même effet. Regardez ce violon qui résout le problème dans votre cas particulier http://jsfiddle.net/gS9q7/

L'astuce consiste à inverser l'ordre des éléments en faisant flotter les deux éléments, le premier à droite, le second à gauche, de sorte que le second apparaît en premier.

.child1 {
    width: calc(100% - 160px);
    float: right;
}
.child2 {
    width: 145px;
    float: left;
}

Enfin, ajoutez un clearfix au parent et vous avez terminé (voir le violon pour la solution complète).

En règle générale, tant que l'élément avec la position absolue est positionné en haut de l'élément parent, il est probable que vous trouviez une solution de contournement en flottant l'élément.

lex82
la source
10

Feeela a raison, mais vous pouvez obtenir un parent qui sedivcontracte / se développe en un élément enfant si vous inversez votredivpositionnement comme ceci:

.parent{
    postion: absolute;
    /* position it in the browser using the `left`, `top` and `margin` 
       attributes */
}

.child{
    position: relative;
    height: 100%;
    width: 100%;

    overflow: hidden;
    /* to pad or move it around using `left` and `top` inside the parent */
}

Cela devrait fonctionner pour vous.

ChrisC
la source
9

Il existe un moyen assez simple de résoudre ce problème.

Il vous suffit de dupliquer le contenu de child1 et child2 dans les divs relatifs avec display: aucun dans le parent div. Dites enfant1_1 et enfant2_2. Mettez child2_2 en haut et child1_1 en bas.

Lorsque votre requête (ou autre) appelle le div absolu, il suffit de définir le div relatif correspondant (child1_1 ou child2_2) avec display: block ET visibilité: caché. L'enfant relatif sera toujours invisible mais augmentera le div des parents.

MMB
la source
2
Cela m'a fait réfléchir dans la bonne direction. Dans mon cas, affichage de la configuration: aucun sur le contenu du "support de taille" ne fait que la taille du div, cependant l'opacité: 0, dimensionne le div correctement et ne nécessite pas de requête supplémentaire.
edencorbin
La façon dont j'ai fait était d'obtenir deux divs en double, le premier est le contenu visible avec la position absolue et le second est un div avec une visibilité cachée qui garde le parent div à la bonne hauteur tout fonctionne bien = D
Diogo Garcia
4

Avec du JavaScript pur, il vous suffit de récupérer la hauteur de votre static positionélément enfant .child1à l'aide de la méthode getComputedStyle () , puis de définir cette valeur de récupération comme padding-topcelle du même enfant à l'aide de la propriété HTMLElement.style .


Vérifiez et exécutez l' extrait de code suivant pour un exemple pratique de ce que j'ai décrit ci-dessus:

/* JavaScript */

var child1 = document.querySelector(".child1");
var parent = document.getElementById("parent");

var childHeight = parseInt(window.getComputedStyle(child1).height) + "px";
child1.style.paddingTop = childHeight;
/* CSS */

#parent { position: relative; width: 100%; }
.child1 { width: auto; }
.child2 { width: 145px; position: absolute; top: 0px; bottom: 0px; }
html, body { width: 100%;height: 100%; margin: 0; padding: 0; }
<!-- HTML -->

<div id="parent">
    <div class="child1">STATIC</div>
    <div class="child2">ABSOLUTE</div>
</div>

AndrewL64
la source
3

Cette question a été posée en 2012 avant flexbox. La bonne façon de résoudre ce problème en utilisant le CSS moderne est avec une requête multimédia et une inversion de colonne flexible pour les appareils mobiles. Aucun positionnement absolu n'est nécessaire.

https://jsfiddle.net/tnhsaesop/vjftq198/3/

HTML:

<div class="parent">
  <div style="background-color:lightgrey;">
    <p>
      I stay on top on desktop and I'm on bottom on mobile
    </p>
  </div>
  <div style="background-color:grey;">
    <p>
      I stay on bottom on desktop and I'm on bottom on mobile
    </p>
  </div>
</div>

CSS:

.parent {
  display: flex;
  flex-direction: column;
}

@media (max-width: 768px) {
  .parent {
    flex-direction: column-reverse;
  }
}
Hunter Nelson
la source
2

J'avais un problème similaire. Pour résoudre ce problème (au lieu de calculer la hauteur de l'iframe à l'aide du corps, du document ou de la fenêtre), j'ai créé un div qui enveloppe tout le contenu de la page (un div avec un id = "page" par exemple) puis j'ai utilisé sa hauteur.

Juliano
la source
1

J'ai trouvé une autre solution, que je n'aime pas mais qui fait le travail.

Dupliquez essentiellement les éléments enfants de manière à ce que les doublons ne soient pas visibles.

<div id="parent">
    <div class="width-calc">
        <div class="child1"></div>
        <div class="child2"></div>
    </div>

    <div class="child1"></div>
    <div class="child2"></div>
</div>

CSS:

.width-calc {
    height: 0;
    overflow: hidden;
}

Si ces éléments enfants contiennent peu de balisage, l'impact sera faible.

btx9000
la source
4
Cela peut poser quelques problèmes avec le classement des moteurs de recherche
mschadegg
1

"Vous utilisez des hauteurs fixes ou vous devez impliquer JS."

Voici l'exemple JS:

---------- Exemple jQuery JS --------------------

    function findEnvelopSizeOfAbsolutelyPositionedChildren(containerSelector){
        var maxX = $(containerSelector).width(), maxY = $(containerSelector).height();

        $(containerSelector).children().each(function (i){
            if (maxX < parseInt($(this).css('left')) + $(this).width()){
                maxX = parseInt($(this).css('left')) + $(this).width();
            }
            if (maxY < parseInt($(this).css('top')) + $(this).height()){
                maxY = parseInt($(this).css('top')) + $(this).height();
            }
        });
        return {
            'width': maxX,
            'height': maxY
        }
    }

    var specBodySize = findEnvelopSizeOfAbsolutelyPositionedSubDivs("#SpecBody");
    $("#SpecBody").width(specBodySize.width);
    $("#SpecBody").height(specBodySize.height);
Nikolay
la source
Cette réponse pourrait bénéficier d'une meilleure explication et orientation de la solution proposée.
DaniDev
1

Il y a un hack très simple qui résout ce problème

Voici un codeandbox qui illustre la solution: https://codesandbox.io/s/00w06z1n5l

HTML

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

CSS

.parent { position: relative; width: 100%; }
.hack { position: absolute; left:0; right:0; top:0;}
.child { position: absolute; left: 0; right: 0; bottom:0; }

vous pouvez jouer avec le positionnement du div hack pour affecter la position de l'enfant.

Voici un extrait:

html {
  font-family: sans-serif;
  text-align: center;
}

.container {
  border: 2px solid gray;
  height: 400px;
  display: flex;
  flex-direction: column;
}

.stuff-the-middle {
  background: papayawhip
    url("https://camo.githubusercontent.com/6609e7239d46222bbcbd846155351a8ce06eb11f/687474703a2f2f692e696d6775722e636f6d2f4e577a764a6d6d2e706e67");
  flex: 1;
}

.parent {
  background: palevioletred;
  position: relative;
}

.hack {
  position: absolute;
  left: 0;
  top:0;
  right: 0;
}
.child {
  height: 40px;
  background: rgba(0, 0, 0, 0.5);
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
}
    <div class="container">
      <div class="stuff-the-middle">
        I have stuff annoyingly in th emiddle
      </div>
      <div class="parent">
        <div class="hack">
          <div class="child">
            I'm inside of my parent but absolutely on top
          </div>
        </div>
        I'm the parent
        <br /> You can modify my height
        <br /> and my child is always on top
        <br /> absolutely on top
        <br /> try removing this text
      </div>
    </div>

Bernatfortet
la source
0

Il existe maintenant une meilleure façon de procéder. Vous pouvez utiliser la propriété bottom.

    .my-element {
      position: absolute;
      bottom: 30px;
    }
rlasch
la source
5
cela ne fonctionnera que si vous connaissez la hauteur finale du parent, ce que vous ne
connaissez
0

C'est très similaire à ce que @ChrisC a suggéré. Il n'utilise pas un élément positionné absolu, mais un élément relatif. Peut-être pourrait travailler pour vous

<div class="container">
  <div class="my-child"></div>
</div>

Et votre css comme ça:

.container{
    background-color: red;
    position: relative;
    border: 1px solid black;
    width: 100%;
}

.my-child{
    position: relative;
    top: 0;
    left: 100%;
    height: 100px;
    width: 100px;
    margin-left: -100px;
    background-color: blue;
}

https://jsfiddle.net/royriojas/dndjwa6t/

roy riojas
la source
0

Pensez également à la prochaine approche:

CSS:

.parent {
  height: 100%;
}
.parent:after {
  content: '';
  display: block;
}

Aussi, puisque vous essayez de repositionner les divs, considérez la grille CSS

Iegor Benzyk
la source
-2

Les vues absolues se positionnent par rapport à l'ancêtre le plus proche qui n'est pas positionné statiquement ( position: static), donc si vous voulez une vue absolue positionnée par rapport à un parent donné, définissez le parent positionsur relativeet l'enfant positionsurabsolute

Isaac Sekamatte
la source
-4

Essayez ça, ça a fonctionné pour moi

.child {
    width: 100%;
    position: absolute;
    top: 0px;
    bottom: 0px;
    z-index: 1;
}

Il définira la hauteur de l'enfant sur la hauteur du parent

Sarath E
la source
bonne solution!
Alexander Cherednichenko
3
@AlexanderCherednichenko Pas vraiment, il manque le point de la question.
wickywills