Divs superpuestos sin posición absoluta

11 minutos de lectura

avatar de usuario
temblores

Lo que sigue es una explicación larga, pero es la única forma de comunicar de manera efectiva el problema que estoy tratando de resolver…

Estoy (algo desesperadamente y sin éxito) tratando de superponer divs sin el uso de posicionamiento absoluto. La necesidad surge de un carrito de paypal que coloco en el sitio a través de un Javascript. La posición natural del carro es fuerte contra el margen superior de la página web (no su div contenedor, que es #wpPayPalo el envoltorio para este div, #principal).

El autor del script recomienda encarecidamente no personalizar la hoja de estilo del carrito, pero encontré un tutorial que escribió que permite insertar el carrito en un div de marcador de posición, con instrucciones de posicionamiento para el contenedor que funciona. Pude colocar el carrito debajo del banner superior del sitio. sección. Sin embargo…

El formulario HTML del carrito y un elemento ul dentro de cada uno tienen requisitos de altura en la hoja de estilo del carrito, y esto empuja el contenido principal de la página, envuelto por el contenedor div #ImagenEnvolturademasiado abajo en la página para ser aceptable.

Traté de colocar #imageWrapper sobre #main con varias ideas recopiladas de publicaciones en este sitio sin éxito. Probé el posicionamiento absoluto en #imageWrapper, pero esto libera el pie de página para que flote debajo. La altura de #imageWrapper es variable, por lo tanto, no quiero mantener el pie de página en su lugar con altura, ya que la altura mínima para evitar la superposición empujaría el pie de página demasiado hacia abajo para gran parte del contenido del sitio.

También intenté extraer position:relative del CSS del formulario del carrito, pero el carrito inmediatamente vuelve a la parte superior de la página web. Margen, margen superior, etc., no solucione esto.

Luego leí un artículo sobre el uso de position:relative y z-index para superponer divs. También intenté esto, primero poniendo z-index: -1 en #main (el div que envuelve el carrito de paypal), pero el carrito desaparece. Tampoco estoy seguro de adónde va, ya que la navegación de migas de pan del sitio, también envuelta por #main, se mantuvo.

Luego establecí el índice z para principal en 0 y apliqué position:relative to #imageWrapper con z-index:100. El carrito reapareció, pero aún mantiene presionado #imageWrapper.

Las sugerencias son muy bien recibidas. No soy una persona de interfaz por ningún tramo de la imaginación, solo un tipo que sabe cómo usar Google, así que gracias de antemano por articular claramente su resolución 🙂 Además, FYI, actualmente tengo el requisito de altura mínima para el carro form establecido en 0, y establezca el elemento UL dentro de height:auto. Con solo un artículo en el carrito, esto permite que #imageWrapper suba la página lo suficiente como para ser aceptable, pero esta no es una solución viable a largo plazo.

Aquí hay un página de ejemplo – para ver el carrito, agregue un artículo usando el menú desplegable que aparece debajo de la imagen principal. En su estado expandido, verá cómo #imageWrapper se asienta contra él.

He incluido partes del código HTML/CSS ofensivo a continuación:

<div id="main">
    <div id="wpPayPal">
    </div><!--end wpPayPal-->
    <div id="breadcrumbs">
        <span class="B_crumbBox"><span class="B_firstCrumb"><a class="B_homeCrumb" href="https://stackoverflow.com/">home</a></span> &raquo;</span></span>
    </div> <!--end breadcrumbs -->
</div><!-- end Main -->

<div id="imageWrapper">
    <div id="imageInnerWrapper">
        <div id="featureImage">
            <div class="filename"><h1>~&nbsp;Bryce Canyon Sunrise | Bryce Canyon | Utah&nbsp;~</h1>
            </div><!--end filename-->

etc…

#main {
    display: inline;
    position: relative;
    z-index: 0;
}

#imageWrapper {
    clear: both;
    width: 840px;
    margin: 0 auto;
    padding: 0;
    position: relative;
    z-index: 100;
}

#imageInnerWrapper {
    width: 840px;
    margin: 0 auto;
    padding: 0;
    position: relative;
    z-index: 100;
}

#featureImage {
    width: 840px;
    margin: 0 auto;
    padding: 0;  
}

#wpPayPal {
    overflow: hidden;
    float: right;
    margin-right: 100px;
    min-width: 365px;
    min-height: 20px;
}

/* Override the default Mini Cart styles */

#wpBody #PPMiniCart form {
    position: relative;
    right: auto;
    width: auto;
    min-height: 0;
}

#wpBody #PPMiniCart form ul {
    height: auto;
}

avatar de usuario
patelarpan

Ahora puedes hacer esto con grid también.

.parent {
  display: grid;
  grid-template-columns: 1fr;
}

.parent div {
 padding: 50px;
 background-color: rgba(0,0,0,0.5);
 grid-row-start: 1;
 grid-column-start: 1;
}
<div class="parent">
  <div class="child1">
  1
  </div>
  <div class="child2">
  2
  </div>
</div>

  • Corto, simple, funciona perfectamente. Uso la cuadrícula CSS a menudo, pero no conocía este truco. Gracias por compartir !

    – Cestyves

    17 de febrero de 2020 a las 16:03

  • ¡estupendo! funciona perfectamente para construir un control deslizante en línea con tamaños de imagen desconocidos y fusionarlos (estoy construyendo un componente Vue). Usando absolute para que los imgs los tengan uno sobre el otro y animen la opacidad, pierdes su ancho y el texto circundante se vuelve loco. ¡Gracias!

    – Iván Ferrer Villa

    30 de julio de 2021 a las 13:59

  • Bienvenido @IvanFerrerVilla

    – patelarpan

    1 de agosto de 2021 a las 6:35

avatar de usuario
Finura

El fondo div para un bloque con una altura dinámica se puede implementar usando flexbox sin un posicionamiento absoluto:

/* Every rule not marked by "required" is optional and used only to decorate the example */
.block {
    margin: 10px 50px;
    display: flex; /* required */
    flex-flow: row nowrap; /* required */
}
.block .background,
.block .foreground {
    box-sizing: border-box; /* required */
    width: 100%; /* required */
    flex: none; /* required */
}
.block .background {
    background: #9ff;
    color: #fff;
    padding: 15px;
    font-size: 30px;
}
.block .foreground {
    padding: 15px;
    border: solid 1px;
    margin-left: -100%; /* required */
}
.block .foreground .outside {
    position: absolute;
    top: 5px;
    left: 8px;
}
<div class="block">
    <div class="background">
        Background
    </div>
    <div class="foreground">
        <div>
            <div class="outside">Outside</div> <!-- The "outside" div is also optional -->
            <div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Odio incidunt perspiciatis sapiente aspernatur repellat delectus atque quae optio nam? Pariatur explicabo laboriosam dolores temporibus molestiae error ipsa sunt molestias doloremque odio nemo iure similique quae exercitationem, adipisci, ullam dicta esse numquam beatae qui velit asperiores. Dolore, quo illum necessitatibus tempora earum nihil cumque corporis aut error eius voluptatibus quia, pariatur.</div>
        </div>
    </div>
</div>

La solución está respaldada por alrededor del 99% de los navegadores.

  • Increíble, esta es definitivamente la respuesta más elegante en este momento.

    – TSga

    14/03/2018 a las 19:31

  • @TSga Gracias ⁢ ⁢⁢⁢⁢⁢⁢

    – Delicadeza

    15 de marzo de 2018 a las 2:08

  • Sé que no debería comentar aquí, ¡pero esto es genial! Muy útil para mí para superponer parcialmente un modal lateral en una mesa.

    – M3RS

    8 sep 2019 a las 10:01

  • ¿Hay alguna forma de hacer que este contenido de primer plano “flote” a la derecha del fondo sin importar su tamaño?

    –Leonardo Rick

    5 oct 2020 a las 23:12

  • @LeonardoRick, no estoy seguro de haberte entendido correctamente. Si desea que el primer plano tome solo la parte derecha del espacio (no todo el fondo), puede agregar padding-left: 50%; hacia .foreground CSS. Tenga en cuenta que puede hacer cualquier diseño dentro .foregroundtambién puede configurar el display Propiedad CSS de .foreground a flex, grid, block o lo que sea.

    – Delicadeza

    6 de octubre de 2020 a las 0:31


avatar de usuario
kay valle ganev

Violín simple: solo CSS

Un tipo publicó otro, pero tenía un montón de código adicional innecesario y algo de JS. Otra publicación tenía la respuesta, pero faltaba algo.

.over {
  background: rgba(230, 6, 6, .5);
  float: right;
  height: 460px;
  margin-top: -500px;
  margin-right: 159px;
  overflow: visible;
  position: relative;
  width: 560px;
  color: #FFFFFF;
  /* Just for looks*/
  z-index: 1000;
  padding: 20px/* Just for looks*/
}

.over span {
  position: relative;
  /* Just for looks*/
  top: 15px;
  /* Just for looks*/
}

.this {
  width: 560px;
  height: 460px;
  color: #FFFFFF;
  /* Just for looks*/
  padding: 20px;
  /* Just for looks*/
  background-image: url("http://www.tshirtvortex.net/wp-content/uploads/dramaticchipmunk.jpg");
  /* Just for looks*/
}
<div class="this">To BE UNDER</div>
<div class="over"><span>..or not To BE UNDER</span></div>

http://jsfiddle.net/3WDf7/

  • Esa elección de imagen en realidad me hizo reír a carcajadas en mi escritorio. Gracias.

    – Urbycoz

    24 de marzo de 2015 a las 10:16

  • ¡Gracias por esto! Definitivamente salvó mi día 🙂

    – Antonio Ribeiro

    12 de febrero de 2016 a las 15:39

  • Esto resuelve mi problema con la altura del contenedor principal, pero el margen superior negativo para el div de superposición provoca un problema de respuesta al escalar, ya que el margen superior es un valor de píxel fijo.

    – Nick W.

    2 de mayo de 2019 a las 12:57

¡¡¡Entiendo!!! 😀

Solución pura de Css muy fácil. Poner el seguimiento.

#main {
float: right;
overflow: visible;
position: relative;
z-index: 1000;
height: 177px;
width: 100%;
}

Reemplazar lo que tengas en css #main con que he hecho arriba.

Asi que retirar el seguimiento:

display: inline;
position: relative;
z-index: 0;

Explicación:
La idea principal aquí es hacer flotar el elemento principal, hacerlo de cierta altura así que en ningún momento empuja todo hacia abajo. pero hazlo desbordamiento de lo visible. El desbordamiento de contenido no afecta hermanos de elemento principal.

avatar de usuario
Antonio Accioly

Ninguna de las respuestas anteriores realmente ayuda con su requisito, que es permitir PPMiniCart expandirse y contraerse sin empujar imageWrapper abajo.

El truco aquí es dar wpPayPal una altura fija lo suficientemente grande como para contener la versión contraída de PPMiniCart (40px servirá – esto le dará suficiente espacio al carrito de compras, sin empujar imageWrapper muy abajo).

#wpPayPal {
    height:40px;
}

Entonces da main (el recipiente que contiene wpPayPal) a z-index mayor que la de imageWrapper para que se desborde sobre él.

#main {
    z-index: 1;
}
#imageWrapper {
    z-index: 0;
}

Ajuste imageWrapper z-index a 100 es un poco exagerado, recomendaría 0 como lo hice anteriormente.

También necesita algo de JavasScript para configurar overflow: visible en wpPayPal después PPMiniCart se expande y eliminarlo antes de que se contraiga. Afortunadamente Minicarrito JS expone una buena API impulsada por eventos que permite devoluciones de llamadas personalizadas. Ya que está utilizando jQuery en su página web, aprovechemos eso:

PAYPAL.apps.MiniCart.render({
    parent: 'wpPayPal',
    events: {
        afterShow: function () {
            $("#wpPayPal").css("overflow", "visible");
        },
        onHide: function () {
            $("#wpPayPal").css("overflow", "");
        }
    }
});

Tenga en cuenta la cuidadosa elección de afterShow y onHide devoluciones de llamada, si intenta hacerlo de otra manera (configurando overflow: visible antes de PPMiniCart se expande o quitarlo antes PPMiniCart contratos) PPMiniCart “flotará” durante la transición.


Finalmente, un violín de trabajo vale más que mil palabras.

avatar de usuario
Daniel Swakman

Descubrí una solución elegante para su problema sin posicionamiento absoluto O flotadores usando flexbox; la principal ventaja es que ambas alturas de div se respetan al calcular la altura de los padres. Muy útil para superponer texto en una imagen:

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

.container {
  max-width: 500px;
  /*border: 1px solid lime;*/
}

.card {
  display: flex;
  /*border: 1px solid red;*/
  overflow: hidden;
}

.box {
  position: relative;
  min-width: 100%;
  width: 100%;
  flex-basis: 100%;
  flex-grow: 1;
}

.box--image {
  z-index: 1;
  overflow: hidden;
}

.box--image.box--heightrestricted {
  max-height: 300px;
}

.box--text {
  z-index: 2;
  margin-left: -100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  color: red;
}

.box--text h3 {
  margin: 0;
  padding: 1rem;
}
<div class="container">

  <button onclick="document.getElementById('imagebox').classList.toggle('box--heightrestricted')">toggle image max-height</button>
  <br>
  <br>

  <div class="card">

    <div id="imagebox" class="box box--image box--heightrestricted">
      <img src="https://placeimg.com/640/640/4" alt="" />
    </div>

    <div class="box box--text">
      <h3>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris in urna porta, maximus velit vitae, suscipit eros. Praesent eleifend est at nisi laoreet auctor. Nunc molestie fringilla magna et dictum. Nam ac massa nec erat consequat lacinia in in leo. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas sollicitudin nibh nisl, sed molestie lorem lobortis in. Nulla eget purus a risus scelerisque cursus. Praesent nisl dolor, varius eget faucibus sit amet, rutrum non lorem. Ut elementum sapien sed facilisis tempus. Morbi nec ipsum sed lacus vulputate sodales quis ut velit. Quisque id ante quis leo pharetra efficitur nec at mauris. Praesent dignissim hendrerit posuere. Vestibulum venenatis urna faucibus facilisis sodales. Suspendisse potenti. Proin a magna elit. Aenean vitae aliquam est, quis fringilla lectus.</h3>
    </div>

  </div>

</div>

avatar de usuario
NDS

También puede usar flexbox para hacer un contenedor de pestañas sin una posición absoluta:

/* Flex Overflow */
section {
  display: flex;
  width: 100%;
  overflow: hidden;
}

section article {
  flex: 100% 0 0;
  order: 0;
}

section article:target {
  order: -1;
}

/* UI */
section { background-color: #ecf0f1; }
section article { 
  display: flex;
  align-items: center;
  justify-content: center;
  color: #ecf0f1;
  font-size: 20px;
  min-height: 8em;
  visibility: hidden;
  opacity: 0;
  transition: visibility .5s ease, opacity .5s ease;
}
section article:first-child,
section article:target {
  visibility: visible;
  opacity: 1;
}
section article#zoneA { background-color: #2980b9; }
section article#zoneB { background-color: #16a085; }
section article#zoneC { background-color: #f39c12; }
section article#zoneD { background-color: #8e44ad; }
<ul>
  <li><a href="#zoneA">Zone A</a></li>
  <li><a href="#zoneB">Zone B</a></li>
  <li><a href="#zoneC">Zone C</a></li>
  <li><a href="#zoneD">Zone D</a></li>
</ul>

<section>
  <article id="zoneA">A</article>
  <article id="zoneB">B</article>
  <article id="zoneC">C</article>
  <article id="zoneD">D</article>
</section>

¿Ha sido útil esta solución?