¿Cómo establecer el margen o el relleno como porcentaje de la altura del contenedor principal?

236

Me había estado estrujando el cerebro creando una alineación vertical en CSS usando lo siguiente

.base{
        background-color:green;
	    width:200px;
	    height:200px;
	    overflow:auto;
	    position:relative;
	}

    .vert-align{
		padding-top:50%;
		height:50%;
	}
<!-- and used the following div structure. -->

    <div class="base">
       <div class="vert-align">
    	   Content Here
       </div>
    </div>

Si bien esto parecía funcionar para este caso, me sorprendió que cuando aumentaba o disminuía el ancho de mi div base, la alineación vertical se rompería. Esperaba que cuando estableciera la propiedad padding-top, tomaría el relleno como un porcentaje de la altura del contenedor principal, que es la base en nuestro caso, pero el valor anterior del 50 por ciento se calcula como un porcentaje del anchura. :(

¿Hay alguna manera de establecer el relleno y / o el margen como un porcentaje de la altura, sin recurrir al uso de JavaScript?

Ryan
fuente

Respuestas:

223

La solución es que sí, el relleno vertical y margen son en relación con la anchura, pero topy bottom no lo son.

Así que solo coloque un div dentro de otro, y en el div interno, use algo como top:50%(recuerde positionsi todavía no funciona)

Camilo Martin
fuente
3
topfunciona muy bien para cambiar el tamaño según la altura del navegador / ventana. ¿Qué tal tener un div debajo de ese div? ¿Cómo puede clearel segundo div estar debajo del div que se desplaza hacia abajo por un top:50%??
Federico
Aprende algo nuevo. No sabía que el relleno vertical y el margen son relativos al ancho antes. Gracias.
shaosh
55
También es posible agregar un div 'espaciador' con un porcentaje de altura establecido. Parece un poco sucio pero funciona. ver esta respuesta .
WCByrne
44
¿Qué es el everliving @%! ^? ¿Por qué el margen vertical y el relleno son relativos al ancho ? ¿QUÉ? ¿Por qué demonios se tomó esa decisión?
temporary_user_name
Su respuesta es extremadamente desproporcionadamente votada en comparación con la respuesta de alain a continuación, que ofrece una solución general, y la encontré muy útil y casi no la vi. top: 50%no es muy útil si necesita alinear los contenidos por su propio centro.
okovko
35

Una respuesta a una pregunta ligeramente diferente: puede usar vhunidades para rellenar elementos en el centro de la ventana gráfica :

.centerme {
    margin-top: 50vh;
    background: red;
}

<div class="centerme">middle</div>
Willoller
fuente
¿Por qué esta respuesta no se votó más alto? ¿Hay algo malo con el uso de vh?
AlanH
3
Es porque no es una respuesta que se adapte a la pregunta original, es un truco útil que funciona solo en algunos casos relacionados.
willoller
usar vhes casi lo mismo que los porcentajes ... incluso peor en algunos casos. Esta respuesta es irrelevante para la pregunta
vsync
33

Aquí hay dos opciones para emular el comportamiento necesario. No es una solución general, pero puede ayudar en algunos casos. El espacio vertical aquí se calcula sobre la base del tamaño del elemento externo, no de su elemento primario, pero este tamaño en sí mismo puede ser relativo al elemento primario y de esta manera el espacio también será relativo.

<div id="outer">
    <div id="inner">
        content
    </div>
</div>

Primera opción: usar pseudoelementos, aquí el espaciado vertical y horizontal es relativo al exterior. Manifestación

#outer::before, #outer::after {
    display: block;
    content: "";
    height: 10%;
}
#inner {
    height: 80%;
    margin-left: 10%;
    margin-right: 10%;
}

Mover el espacio horizontal al elemento externo lo hace relativo al padre del exterior. Manifestación

#outer {
    padding-left: 10%;
    padding-right: 10%;
}

Segunda opción: usar posicionamiento absoluto. Manifestación

#outer {
    position: relative;
}
#inner {
    position: absolute;
    left: 10%;
    right: 10%;
    top: 10%;
    bottom: 10%;
}
usuario
fuente
10

Para hacer que el elemento secundario se posicione absolutamente desde su elemento primario, debe establecer la posición relativa en el elemento primario Y la posición absoluta en el elemento secundario.

Luego, en el elemento hijo, 'top' es relativo a la altura del padre. Por lo tanto, también debe 'traducir' hacia arriba al niño el 50% de su altura.

.base{
    background-color: green;
    width: 200px;
    height: 200px;
    overflow: auto;
    position: relative;
}
    
.vert-align {
    position: absolute;
    top: 50%;
    transform: translate(0, -50%);
}
    <div class="base">
        <div class="vert-align">
            Content Here
        </div>
    </div>

Hay otra solución usando flex box.

.base{
    background-color:green;
    width: 200px;
    height: 200px;
    overflow: auto;
    display: flex;
    align-items: center;
}
<div class="base">
    <div class="vert-align">
        Content Here
    </div>
</div>

Encontrará ventajas / desventajas para ambos.

alain
fuente
1
El uso de la traducción es la única forma real de mover un elemento verticalmente en relación con su propio tamaño.
Eran Goldin
Gracias por esto. Esta debería ser la respuesta elegida.
Wessam El Mahdy
6

Esto se puede lograr con la writing-modepropiedad. Si configura un elemento writing-modeen un modo de escritura vertical, como vertical-lrlos valores porcentuales de sus descendientes para el relleno y el margen, en ambas dimensiones, se vuelven relativos a la altura en lugar del ancho.

De la especificación :

. . . Los porcentajes sobre el margen y las propiedades de relleno, que siempre se calculan con respecto al ancho del bloque contenedor en CSS2.1, se calculan con respecto al tamaño en línea del bloque contenedor en CSS3.

La definición de tamaño en línea :

Una medida en la dimensión en línea: se refiere al ancho físico (dimensión horizontal) en los modos de escritura horizontal y a la altura física (dimensión vertical) en los modos de escritura vertical.

Ejemplo, con un elemento redimensionable, donde los márgenes horizontales son relativos al ancho y los márgenes verticales son relativos a la altura.

.resize {
  width: 400px;
  height: 200px;
  resize: both;
  overflow: hidden;
}

.outer {
  height: 100%;
  background-color: red;
}

.middle {
  writing-mode: vertical-lr;
  margin: 0 10%;
  width: 80%;
  height: 100%;
  background-color: yellow;
}

.inner {
  writing-mode: horizontal-tb;
  margin: 10% 0;
  width: 100%;
  height: 80%;
  background-color: blue;
}
<div class="resize">
  <div class="outer">
    <div class="middle">
      <div class="inner"></div>
    </div>
  </div>
</div>

El uso de un modo de escritura vertical puede ser particularmente útil en circunstancias en las que desea que la relación de aspecto de un elemento permanezca constante, pero desea que su tamaño se escale en correlación con su altura en lugar de su ancho.

James T
fuente
Esta es, IMO, sería la solución más elegante, pero (a partir de 05/05/2018), los modos de escritura vertical no son compatibles . Esperemos que eso cambie pronto.
zanerock
1
@zanerock Estoy bastante seguro de que la tabla de compatibilidad MDN está desactualizada. Por ejemplo, dice que Safari necesita el -webkit-prefijo, pero según caniuse no ha requerido el prefijo desde Safari 11. ¿Lo probó con algún navegador en el que no funcionó?
James T
1
No, debo admitir que asumí que era bueno, incluso automatizado.
zanerock
4

Otra forma de centrar el texto de una línea es:

.parent{
  position: relative;
}

.child{
   position: absolute;
   top: 50%;
   line-height: 0;
}

o solo

.parent{
  overflow: hidden; /* if this ins't here the parent will adopt the 50% margin of the child */
}

.child{
   margin-top: 50%;
   line-height: 0;
}
rawiro
fuente
0

Un relleno del 50% no centrará a su hijo, lo colocará debajo del centro. Creo que realmente quieres un relleno superior del 25%. ¿Tal vez te estás quedando sin espacio a medida que tu contenido se hace más alto? ¿También ha intentado configurar el margen superior en lugar de relleno superior?

EDITAR: Nevermind, dice el sitio w3schools

% Especifica el relleno en porcentaje del ancho del elemento contenedor

Entonces, ¿tal vez siempre usa ancho? Nunca me había dado cuenta.

Lo que está haciendo se puede lograr usando display: table aunque (al menos para los navegadores modernos). La técnica se explica aquí .

SpliFF
fuente
1
Gracias Spliff Entiendo que mi 50% no centrará el contenido del div. De hecho, solo tengo una línea de texto que debe centrarse verticalmente. ¡Muchas gracias por el enlace!
Ryan
3
Si es solo una línea de texto, ¿ha considerado utilizar un tamaño ridículamente grande line-height, es decir, hacer que la altura de la línea sea de 200 px?
SpliFF
@Ryan para centrar el texto verticalmente, consulte stackoverflow.com/questions/8865458/…
usuario
su enlace está roto
2016
0

Este es un error muy interesante. (En mi opinión, es un error de todos modos) ¡Buen descubrimiento!

En cuanto a cómo configurarlo, recomendaría la respuesta de Camilo Martin. Pero en cuanto a por qué , me gustaría explicar esto un poco si no les importa.


En las especificaciones de CSS encontré:


Porcentajes de 'relleno' : se refieren al ancho del bloque contenedor

... lo cual es raro, pero está bien.

Entonces, con un padre width: 210pxy un hijo padding-top: 50%, obtengo un valor calculado / calculado de padding-top: 96.5px, que no es el esperado105px .

Esto se debe a que en Windows (no estoy seguro acerca de otros sistemas operativos), el tamaño de las barras de desplazamiento comunes es por defecto 17px × 100%(o 100% × 17pxpara las barras horizontales). Esos 17pxse restan antes de calcular el 50%, por lo tanto 50% of 193px = 96.5px.

WoodrowShigeru
fuente
Hay una razón para la especificación, y esto lo explica mejor: hongkiat.com/blog/calculate-css-percentage-margins
manikanta