1

I have a form laid out using display: table-row and table-cell, where each row contains two cells: a label and an input. Both cells have an unspecified width, because I want them to stretch along with the contents inside them.

However, in a particular cell I need to add an element with extra information. No matter how long the information in it is, I don't want it to stretch the right-hand cell. I just want the text to wrap as if the block had a width set, but without setting one (because I do not know what it will have to be)

.row {
    display: table-row;
    outline: 1px solid black;
}
.cell {
    display: table-cell;
    padding: 5px;
}
.info {
    display: block;
}
<div class="row">
    <div class="cell">Label</div>
    <div class="cell input">
        <input type="text" />
    </div>
</div>
<div class="row">
    <div class="cell">Another label</div>
    <div class="cell input">
        <input type="text" />
        <span class="info">This text should not make the cell larger</span>
    </div>
</div>

I know that the relatively new width: min-content should be able to handle this, which it does on inline blocks but that defies the purpose of using table-cell, which I found out during my previous questionx. Also it's not supported by IE, which I do need.

I've tried setting the .info to inline and inline-block on a new line (both using <br> and a pseudo-element with display: block), all in combination with word-break: break-word but to no avail.

Strangely, when I apply max-width: 0 to the .input div after the page rendered (using the developer tools) the cell will shrink to fit the input, and it produces exactly the desired effect. However, setting this value beforehand will actually force a 0 width cell and all the contents will overflow.
I really don't want to resort to having to set this value after rendering using javascript. Is there a CSS way to do this?

Community
  • 1
  • 1
Stephan Muller
  • 27,018
  • 16
  • 85
  • 126
  • 1
    Why not use a table? – TylerH Sep 23 '14 at 17:45
  • @TylerH - Why would it help? – LcSalazar Sep 23 '14 at 17:49
  • 1
    @LcSalazar If he's dead set on making it behave and look like a table, then actually using an HTML table would allow for built-in controls and table behavior, which you have to fake when using CSS. – TylerH Sep 23 '14 at 17:50
  • 1
    This: [css table-cell equal width](http://stackoverflow.com/questions/10525744/css-table-cell-equal-width) look promising. – Andrew Morton Sep 23 '14 at 17:51
  • 1
    @TylerH - First, the problem here is not *making it behave like a table*, it already does. The problem is something else... Second, HTML tables are not recomended for layout. – LcSalazar Sep 23 '14 at 17:52
  • @LcSalazar First, it doesn't behave like a table; it is *displayed* like a table. There is a difference. Second, tables are not recommended for laying out your *entire site*. HTML tables *are* recommended for situations where you want tabular data, because they are really powerful and also quite flexible. Not only would he have more intuitive ways to solve his problem (tables do a lot of thinking for you regarding stretching), it would also mean more semantic markup. – TylerH Sep 23 '14 at 17:57
  • @AndrewMorton, that would work if I knew what width to set the table to. Unfortunately, both columns can have variable widths. – Stephan Muller Sep 23 '14 at 18:03
  • @TylerH if you can solve this problem using an actual table, please go ahead. But I'm quite positive that that won't change anything. I will try out an actual table for completeness anyway. – Stephan Muller Sep 23 '14 at 18:04
  • (I disagree about the html being more semantic though. A form is not tabular data) – Stephan Muller Sep 23 '14 at 18:05
  • I agree a form is not tabular data, but you are trying to make your form look and behave like tabular data, which makes me wonder why you aren't just using a table. – TylerH Sep 23 '14 at 18:06
  • Semantics, more elements introduced, harder to make responsive if I need to do that. Now I can just set them back to block for smaller screens, that's not so easy with actual tables. I believe that if you can solve this problem with a real table, then you can do it with my way too. Prove me wrong and I'll switch. – Stephan Muller Sep 23 '14 at 18:09
  • @StephanMuller I have an answer ready, but first I would like to know what you mean by "add an element with extra information". How do you expect the cells to grow? Do you plan on having other content inside them aside from input fields (which are static width)? – TylerH Sep 23 '14 at 18:31
  • Yes, I expect any kind of content in there from inputs to a list of radio buttons (with labels) to just plain text. The width of those I can manage. It's just the width of the `.info` element I don't want interfering with the cell's width. It should just wrap and push down the element below them as if it was given a fixed width. – Stephan Muller Sep 23 '14 at 18:41
  • @StephanMuller Re: semantics - just call it an *input table* :) – Andrew Morton Sep 23 '14 at 20:30

4 Answers4

3

With inspiration from table-cell - some kind of colspan?, using another CSS table layout inside, and assuming you want a result like

Render example

The idea being to use a table-caption for the part you want to be only as wide as the items above it.

.row {
  display: table-row;
  outline: 1px solid black;
}
.cell {
  display: table-cell;
  padding: 5px;
}
.info {
  display: table-caption;
  caption-side: bottom;
  width: 100%;
}
<div class="aTable">
  <div class="row">
    <div class="cell">
      <label for="inp1">Label</label>
    </div>
    <div class="cell input">
      <input type="text"  id="inp1" />
    </div>
  </div>
  <div class="row">
    <div class="cell">
      <label for="inp2">Another label</label>
    </div>
    <div class="cell">
      <div class="aTable">
        <div class="row">
          <div class="input">
            <input type="text" id="inp2" />
            <label>
              <input type="radio" id="r1" name="radioChoice" value="radiogaga" />
              Radio GAGA
            </label>
            <label>
              <input type="radio" id="r2" name="radioChoice" value="radiokaos" checked />
              Radio KAOS
            </label>
          </div>
          <div class="info">
            This text should not make the cell any larger - it works in my testing with IE11 and FF32.0.2.
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
Community
  • 1
  • 1
Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
  • @Oriol Thanks for code-snippetting it - I couldn't get that to work on my first attempt. – Andrew Morton Sep 23 '14 at 20:36
  • That's an interesting solution! It doesn't seem to work on Chrome, but I'll definitely dive into that and see if I can get it to do what FF does. I'd never heard of `table-caption` and `caption-side` before, so +1 just for that alone. To be continued after some tinkering – Stephan Muller Sep 23 '14 at 20:42
  • @AndrewMorton +1 great idea. However, maybe it's not clear enough what exactly does the trick, so I posted another answer summing up your code. – Oriol Sep 23 '14 at 20:54
3

Simplifying @AndrewMorton's answer,

<span class="info">
    <span class="info-inner">
        This text should not make the cell larger
    </span>
</span>
.info {
    display: table;
    width: 100%;
}
.info-inner {
    display: table-caption;
}

.row {
    display: table-row;
    outline: 1px solid black;
}
.cell {
    display: table-cell;
    padding: 5px;
}
.info {
    display: table;
    width: 100%;
}
.info-inner {
    display: table-caption;
}
<div class="row">
    <div class="cell">Label</div>
    <div class="cell input">
        <input type="text" />
    </div>
</div>
<div class="row">
    <div class="cell">Another label</div>
    <div class="cell input">
        <input type="text" />
        <span class="info">
            <span class="info-inner">
                This text should not make the cell larger
            </span>
        </span>
    </div>
</div>
Community
  • 1
  • 1
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • Whoa, nice! Works in all relevant browsers too. – Stephan Muller Sep 23 '14 at 20:56
  • Sorry Oriol, while this is an ingenious fix and I've already been able to use it in another case (where the wrapper was an `inline-block` that shouldn't be stretched), in this particular case where the wrapper is a `table-cell`, I found a much simpler answer. Since that works for actual `td`s too I think my solution is actually better suited for the question. Didn't mean to steal your thunder, but I will unaccept this answer. – Stephan Muller Sep 24 '14 at 21:10
  • @StephanMuller Of course, I also think your answer is better. – Oriol Sep 24 '14 at 22:44
1

As a result of some unrelated tinkering to the width of a specific unrelated column that actually did need a fixed width I stumbled upon this fix:

.input { 
    width: 1px;
}

I completely overlooked the fact that on elements with a display: table-cell, the width property acts like a min-width would on other elements. So by setting a 1 pixel width, the cell always shrinks to the minimum width it needs. Inputs can't be shrunk so that's the smallest size the cell takes, and the .info element is actually wrapped to fit inside the cell. This completely solved my problem in one simple CSS rule.

If I want to have an element that does push the cell width now, I can simply set a width on it, or use white-space: nowrap to not have it wrapped (so then it simply has to push the cell boundary).

.row {
    display: table-row;
    outline: 1px solid black;
}
.cell {
    display: table-cell;
    padding: 5px;
}
.input { 
    width: 1px;
}
.info {
    display: block;
}
<div class="row">
    <div class="cell">Label</div>
    <div class="cell input">
        <input type="text" />
    </div>
</div>
<div class="row">
    <div class="cell">Another label</div>
    <div class="cell input">
        <input type="text" />
        <span class="info">This text should not make the cell larger</span>
    </div>
</div>
Oriol
  • 274,082
  • 63
  • 437
  • 513
Stephan Muller
  • 27,018
  • 16
  • 85
  • 126
0

Okay, here is a table that I believe does what you are asking.

I cannot think of a situation where choosing an arbitrary width of the below p element beforehand will be a problem; if you want an element that is smaller than the input box (the minimum width) then it's no problem and it won't change the size anyway.

However, if you want to add a description element that is bigger than the input box (and would grow the cell's width), or you want to add content, then the cell is going to grow anyway.

It will be difficult to really tell, I think, without knowing all the kinds of elements you will have. In the comments you mentioned radio buttons as well. I would add a different class for each type of input device (box, radio button, True/False choice, slider, dropdown box) and set a unique fixed width for each one of those.

At that point, however, it may in fact end up easier (fewer LOC) to do in JavaScript. I can't speculate there, as I don't really know JavaScript.

JSFiddle

<table rules="rows">
    <tr>
        <td>This is a super long label to show that the table can grow.</td>
        <td class="right-col"><input/></td>
    </tr>
    <tr>
        <td>Another Label</td>
        <td class="right-col"><input/>Delete this text to see that non "p" description text will still make the table shrink or grow.<p>This is a fixed-width description with the same length as the input element above.</p></td>
    </tr>
    <tr>
        <td>A Third Label</td>
        <td class="right-col"><input type="radio"/>This text gets to expand the cell.<p>Another test example.</p></td>
    </tr>
</table>

CSS:

table {
    border: 1px solid black;
}

.right-col p {
    margin: 0;
    width: 150px;
    color: red;
}

input[type=radio] ~ p {
    margin: 0;
    width: 25px;
    color: blue;
    word-wrap: break-word;
}
TylerH
  • 20,799
  • 66
  • 75
  • 101
  • `.right-col p { width: 150px; }` does exactly the same as `.input { width: 150px; }` would in my code snippet. The point is that I can't hardcode the width, because I'm not always sure how wide the inputs are going to be. – Stephan Muller Sep 23 '14 at 19:38
  • @StephanMuller Why not just have them all be 150px or 200px or something and then if necessary, the text will just scroll? The question would be better if it had a more complete example of the form you are wanting to implement. – TylerH Sep 23 '14 at 20:27
  • The example is the exact bare minimum needed to explain my problem. I could include my entire project's code but it'd make you none the wiser. I don't know how big elements in the right column will be, but I'm the dev who has to build what the designer gives me and he gives me this. I'm looking for the most flexible, easiest to maintain implementation of his design. – Stephan Muller Sep 23 '14 at 20:39
  • @StephanMuller "None the wiser" Well, I disagree, since needing to find a solution that works for input boxes doesn't necessarily include a solution that works for radio buttons too, but it's moot since there's an accepted answer. – TylerH Sep 23 '14 at 21:06