【问题标题】:table column width by content but not more the 50%表格列宽(按内容)但不超过 50%
【发布时间】:2021-12-06 07:33:30
【问题描述】:

美好的一天。 我有两列的表格:第一列用于标签,第二列用于控制元素。标签可以很短也可以很长。

table{
padding-bottom: 20px;
}

td{ border: 1px solid}
<table style="width:100%;">
    <tr>
      <td class="first-column">very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very label</td>
      <td class="second-column"><input style="width:100%"/></td>
    </tr>
    <tr>
      <td class="first-column">label</td>
      <td class="second-column"><input style="width:100%"/></td>
    </tr>
</table>
    
  
<table style="width:100%;">
    <tr>
      <td class="first-column">medium label</td>
      <td class="second-column"><input style="width:100%"/></td>
    </tr>
    <tr>
      <td class="first-column">label</td>
      <td class="second-column"><input style="width:100%"/></td>
    </tr>
 </table>

 <table style="width:100%;">
    <tr>
      <td class="first-column">label</td>
      <td class="second-column"><input style="width:100%"/></td>
    </tr>
    <tr>
      <td class="first-column">label</td>
      <td class="second-column"><input style="width:100%"/></td>
    </tr>
 </table>

我需要根据其内容(最长标签的宽度)调整第一列的大小,但如果标签很长,它不应填充超过 50% 的表格。 像这样的东西

您能帮我为这种情况编写正确的 css 吗?我不能使用 Javascript,它应该是 css-only 解决方案。

【问题讨论】:

  • .first-column{ 最大宽度:50%;宽度:100%; } - jsfiddle.net/b84yhvt3/1
  • 在第二个表中第一列的宽度是 50%,我需要它是按内容
  • 看我的例子 - jsfiddle.net/9jmwf5kc
  • 来自@LuisP.A. 的小提琴给出了正确的视觉结果,但它要求系统提前知道哪些是短列(并为那些引入了无换行)。您是否受限于使用表格而不是其他 HTML 结构?
  • @AHaworth 不,我没有限制只能使用表格元素。我只需要表格布局。它可以用任何其他 html 元素制作。

标签: html css html-table width col


【解决方案1】:

td{
  border: 1px solid black;
  width: 100%;
}
td.first-column {
  max-width: 50%;
  min-width: 10px;
}
<table style="width:100%;">
<tr>
  <td class="first-column">very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very label</td>
  <td class="second-column"><input style="width:100%"/></td>
</tr>
</table>

<table style="width:100%;">
<tr>
  <td class="first-column">short label</td>
  <td class="second-column"><input style="width:100%"/></td>
</tr>
</table>

【讨论】:

  • 它不工作。我按了“运行代码 sn-p”,结果不符合预期。
  • 编辑答案后它不起作用,因为在第二个表中第一列大小为 50%,而我需要按内容宽度。
  • 啊,现在我明白了。我稍后再看
【解决方案2】:

我自己的建议是首先 - 除非由于其他原因不切实际 - 将所有标签和 &lt;input&gt; 元素合并到同一个父元素中,这样可以简化所有列的对齐方式。

为此,我将元素分组为单个 &lt;fieldset&gt; 元素,该元素本身位于 &lt;form&gt; 中:

// This JavaScript has no part to play in the resizing of elements,
// but merely logs the size of each of the two columns in the
// relevant elements (the last <label> and the last <input>:
const D = document,
            logLengths = () => {
    let label = D.querySelector('label:last-of-type'),
        input = D.querySelector('input:last-of-type');
  [label, input].forEach(
    (el) =>{
        el[ 
        el.tagName.toLowerCase() === 'input' ? 'value' : 'textContent'
        ] = Math.round(el.getBoundingClientRect().width*10)/10 + 'px';
    });
};

logLengths();
D.querySelectorAll('label').forEach(
    (label) => label.addEventListener('input', logLengths)
);
/* Generic CSS reset: */
*,
::before,
::after {
  box-sizing: border-box;
  font-size: 16px;
  line-height: 1.5;
  margin: 0;
  padding: 0;
}

form {
  border: 1px solid currentColor;
  /* using CSS logical properties to place a 1em margin
     on the block axis (top/bottom) in left-to-right, top-
     to-bottom languages) */
  margin-block: 1em;
  /* ...and a margin of auto (to centre the element) on
     the inline-axis (left and right in ltr languages): */
  margin-inline: auto;
  padding: 0.2em;
  width: 90vw;
}

fieldset {
  /* in order to use CSS Grid: */
  display: grid;
  /* setting gaps/'gutters' between rows of 0.5em,
     and 0.25em gaps between adjacent columns: */
  gap: 0.5em 0.25em;
  /* defining two columns, the first of which is sized
     'auto', allowing the layout to be sized appropriately
     to the content within the limits of other columns,
     the second column is sized using the 'minmax()'
     function between a minimum size of 50% (because the
     maximum permitted size of the first column is 50%),
     and 1fr, which is the fractional unit of the remaining
     space available: */
  grid-template-columns: auto minmax(50%, 1fr);
}

/* this styles the 'information' <div> that provides
   guidance about the interactivity of the editable
   <label> elements: */
fieldset div {
  grid-column: 1 / -1;
  text-align: center;
  padding: 0 2rem;
}

code, kbd {
  font-family: consolas, ubuntu mono, monospace;
}

kbd {
  border: 1px solid #aaa;
  border-radius: 0.4em;
  padding: 0.1em 0.3em;
}

label {
  /* to indicate interactivity: */
  cursor: pointer;
  /* for positioning the pseudo element: */
  position: relative;
}

/* entirely irrelevant to the demo, but just to
   make it look a little prettier (adjust to
   taste or remove as you like): */
label::before {
  content: '';
  background: linear-gradient(90deg, lime, #ffff);
  height: 100%;
  position: absolute;
  transform: scaleX(0);
  transition: transform 0.3s ease-in-out;
  transform-origin: 0 100%;
  width: 100%;
  z-index: -1;
}

label:hover::before {
  transform: scaleX(1);
}

.length {
  background: revert;
  background-color: #fff;
  border-color: transparent;
  border-top: 1px solid currentColor;
  cursor: not-allowed;
  font-style: italic;
  text-align: center;
}
<form action="#">
  <fieldset>
  <!-- this <div> is here simply to provide some guidance as to the
       interactivity of the <label> elements for the purpose of this
       demo; otherwise it can be removed entirely: -->
  <div>Most labels are <code>contentEditable</code>, though they will focus the &lt;input&gt; element when clicked; <kbd>shift</kbd>&plus;<kbd>tab</kbd> to focus the &lt;label&gt;</div>
    <!-- because we're using a grid (and the majority of browsers don't yet
         support display: subgrid) to create the aligned columns, the <input>
         elements are the following-siblings of the <label> elements; in order
         to associate the <label> with the correct <input> I've added an 'id'
         attribute to each <input>, and the same id-value for the associated
         <label> in their 'for' attribute; this means clicking/tapping on a
         <label> will focus the appropriate <input>: -->
    <label for="inputElement_0" contentEditable>longer label</label>
    <input id="inputElement_0">
    <label for="inputElement_1" contentEditable>label</label>
    <input id="inputElement_1">
    <label for="inputElement_2" contentEditable>medium label</label>
    <input id="inputElement_2">
    <label for="inputElement_3" contentEditable>label</label>
    <input id="inputElement_3">
    <label for="inputElement_4" contentEditable>label</label>
    <input id="inputElement_4">
    <label for="inputElement_5" contentEditable>label</label>
    <input id="inputElement_5">
    <!-- these elements are here purely to report the length of the 
         grid-columns in which they appear: -->
    <label for="lengthInput" class="length"></label>
    <input id="lengthInput" type="text" class="length" readonly>
  </fieldset>
</form>

JS Fiddle demo.

如果 subgrid 在您的浏览器中可用(目前仅在 Firefox 中可用),那么以下是可能的:

// Again, this JavaScript has nothing to do with the resizing, but only shows
// the widths of the grid-tracks the elements are in:
const D = document,
  logLengths = () => {
    let label = D.querySelector('label:last-of-type'),
      input = label.querySelector('input:last-of-type');
    [label, input].forEach(
      (el) => {
        let width = Math.round(el.getBoundingClientRect().width / 10) * 10,
          val = `${width}px`;
        if (el.matches('label')) {
          label.firstChild.nodeValue = val;
        } else if (el.matches('input')) {
          el.value = val;
        }
      });
  };

logLengths();
D.querySelectorAll('label').forEach(
  (label) => label.addEventListener('input', logLengths)
);
*,
::before,
::after {
  box-sizing: border-box;
  font-size: 16px;
  line-height: 1.5;
  margin: 0;
  padding: 0;
}

form {
  border: 1px solid currentColor;
  margin-block: 1em;
  margin-inline: auto;
  padding: 0.2em;
  width: 90vw;
}

fieldset {
  display: grid;
  gap: 0.5em 0.25em;
  grid-template-columns: auto minmax(50%, 1fr);
}

fieldset div {
  grid-column: 1 / -1;
  text-align: center;
  padding: 0 2rem;
}

code,
kbd {
  font-family: consolas, ubuntu mono, monospace;
}

kbd {
  border: 1px solid #aaa;
  border-radius: 0.4em;
  padding: 0.1em 0.3em;
}

label {
  cursor: pointer;
  position: relative;
  /* Using display: grid to allow us to make use
     of subgrid: */
  display: grid;
  /* instructing the layout engine to use the
     grid-columns/grid-tracks of the parent
     element: */
  grid-template-columns: subgrid;
  /* positioning the grid-start in the first
     grid-column and the grid-end in the last
     grid-column: */
  grid-column: 1 / -1;
}

label::before {
  content: '';
  background: linear-gradient(90deg, lime, #ffff);
  height: 100%;
  position: absolute;
  transform: scaleX(0);
  transition: transform 0.3s ease-in-out;
  transform-origin: 0 100%;
  width: 100%;
  z-index: -1;
}

label:hover::before {
  transform: scaleX(1);
}

.length {
  background: revert;
  background-color: #fff;
  border-color: transparent;
  border-top: 1px solid currentColor;
  cursor: not-allowed;
  font-style: italic;
  text-align: center;
}
<form action="#">
  <fieldset>
    <div>All labels are <code>contentEditable</code>, though they will focus the &lt;input&gt; element when clicked; <kbd>shift</kbd>&plus;<kbd>tab</kbd> to focus the &lt;label&gt;</div>
    <!-- because we can use subgrid, we can place the <input> elements
         inside of their associated <label> elements, which removes the
         need to assign either a 'for' attribute to the <label> or an
         'id' attribute to the <input>, since they're automatically
         associated this way via nesting: -->
    <label contentEditable>longer label
      <input>
    </label>

    <label contentEditable>label
      <input>
    </label>
    <label contentEditable>medium label
      <input>
    </label>
    <label contentEditable>label
      <input>
    </label>
    <label contentEditable>label
      <input>
    </label>
    <label contentEditable>label
      <input>
    </label>
    <label class="length">
      <input type="text" class="length" readonly>
    </label>
  </fieldset>
</form>

JS Fiddle demo.

参考资料:

【讨论】:

  • 如果我在很长的标签中删除您的第一个代码 sn-p 那么标签的列仍占网格的 50%。 jsfiddle.net/dw26gj3p
  • @АрсенМирзаян:我刚刚更新了演示;我的错误是误解了minmax() 函数;在这个演示中,大部分&lt;label&gt; 元素是contentEditable,并允许您输入或删除文本以实时演示调整大小。抱歉,我以为我在发布之前检查了原始代码是否按预期工作。 Sigh... 此外,虽然答案中有一些 JavaScript 对调整大小没有任何作用,只是报告每个网格轨道的当前大小。
  • 完美。它完全按照我的需要工作。谢谢您的帮助。我将此答案标记为解决方案。
  • @АрсенМирзаян:不客气,很高兴能帮上忙!
猜你喜欢
  • 2022-12-18
  • 2012-07-16
  • 1970-01-01
  • 1970-01-01
  • 2013-05-09
  • 2019-01-28
  • 1970-01-01
  • 1970-01-01
  • 2016-09-20
相关资源
最近更新 更多