Clase de tabla para tablas que, cuando son demasiado anchas, dividen todas sus celdas en filas


Estoy tratando de averiguar qué HTML / CSS necesito para obtener un cierto comportamiento de ruptura dependiendo de cuánto espacio está disponible. Básicamente, quiero que una línea larga de texto se rompa automáticamente en ciertos lugares, y todo en uno), cuando ya no hay espacio para ello.

Ejemplo 1:

  • Hay suficiente espacio horizontal para toda la línea de texto:

    introduzca la descripción de la imagen aquí

  • No hay suficiente espacio horizontal para toda la línea (pero incluso si hay espacio para los dos primeros elementos, todo termina en su propia línea) introduzca la descripción de la imagen aquí

Ejemplo 2: Este es el mismo que el ejemplo anterior, sin embargo, muestra que me gustaría poder usar esto de una manera anidada también:

  • Hay suficiente espacio horizontal para toda la línea de texto:

    introduzca la descripción de la imagen aquí

  • Simplemente no hay suficiente espacio horizontal para toda la línea, por lo que cada celda va por su cuenta línea

    introduzca la descripción de la imagen aquí

  • No hay suficiente espacio horizontal para la segunda celda

    introduzca la descripción de la imagen aquí

Estoy buscando una solución que use solo HTML y CSS (o solo use JavaScript muy ligeramente) ya que mi caso de uso previsto es usar esto bastante fuertemente en páginas de documentación HTML generadas automáticamente.

He encontrado ejemplos como estos , pero no estoy seguro de ver cómo hacer que esto funcione para los subtemas (y cómo hacer que esto funcione sin asignar un tamaño fijo a cada celda - quiero que el tamaño de la celda se determine por su contenido).

Clarfiying editar

Simplemente poniendo énfasis adicional en una parte crucial de la cuestión que se ha pasado por alto. Nunca quiero encontrarme en un estado donde hay dos elementos en una línea y el tercer elemento en la siguiente línea. Los tres elementos deben ir directamente de ser todos en una línea a todos en líneas separadas.

Author: Alec, 2017-12-09

8 answers

Como ya he dicho en los comentarios, lo que el OP está buscando no se puede lograr sin el uso de Javascript, así que aquí está lo que se me ocurrió.

Inicialmente tenemos una estructura de tabla normal, calculamos el ancho de cada tabla y aplicamos un atributo data-width en cada tabla - padre o anidada.

Al redimensionar, tan pronto como cada tabla es más larga que el ancho de la ventana, cambia su visualización de contenido de table-cell a block, apilando así todos los hijos.

Tan pronto Como la ventana el ancho se expande se compara con el atributo data-width de cada tabla y cuando encaja, se expande.

Editar: Pensé que por alguna razón no funcionaría en algunos casos, pero en realidad funciona, así que elimino la hinchazón!

HTML:

<div class="table">
  <div class="cell">
    Content 1
  </div>
  <div class="cell">
    <div class="table">
      <div class="cell">
        Content 1
      </div>
      <div class="cell">
        Cont
      </div>
      <div class="cell">
        Content 3
      </div>    
    </div>
  </div>
  <div class="cell">
    Content 3Content 3Content 3
  </div>

</div>

CSS:

.table {
  display: table;
  border: 1px solid #e4e5e7;
  white-space: nowrap;
}

.cell {
  display: table-cell;
  vertical-align: middle;
  padding: 10px;
  border: 1px solid #e4e5e7;
}

.cell .table {
  margin-bottom: -2px;
}

.table.wrap {
  white-space: normal;
}

.table.wrap > .cell {
  display: block;
}

Javascript:

$('.table').each(function(i) {
  tw = 0;
  $(this).children('.cell').each(function() {
    tw += $(this).outerWidth(true);
  });
  $(this).attr('data-width', tw);
});

$(window).on('load resize', function() {
  w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
  $('.table').each(function(i) {
    if ($(this).width() >= w) {
      $(this).addClass('wrap');
    } else if (w >= $(this).attr('data-width')) {
      $(this).removeClass('wrap');    
    }
  });
}).resize();

Y aquí hay un violín de trabajo

 14
Author: scooterlord,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-22 10:23:36

Otra variante con JS puro

window.addEventListener('load', collapse);
window.addEventListener('resize', collapse);

function collapse() {
  var parents = document.querySelectorAll('.parent');
  var children;
  var width;
  for (var i = 0; i < parents.length; i++) {
    parents[i].classList.remove('collapsed');
    width = 0;
    children = parents[i].children;
    for (var j = 0; j < children.length; j++) {
      width += children[j].offsetWidth;
    }
    if (width > parents[i].offsetWidth) {
      parents[i].classList.add('collapsed');
    }
  }
}
.parent,
.child {
  border: 1px solid gray;
  margin: 5px;
  padding: 5px;
}

.parent {
  display: flex;
  flex-wrap: wrap;
}

.collapsed {
  display: block;
}

.child {
  flex-grow: 1;
}
<div class="parent">
  <div class="child">Some thing one</div>
  <div class="parent child">
    <div class="child">Some inner</div>
    <div class="child">long thing</div>
    <div class="child">two</div>
  </div>
  <div class="child">Thing three</div>
</div>
 7
Author: Sam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-19 07:23:53

Un enfoque es usar @media consultas para alternar entre

display: block

Y

display: inline-block

Ejemplo De Trabajo:

.long-row {
display: inline-block;
width: 200px;
padding-left: 4px;
font-size: 16px;
line-height: 32px;
border: 1px solid rgb(0, 0, 0);
}

@media only screen and (min-width: 801px) {
    .long-row {
        display: inline-block;
        float: left;
    }
}

@media only screen and (max-width: 800px) {
    .long-row {
        display: block;
        border-top: none;
    }

    div:first-of-type.long-row {
        border-top: 1px solid rgb(0, 0, 0);
    }
}

@media only screen and (max-width: 600px) {
    .long-row {
    }

    .short-row {
        display: block;
        margin-left: -4px;
        padding-left: 4px;
        border-bottom: 1px solid rgb(0, 0, 0);
    }
    
    span:last-of-type.short-row {
        border-bottom: none;
    }
}
<div class="long-row">Some thing one</div>

<div class="long-row">
<span class="short-row">Some inner</span>
<span class="short-row">long thing</span>
<span class="short-row">two</span>
</div>

<div class="long-row">Thing three</div>
 1
Author: Rounin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-15 00:11:36

Antes de llegar al script, hay pares de notas que deben considerarse:

En mi estado actual de conocimiento, esto no se puede hacer usando solo CSS. Así que la pregunta es cómo hacer esto usando JavaScript puro con el mejor rendimiento posible? Y he llegado con algunas pautas :

  • usando for bucles ya que son los más rápidos usando caché del número de iteraciones
  • Minimizando las llamadas a funciones siempre que sea posible

    Evitar :

  • Funciones Recursivas

  • [].foreach construye

  • Acceso DOM siempre que sea posible

Además de que se puede anidar a cualquier nivel

La idea:

El script toma todos los elementos, los fuerza en una sola línea, y ve si no hay suficiente espacio, los hace mostrarse uno encima del otro, de lo contrario permanecerían en la misma línea.

Hace esto cada vez que el marcado del documento se carga, y cuando se cambia el tamaño de la ventana.

Https://jsfiddle.net/nasdao/qzdtr9ym /

Salud!

 1
Author: user10089632,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-18 07:44:46

Como mencioné en mi comentario puedes hacer uso de flexbox, aquí hay una demostración de cómo querías. Hope, esto ayuda.

.flex-container {
  display: flex;
  align-items: center;
  flex-direction: row;
  flex-wrap: wrap;
  flex-flow: row wrap;
  align-content: flex-end;
}

.flex-item {
  background: gray;
  color: white;
  margin: 2px;
  height: 80px;
  text-align: center;
  font-size: 30px;
  border:3px solid black;
}
<div>
<div class="flex-container">
  <div class="flex-item">Something One</div>
  <div class="flex-container" style="border:2px solid black">
     <div class="flex-item">Something 2</div>
     <div class="flex-item">Something random3</div>
     <div class="flex-item">Some 4</div>
  </div>
  <div class="flex-item">Something Five</div>
</div>
 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-09 19:54:02

Puedes hacerlo usando display: flex;

Por ejemplo:

 .horz_cont {
        display: flex;
        align-items: center;
        flex-direction: row;
        flex-wrap: wrap;
        flex-flow: row wrap;
        align-content: flex-end;
        border: 1px solid #000;
        padding: 4px;
    }
    
    .horz_cont .horz_cont {
       border: none;
       padding: 0;
    }
    
    .item {
        display: flex;
        align-items: center;
        justify-content: center;
        margin: 4px;
        padding: 4px;
        height: 50px;
        font-size: 34px;
        font-weight: bold;
        border: 1px solid #000;
    }
<div class="horz_cont">
  <div class="item">Some thing one</div>
  <div class="horz_cont">
     <div class="item">Some inner</div>
     <div class="item">long thing</div>
     <div class="item">two</div>
  </div>
  <div class="horz_cont">
     <div class="item">Thing three</div>
  </div>
</div>
 0
Author: Elvin Mammadov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-09 20:59:31

Puede intentar usar media queries en los tamaños de pantalla, de modo que cuando el contenido interno del flexbox medio excede su contenedor, puede escribir CSS que solo se aplica a ese escenario.

También es importante agregar la etiqueta viewport al encabezado de su html:

<meta name="viewport" content="width=device-width, initial-scale=1.0">

Abra el ejemplo a pantalla completa y cambie el tamaño de la ventana del navegador para ver cómo aparecen los elementos.

Espero que esto sea útil para usted.

Salud!

.flex-container {
  display: flex;
  align-items: center;
  flex-direction: row;
  flex-wrap: wrap;
  flex-flow: row wrap;
  align-content: flex-end;
}
.flex-item, .inner-flex-item {
  background: white;
  color: black;
  padding: 5px;
  margin: 2px;
  height: 100px;
  text-align: center;
  line-height: 100px;
  font-size: 50px;
  border:3px solid black;
}
@media screen and (max-width: 1180px) {
  .flex-item {
    width: 80%;
}
@media screen and (max-width: 640px) {
  .inner-flex-item {
    width: 80%;
}
<div>
  <div class="flex-container">
  <div class="flex-item">Something One</div>
  <div class="flex-container" style="border:2px solid black">
    <div class="inner-flex-item">Some inner</div>
    <div class="inner-flex-item">long thing</div>
    <div class="inner-flex-item">two</div>
  </div>
  <div class="flex-item">Thing three</div>
</div>
 0
Author: JSONaLeo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-16 00:48:03

No se una manera de hacerlo en cada tamaño de pantalla en css puro. Necesito un poco de javascript (más fácil con jquery)

  1. Esos elementos son bloques en línea.
  2. Para cada grupo de elementos hermanos compruebe si la posición superior del último hijo es la misma que la posición superior del primer hijo (si es así, están en la misma línea).
  3. Si no es la misma posición superior, agregue una clase para hacerlos bloques de nuevo (a pesar de los bloques en línea).

Funciona bien con niveles n-anidados y es razonablemente ligero javascript. (además, no hay consultas de medios, ningún número de elementos por nivel, no hay bucles con "tratando de encajar", probablemente el soporte más amplio del navegador...)

$(function() {
 $('div.line:first-child ~ div.line:last-child').each(
  function(){
    if( $(this).position().top != $(this).siblings(":first-child").position().top ){
      $(this).parent().addClass("breaks")
    }
  }
 );
});
div{outline:1px solid red;}

.line{display:inline-block;}
.breaks > .line{display:block;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="line">Some thing one</div>
<div class="line">
  <div class="line">Some inner</div>
  <div class="line">longest thing</div>
  <div class="line">two</div>
</div>
<div class="line">this is long Thing three</div>
</div>

EDITAR: una segunda opción con la misma lógica, pero usando selector para el "grupo" de elementos-no los propios elementos-, con mejor rendimiento y sin jquery

window.addEventListener('load', breaklines);

function breaklines() {
  var groups = document.querySelectorAll('.group');
  for (var i = 0; i < groups.length; i++) {
    if(groups[i].children[0].offsetTop != groups[i].children[ groups[i].children.length - 1].offsetTop){
      groups[i].classList.add('breaks');
    }else{
      groups[i].classList.remove('breaks');
    }
  }
}
div.group > div{outline:2px dotted red;}
div.group div.group > div{outline:2px solid green;}


.group > div {display:inline-block}
.group.breaks > div {display:block}
<div class="group">
<div>Some thing one</div>
<div class="group">
  <div>Some inner</div>
  <div>longest thing</div>
  <div>two</div>
</div>
<div>this is long Thing three</div>
</div>
 0
Author: miguel-svq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-18 12:53:57