Balaji V
Balaji V

Reputation: 109

Dynamic Responsive Forms using css

I'm trying to create a User Entry Form with multiple fields/values in a table format. If its a desktop, it should show 6 columns (a pair of field name/value each) and if its a phone (portrait mode) should show just 2. If it's in landscape show 4 columns.

Expected output: Phone (Portrait)

+--------+---------+
+  Field + Value   +
+--------+---------+
+  Field + Value   +
+--------+---------+
+  Field + Value   +
+--------+---------+

Phone (Landscape mode)

+--------+---------+--------+---------+
+  Field + Value   +  Field + Value   +
+--------+---------+--------+---------+
+  Field + Value   +  Field + Value   +
+--------+---------+--------+---------+
+  Field + Value   +  Field + Value   +
+--------+---------+--------+---------+

iPad or larger

+--------+---------+--------+---------+--------+---------+--------+---------+
+  Field + Value   +  Field + Value   +  Field + Value   +  Field + Value   +
+--------+---------+--------+---------+--------+---------+--------+---------+
+  Field + Value   +  Field + Value   +  Field + Value   +  Field + Value   +
+--------+---------+--------+---------+--------+---------+--------+---------+

I want it to be pure CSS (as much as possible) as the content will be filled by an angular constructor later.

However, I'm not getting the correct flow as the divs seem to stick together and not break away clean as a row! Probably I'm missing something here. It works fine in the phone portrait mode but as you can see in the pen below, it's all over the place.

Code Pen: Link

Here is the code so far:

            <div class='table-type'>
            <div class='row-type'>
                <div class='cell-type'>Account</div>
                <div class='cell-type'>Acme Incorporated US and Seychelles</div>
                <div class='cell-type'>Geography</div>
                <div class='cell-type'>North America</div>
                <div class='cell-type'>Premier</div>
                <div class='cell-type'>Yes</div>
                <div class='cell-type'>Countact Count</div>
                <div class='cell-type'>23</div>
                <div class='cell-type'>Account Manager</div>
                <div class='cell-type'>Dustin Brown</div>
                <div class='cell-type'>Customer Engineer</div>
                <div class='cell-type'>David Hoff</div>
                <div class='cell-type'>Exec Sponsor</div>
                <div class='cell-type'>Jeff Larabee</div>
            </div>
        </div>

Now the CSS:

    .table-type
{
    display: table;
    margin-bottom: 5px;
    width:100%;
    table-layout: fixed;
}
.row-type
{
    display: table-row;
}
.cell-type
{
    float: left;
    margin-top: 2px;
    margin-bottom: 2px;
    padding: 5px;
    line-height: 16px;
    font-family: 'Lato', sans-serif;
    border: 4px solid;
    border-color: #fff;
    border-radius: 15px;
    border-spacing: 15px 15px;
}
.cell-type:nth-child(odd)
{
    text-align: right;
}
.cell-type:nth-child(even)
{
    text-align:left;
    font-weight: bold;
    -webkit-border-radius:15px;-moz-border-radius:15px;
    background-color: #e3f2f2;
}
@media (max-width: 500px)
{
    .cell-type:nth-child(3n+3)
    {
        display: block;
    }
    .cell-type:nth-child(odd)
    {
        width:30%;
    }
    .cell-type:nth-child(even)
    {
        width:70%;
    }
}
@media (max-width: 700px) and (min-width: 501px)
{

    .cell-type:nth-child(odd)
    {
        width:20%;
    }
    .cell-type:nth-child(even)
    {
        width:30%;
    }
    .cell-type:nth-child(5n+5)
    {
        display: block;
    }
}
@media (min-width: 701px)
{
    .cell-type:nth-child(odd)
    {
        width:13%;
    }
    .cell-type:nth-child(even)
    {
        width:20%;
    }
    .cell-type:nth-child(7n+7)
    {
        display: block;
    }

}

Upvotes: 1

Views: 840

Answers (2)

tao
tao

Reputation: 90287

I think it will be easier to achieve desired outcome using flexbox:

.row-type {
  display: flex;
  flex-wrap: wrap;
}
.cell-type {
  flex: 0 0 10% 
  /* translates to: flex-grow: 0;
   *                flex-shrink: 0;
   *                flex-basis: 10%;
   */
}
.cell-type:nth-child(even) {
  flex-basis: 15%; 
  /* 10% + 15% = 25% */
}

But the first problem you need fixing is to apply box-sizing:border-box to all your cells. This will change the way padding and border are taken into account, to be included in the width property (or flex-basis for flexbox), so you don't have to set percentages and deduct padding and border sizes.

Then, it's just a matter of laying out correct sizes of your cells based on parent width. In order to do it, pick a direction (from large to small or from small to large). I picked from large to small below, but doing it from small to large works as well.

Write the rules for your first picked interval outside of any @media query before the @media queries (this is important because the selectors inside your @media queries will have equal specificity to ones outside and the rules inside @media will apply solely on the fact they are placed later in CSS).
Remember: @media queries do not change specificity. They only set whether or not the rules inside apply based on the provided condition. So the rules set before the @media queries will only apply when none of your subsequent @media queries (overriding them) are true.

Then, using the same exact selectors, write your rules for the next interval, inside the appropriate @media rule and continue until you get to the last @media rule. You only need to overwrite the property that changes, which in this case is flex-basis. In the case of tables it would be width.

I also happen to believe your breakpoints are a bit off, as 700px and 500px are way too low as breaking points for your table (I decided to break them from 8 to 6/row at 1200px, from 6 to 4/row at 950px and from 4 to 2/row at 650px). Feel free to disagree and adjust them according to your own needs and liking.

Here it is:

.table-type {
  margin-bottom: 5px;
  width: 100%;
}

.row-type {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch; /* you might also try `center` here */
}

.cell-type {
  display: block;
  flex: 0 0 10%;
  margin: 3px 0;
  padding: 7px 12px;
  line-height: 16px;
  min-height: 46px; /* added for equal height cells. removed on mobile */
  font-family: 'Lato', sans-serif;
  border-radius: 16px;
  box-sizing: border-box;
}

.cell-type:nth-child(odd) {
  text-align: right;
}

.cell-type:nth-child(even) {
  flex-basis: 15%;
  font-weight: bold;
  background-color: #eaf5f5;
  box-shadow: inset 0 1px 3px rgba(0,0,0,.06), inset 0 1px 1px rgba(0,0,0,.04), inset 0 2px 1px rgba(0,0,0,.03)
}

@media(max-width: 1200px) {
  .cell-type:nth-child(odd) {
    flex-basis: 13.3333%;
  }
  .cell-type:nth-child(even) {
    flex-basis: 20%;
  }
}

@media(max-width: 950px) {
  .cell-type:nth-child(odd) {
    flex-basis: 20%;
  }
  .cell-type:nth-child(even) {
    flex-basis: 30%;
  }
}

@media(max-width: 650px) {
  .cell-type {
    min-height:0;
  }
  .cell-type:nth-child(odd) {
    flex-basis: 40%;
  }
  .cell-type:nth-child(even) {
    flex-basis: 60%;
  }
}
<div class='table-type'>
  <div class='row-type'>
    <div class='cell-type'>Account</div>
    <div class='cell-type'>Acme Incorporated US and Seychelles</div>
    <div class='cell-type'>Geography</div>
    <div class='cell-type'>North America</div>
    <div class='cell-type'>Premier</div>
    <div class='cell-type'>Yes</div>
    <div class='cell-type'>Countact Count</div>
    <div class='cell-type'>23</div>
    <div class='cell-type'>Account Manager</div>
    <div class='cell-type'>Dustin Brown</div>
    <div class='cell-type'>Customer Engineer</div>
    <div class='cell-type'>David Hoff</div>
    <div class='cell-type'>Exec Sponsor</div>
    <div class='cell-type'>Jeff Larabee</div>
  </div>
</div>


This can also be achieved with box model (using floats). Do note display:table (and it's related props for sub-elements) and box-model do not play nice together. And by that I mean: to make cells wrap where you want them, you need either one of:

  • actually wrap the cells of a single row inside one distinct DOM element with display:table-row (that's how table model works).
  • use floats (box-model) by setting display:block on both row and cell and float:left on cells. This technique also needs clearing after correct end of row cell, to avoid cells floating at the wrong position when you have height differences between cells.

Upvotes: 1

Smollet777
Smollet777

Reputation: 1646

Is this what you want?

.row-type
{
    display: grid;
    justify-items: center;
    align-items: center;
}
...
@media (max-width: 500px)
{ 
    .row-type{
      grid-template-columns: repeat(2,1fr);
    }
}
@media (max-width: 700px) and (min-width: 501px)
{
    .row-type{
      grid-template-columns: repeat(4,1fr);
    }
}
@media (min-width: 701px)
{   
    .row-type{
    grid-template-columns: repeat(8,1fr);
    }
}

https://codepen.io/smollet777/pen/mzypJo?editors=0100

Upvotes: 1

Related Questions