user17753
user17753

Reputation: 3161

Table Layout to CSS Layout how to work around colspan?

If I create a layout with tables like the old-school way:

input {
    width: 100%;    
    padding: 5px;
}
table {
    border-collapse: collapse;  
    padding: 0;
    margin: 0;
    width: 50%;
}
td {
    padding: 5px;
}
<table>
  <tr>
    <td colspan="3"><label>Label 1:</label></td>
  </tr>
  <tr>
    <td colspan="3"><input type="text" /></td>
  </tr>                               
  <tr>
    <td><label>Label 2:</label></td>
    <td>&nbsp;</td><td>
    <label>Label 3:</label></td>
  </tr>
  <tr>
    <td><input type="text" /></td>
    <td>&nbsp;</td>
    <td><input type="text" /></td>
  </tr>

  <tr>
    <td colspan="3"><label>Label 4:</label></td>
  </tr>
  <tr>
    <td colspan="3"><input type="text" /></td>
  </tr>

  <tr>
    <td colspan="3"><label>Label 5:</label></td>
  </tr>
  <tr>
    <td colspan="3"><input type="text" /></td>
  </tr>           
</table>

https://jsfiddle.net/njb69anL/

I get a layout where it is like a grid on the screen. It resizes to the width of the browser easily. Everything is spaced and placed correctly.

However, my html markup is full of table tags. If I wanted to rid myself of the table I'd start by making the markup semantic:

        <div id="grp">
            <label>Label 1:</label><input type="text" />
            <label>Label 2:</label><input type="text" />
            <label>Label 3:</label><input type="text" />
            <label>Label 4:</label><input type="text" />
            <label>Label 5:</label><input type="text" />            
        </div>

But is it even possible to achieve the same table-like layout with this little markup? It seems display: table cannot do colspan, and the trickiest part is having a row with two label,input pairs on the same row. Is it possible to achieve this without adding a whole bunch of wrapper divs and thus making the original markup messy (non-semantic) anyways?

Upvotes: 0

Views: 129

Answers (4)

orangeh0g
orangeh0g

Reputation: 428

* {
  box-sizing: border-box;
}

.labels-wrapper {
  display: flex;
  flex-wrap: wrap;
  width: 40%;
}

label {
  flex-basis: 100%;
  padding: 10px;
}
label:nth-child(2),
label:nth-child(3) {
  flex-basis: 50%;
}

input {
  margin-top: 5px;
  display: block;
  width: 100%;
}
<div class="labels-wrapper">
  <label>Label 1:
    <input type="text" />
  </label>
  <label>Label 2:
    <input type="text" />
  </label>
  <label>Label 3:
    <input type="text" />
  </label>
  <label>Label 4:
    <input type="text" />
  </label>
  <label>Label 5:
    <input type="text" />
  </label>
</div>

Adding flexbox example for an alternative. Please use the "full page" button to really get a feel for how it looks.

Upvotes: 1

Will B.
Will B.

Reputation: 18416

You would use css float or inline-block and width percentage to specify the amount of space each row element consumes.

EDITED CSS Version

Example: https://jsfiddle.net/njb69anL/3/

In order for this example to work, the label and input positions would need to be next to each other for them to appear on the same row. The end result is your markup looks like the display. Using nth-child allows you to specify which element in the list to apply your rule to.

HTML

<div id="grp">
  <label>Label 1:</label>
  <input type="text" />
  <label>Label 2:</label><label>Label 3:</label>
  <input type="text" /><input type="text" />
  <label>Label 4:</label>
  <input type="text" />
  <label>Label 5:</label>
  <input type="text" />            
</div>

CSS

*{
  box-sizing: border-box;
}

#grp {
  width: 50%;
}

input,
label {
  display: block;
  float: left;
  width: 100%;
  padding: 5px;
}

label:nth-child(3),
label:nth-child(4){
  width: 50%;
}

input:nth-child(5) {
  width: 49%;
}

input:nth-child(6) {
  width: 49%;
  margin-left: 2%;
}

For example: https://jsfiddle.net/njb69anL/2/

updated with a responsive layout

HTML

<form>
  <div class="full-row">
    <label>
      <span>Label 1:</span>
      <input type="text" />
    </label>
  </div>
  <div class="half-row">
    <label>
      <span>Label 2:</span>
      <input type="text" />
    </label>
  </div>
  <div class="half-row">
    <label>
      <span>Label 3:</span>
      <input type="text" />
    </label>
  </div>
  <div class="full-row">
    <label>
      <span>Label 4:</span>
      <input type="text" />
    </label>
  </div>
</form>

CSS

* {
  box-sizing: border-box;
}

form input{
  width: 100%;
  padding: 5px;
}

form {
  width: 80%;
  overflow: hidden;
}

form > div {
  float: left;
  padding: 5px;
}

.full-row {
  width: 100%;
}

.half-row {
  width: 50%;
}

label > span{
  display: block;
}

Upvotes: 0

kiaaanabal
kiaaanabal

Reputation: 384

This is definitely possible. I have created a fiddle for you. It's about the same amount of content, but it is definitely more easy to manipulate than a table.

I just use:

<wrapper>
    <row>
        <label></label>
        <input>
    </row>
</wrapper>

https://jsfiddle.net/Kiaaanabal/qv89yb56/

Upvotes: 0

Richard Parnaby-King
Richard Parnaby-King

Reputation: 14862

The only way to get it looking right using the html above is with position:absolute which to me feels like a hack. I have wrapped label 2 and label 3 in a div so they may be grouped together.

The below html / css gets very close to the fiddle:

#grp {
  width: 50%;
  white-space:nowrap;
}
#grp label,
#grp input {
  width:100%;
  display:block;
  clear:left;
}
#grp input {
  margin-bottom:1em;
}
#grp div {
  float:left;
  width:49%;
}
#grp div + div {
  margin-left:2%;
}
<div id="grp">
  <label>Label 1:</label><input type="text" />
  <div><label>Label 2:</label><input type="text" /></div>
  <div><label>Label 3:</label><input type="text" /></div>
  <label>Label 4:</label><input type="text" />
  <label>Label 5:</label><input type="text" />            
</div>

Upvotes: 0

Related Questions