Search code examples
htmlcssalignmentcss-grid

css-grid creates an imaginary column


I am creating a simple form, where I want to have this kind of layout

screenshot1

So far so good, very simple 2 columns with a nested 2 columns, all of them defined with 0.5fr which should be the half of "free-space" if I understood correctly.

But, if I try to reduce the screen, this happens. even if I have NO media queries.

screenshot2

if you debug with chrome devtools you can see it's creating a 3rd column from nowhere without any element. Any idea?

https://stackblitz.com/edit/js-zzm4gy?file=index.html

h1, h2 {
  font-family: Lato;
}


.form{
  border: 1px solid black;
  text-align: center;
  display: grid;
  grid-template-rows: 1fr;
  grid-gap: 1em;
}

.two-field{
  display: grid;
  grid-template-columns: 0.25fr 0.75fr;
}

/********************/
/* Four elements row*/
/********************/
.four-field{
  display: grid;
  grid-template-columns: 0.5fr 0.5fr;
}

.four-field .left{
  display: grid;
  grid-template-columns: 0.5fr 0.5fr;
}

.four-field .right{
  display: grid;
  grid-template-columns: 0.25fr 0.75fr;
}
/********************/
/********************/
/********************/

/********************/
/******Buttons*******/
/********************/
.buttons{
  display: grid;
  grid-template-columns: 0.25fr 0.75fr;
}

.button-column{
  display: grid;
  grid-template-columns: 0.5fr 0.5fr;
  grid-column-gap: 1em;
}
/********************/
/********************/
/********************/
<div id="app">
	<form class="form">
		<div class="two-field">
			<label>First name:</label>
      <input type="text" name="firstname">
    </div>

    <div class="four-field">
      <div class="left">
        <label>Postal code:</label>
        <input type="text" name="Postal code">
      </div>
      <div class="right">
        <label>Place:</label>
        <input type="text" name="Place" >
      </div>
    </div>

    <div class="two-field">
      <label>Phone</label>
      <input type="text" name="phone">
    </div>

    <div class="buttons">
      <div class="empty"></div>
      <div class="button-column">
        <button type="submit">Confirm</button>
        <button>Abort</button>
      </div>
    </div>
  </form>
</div>


Solution

  • The minimum size of a grid item is as much as its content; which means that min-width and min-height resolves to auto.

    To provide a more reasonable default minimum size for grid items, this specification defines that the auto value of min-width/min-height also applies an automatic minimum size in the specified axis to grid items whose overflow is visible and which span at least one track whose min track sizing function is auto.

    MDN

    And note that input elements have an instrinsic width. So here you can add min-width: 0 to input elements to fix the issue - see demo below:

    h1, h2 {
      font-family: Lato;
    }
    
    
    .form{
      border: 1px solid black;
      text-align: center;
      display: grid;
      grid-template-rows: 1fr;
      grid-gap: 1em;
    }
    
    input {
      min-width: 0; /* ADDED */
    }
    
    .two-field{
      display: grid;
      grid-template-columns: 0.25fr 0.75fr;
    }
    
    /********************/
    /* Four elements row*/
    /********************/
    .four-field{
      display: grid;
      grid-template-columns: 0.5fr 0.5fr;
    }
    
    .four-field .left{
      display: grid;
      grid-template-columns: 0.5fr 0.5fr;
    }
    
    .four-field .right{
      display: grid;
      grid-template-columns: 0.25fr 0.75fr;
    }
    /********************/
    /********************/
    /********************/
    
    /********************/
    /******Buttons*******/
    /********************/
    .buttons{
      display: grid;
      grid-template-columns: 0.25fr 0.75fr;
    }
    
    .button-column{
      display: grid;
      grid-template-columns: 0.5fr 0.5fr;
      grid-column-gap: 1em;
    }
    /********************/
    /********************/
    /********************/
    <div id="app">
    	<form class="form">
    		<div class="two-field">
    			<label>First name:</label>
          <input type="text" name="firstname">
        </div>
    
        <div class="four-field">
          <div class="left">
            <label>Postal code:</label>
            <input type="text" name="Postal code">
          </div>
          <div class="right">
            <label>Place:</label>
            <input type="text" name="Place" >
          </div>
        </div>
    
        <div class="two-field">
          <label>Phone</label>
          <input type="text" name="phone">
        </div>
    
        <div class="buttons">
          <div class="empty"></div>
          <div class="button-column">
            <button type="submit">Confirm</button>
            <button>Abort</button>
          </div>
        </div>
      </form>
    </div>


    Suggestion

    But there is no need for a lot of nesting here (I am suggesting a change in markup here) - you can make this work in a simple 4-column grid layout like below:

    .form {
      border: 1px solid black;
      text-align: center;
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      grid-gap: 1em;
      padding: 10px;
    }
    
    input {
      min-width: 0;
    }
    
    input[name=firstname],
    input[name=phone] {
      grid-column: span 3;
    }
    
    .button-column {
      grid-column: 2 / 5;
      display: grid;
      grid-template-columns: 1fr 1fr;
      grid-gap: 1em;
    }
    <div id="app">
      <form class="form">
        <label>First name:</label>
        <input type="text" name="firstname">
        <label>Postal code:</label>
        <input type="text" name="Postal code">
        <label>Place:</label>
        <input type="text" name="Place">
        <label>Phone</label>
        <input type="text" name="phone">
        <div class="button-column">
          <button type="submit">Confirm</button>
          <button>Abort</button>
        </div>
      </form>
    </div>