且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

当孩子是一张桌子时,min-width不够好

更新时间:2022-10-18 11:51:39

我认为 .container {min-width:400px; width:min-content;} >

My previous question got an answer using min-width to set the width of a containing block but allow it to grow when its children are too big.

This worked fine with some kinds of children (simple divs with their own min-width and max-width specified explicitly). Now I'm looking at a more complex variation in which the children are tables. (Legitimate tables with semantically meaningful rows and columns, not page-layout tables.)

There is no manually-specified min-width or max-width on these tables, but tables have an inherent maximum and minimum width, corresponding to the width that the table would have if rendered with no line breaks in any of the cells (maximum) and the width that it would have with line breaks inserted insertion of all possible line breaks (minimum).

In the existing page layout which I'm trying to replace, the outermost container is a table (the bad kind of table) with a single cell in a single row, and a CSS width (not min-width) set to the preferred width. When the children are tables, they try really hard to fit into the container's width. A wide table will be rendered with line breaks to make it fit, and the container will expand only if the child still doesn't fit after all line breaks are inserted.

In other words, the parent's width property is treated as a minimum, but it is also a strongly preferred width, which has a higher priority than the child's preferred (i.e. maximum) width.

By contrast, when the parent is a plain div with display:inline-block and a specified min-width, the parent's min-width is not strongly preferred. The child prefers to be wider, so the parent expands, even if the child is capable of being rendered with a smaller width.

Here's a snippet, much like the one in the previous question, which demonstrates all of this. The goal is to make the second container act like the first one in some way that is more "proper" than using display:table for layout.

(Note: the table widths at the heart of this question are very sensitive to choice of font. I hope the Courier New comes through and everybody sees the same widths in the snippet.)

var containers = document.querySelectorAll(".container");
for(var i = 0; i < containers.length; ++i) {
  (function() {
    var c = containers[i],
        b = c.nextElementSibling;
    b.addEventListener("click", function(ev) {
      big = c.querySelector(".bigchild");
      medium = c.querySelector(".mediumchild");
      small = c.querySelector(".smallchild");
      if(big.style.display != "block" &&
         medium.style.display != "block" &&
         small.style.display != "block") {
        big.style.display = "block";
      } else if(big.style.display == "block") {
        big.style.display = "none";
        medium.style.display = "block";
      } else if(medium.style.display == "block") {
        medium.style.display = "none";
        small.style.display = "block";
      } else {
        small.style.display = "none";
      }
    });
  })();
}

body {
  background-color: #ccc;
  text-align: center;
  font-size: 14px;
  font-family: "Courier New";
}
table {
  border-collapse: collapse;
}
td {
  border: 1px solid black;
  padding: 5px;
}
.container {
  background-color: white;
  min-height: 250px;
  margin-left: auto;
  margin-right: auto;
}
.bigchild, .mediumchild, .smallchild {
  display: none;
}
button {
  display: block;
  margin: 10px auto 20px;
}
#container1 {
  display: table;
  width: 400px;
}
#container2 {
  display: inline-block;
  min-width: 400px;
}

<div class="container" id="container1">
    <table class="bigchild">
      <tr>
        <td>Lots of</td>
        <td>columns</td>
        <td>make this</td>
        <td>a very</td>
        <td>wide</td>
        <td>table</td>
        <td>that won't</td>
        <td>fit</td>
        <td>even with</td>
        <td>added</td>
        <td>line breaks</td>
      </tr>
    </table>
    <table class="mediumchild">
      <tr>
        <td>This table</td>
        <td>is smaller</td>
        <td>and</td>
        <td>it fits</td>
        <td>but</td>
        <td>only with</td>
        <td>added</td>
        <td>line breaks</td>
      </tr>
    </table>
    <table class="smallchild">
      <tr>
        <td>very</td>
        <td>small</td>
      </tr>
    </table>
  </div>
  <button>Next</button>

  <div class="container" id="container2">
    <table class="bigchild">
      <tr>
        <td>Lots of</td>
        <td>columns</td>
        <td>make this</td>
        <td>a very</td>
        <td>wide</td>
        <td>table</td>
        <td>that won't</td>
        <td>fit</td>
        <td>even with</td>
        <td>added</td>
        <td>line breaks</td>
      </tr>
    </table>
    <table class="mediumchild">
      <tr>
        <td>This table</td>
        <td>is smaller</td>
        <td>and</td>
        <td>it fits</td>
        <td>but</td>
        <td>only with</td>
        <td>added</td>
        <td>line breaks</td>
      </tr>
    </table>
    <table class="smallchild">
      <tr>
        <td>very</td>
        <td>small</td>
      </tr>
    </table>
  </div>
  <button>Next</button>

I think .container {min-width: 400px;width: min-content;}, modulo vendor prefixes, is what you want.