1

I have the following piece of HTML with effectively a table for an aligned form:

<div id="one">
  <p>
    <label for="a">a</label> <input type="text" id="a">
  </p>
  <p class="h">
    <label for="b">bbbbbb</label> <input type="text" id="b">
  </p>
</div>

with the following CSS:

#one {
  display: table;
  width: auto;
}

p {
  display: table-row;
}

p label, p input {
  display: table-cell;
}

#one is something of automatically computed width, and labels and inputs are of unknown width. I want the functionality of an aligned form, but such that adding class h to their row removes then, making space for other elements vertically, but not changing width of #one, since it is supposed to sit next to other elements with automatically computed width.

What .h definition in CSS3 would give me my "table row" (p) height equal to 0 or otherwise visually remove it without changing the width of its parent? I can change HTML if needed, but I want to find a solution that does not use JS for that.

visibility: hidden does not remove it vertically, height: 0 does not work (probably because it is table-row), and display: none does not work, because it changes the effective width to 0. And I want my #one to stay the same width. Using display: block !important in combination with height: 0 partially works, but leaves a weird vertical space (and block should not really be a child of table).

What I'm searching for is similar to this SO question, but I'm searching for a pure CSS solution and without fixing the table width.

You can play with it here: JSFiddle.

nemanja
  • 664
  • 5
  • 16
Xilexio
  • 1,178
  • 19
  • 40
  • This is really, really confusing. Even jsfiddle doesn't help much. I think I MIGHT have some idea about what you're trying to achieve, but a few questions: 1. Is it absolutely necessary to use "css table"? 2. Do you have predered width of `#one` (you've never set it)? 3. Do you have any control over the HTML? And what is the ultimate visual goal for the whole structure - that is: how do you want table to look? – nemanja Dec 02 '18 at 01:57
  • The width of `#one` should be `auto`. It is not necessary to use css table, but this is as I have it in my project and I do not want to depend on various `table`'s default values - I just want the form aligned without knowing its width (and the form is next to something else of unknown width). I have the control over HTML. The visual goal is that when `p` gets `h` class then it disappears, making space for other stuff vertically, but not triggering change of width of the form. I'll update the question accordingly. – Xilexio Dec 02 '18 at 02:02
  • If you don't have width of **any** element set anywhere, and the width is auto, I can't think of a way that the removal of `.h` doesn't affect the width of `#one`. In fact, it is reverting the width to `#one's` **original** state! `.h` is wider and the whole table adapts to its width when it is present/visible.`width: auto` is absolutely doing the way it is supposed to do - it is adapting to the contents. I mean, the request is contradicting itself, don't you think? – nemanja Dec 02 '18 at 02:29

1 Answers1

1

Ok, this might work as your solution. Note that it doesn't have to be flex - it works with floats as well, but it doesn't work with display: table (and to be honest, I don't really see the point of using it in 2018).

Btw, I have added one more "row" after the .h so that we can control what happens. If everything is working correctly, we should see .h vertically "collapsing" so that the first and the third rows are in contact.

#one {
  display: inline-block;
  background-color: #F0FFFF;
}

p {
  display: flex;
  justify-content: space-between;
  margin: 0; /* this is crucial because paragraphs have some margin set by default and I cannot know do you "reset" or "normalize" your css */
}

.h {
  transform: scaleY(0); /* this is something that is used actually quite often for animating dropdown menus */
  transform-origin: 50% 0; /* this line of code isn't contributing anythow NOW to your problem, but should you choose to animate "collapsing" the height of the row, it is setting its origin of transformation to the middle of the top border */
  height: 0;
}
<div id="one">
  <p>
    <label for="a">a</label> <input type="text" id="a">
  </p>
  <p class="h">
    <label for="b">bbbbbb</label> <input type="text" id="b">
  </p>
  <p>
    <label for="a">a</label> <input type="text" id="a">
  </p>
</div>

Additionally, you can add visibility: hidden if you want, but it doesn't change the solution. Hope it helped.

EDIT:

In searching for the solution, I have just stumbled upon this article (especially - this part). Although the article suggests that visibility: collapse should almost never been used, I felt it's worth mentioning it because it answers your original question. And, to be honest, I've learned about that "feature" of visibility just now while researching. Probably because nobody ever uses it :D.

CSS for your original code would have just this one more rule added (but you could also combine it with scaleY, height...):

#one {
  display: table;
  width: auto;
}

p {
  display: table-row;
}

p label, p input {
  display: table-cell;
}

.h {
  visibility: collapse;
}

Further reading: MDN: Visibility

(visibility: collapse) For rows, columns, column groups, and row groups, the row(s) or column(s) are hidden and the space they would have occupied is removed (as if display: none were applied to the column/row of the table). However, the size of other rows and columns is still calculated as though the cells in the collapsed row(s) or column(s) are present. This value allows for the fast removal of a row or column from a table without forcing the recalculation of widths and heights for the entire table.

nemanja
  • 664
  • 5
  • 16
  • 1
    Thank you! I learned a lot. I didn't know about `justify-content`, so I assumed the only sane way to align labels and form fields with unknown widths was with `display: table`. And, of course, I never heard about `visibility: collapse`. That `visibility` option really surprised me :D. – Xilexio Dec 02 '18 at 06:16