0

I want to recreate the same design as the second image below using CSS grid. I got a problem with the alignment, of course because of the two spans the inputs are not aligned like they should be. I am almost there with CSS grid but i can't figure it out. Is there a way to do it with grid or is there another solution for this?

Render in react Adobe xd design

 <div className="grade-card">
            <div className="grade-card-header">
                <span className="title">{this.props.title}</span>
            </div>
            <div className="grade-card-body">
                <div className="grade-input">
                    <span>I</span>
                    <input type="text"/>
                    <span>1x</span>
                </div>
                <div className="grade-input">
                    <span>I</span>
                    <input type="text"/>
                    <span>Min</span>
                </div>
                <div className="grade-input">
                    <span>I</span>
                    <input type="text"/>
                    <span>1x</span>
                </div>
                <div className="grade-input">
                    <span>I</span>
                    <input type="text"/>
                </div>
                <div className="grade-input">
                    <span>I</span>
                    <input type="text"/>
                </div>
                <div className="grade-input">
                    <input type="text"/>
                </div>
            </div>
        </div>
.grade-card{
  width: 349px;
  height: 384px;
  background-color: white;
  border-radius: 28px;

  .grade-card-header{
    display: flex;
    align-items: center;
    justify-content: center;
    height: 20%;
    border-radius: 28px 28px 0 0;
    background-color: #1089FF;

    .title{

      color: white;
      font-size: 1.5em;
    }
  }

  .grade-card-body{
    height: 80%;
    cursor: pointer;
    display: grid;
    grid-template-columns: repeat(2, 174.5px);
    grid-template-rows: repeat(3, 102.4px);
    justify-items: center;//horizontally
    align-items: center;//vertically

    input{
      outline: none;
      width: 74px;
      height: 51px;
      border: 1px solid #707070;
      border-radius: 6px;
      font-size: 1.3em;
      text-align: center;
    }

    .grade-input:last-child{
      input{
        width: 117px;
        height: 69px;
      }
    } 
  }
}
Arton Hoxha
  • 343
  • 3
  • 12

2 Answers2

1

This is a little of a variation on @Brice's answer, because in his version:

  1. you need to adjust for each variation of the label text
  2. if the font is rendered different, it will break (zoom, differences between platforms, etc).

This version solves it, but the idea to use absolute positioning to escape the flow is the same.

/*********** begin changes **********/

.grade-input {
  position: relative;
}

.label {
  position: absolute;
  top: 50%;
}

.label-left {
  transform: translate(calc(-100% - 6px), -50%);
}

.label-right {
  transform: translate(6px, -50%);
}

/*********** end changes **********/


.grade-card {
  width: 349px;
  height: 384px;
  background-color: white;
  border-radius: 28px;
}

.grade-card .grade-card-header {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 20%;
  border-radius: 28px 28px 0 0;
  background-color: #1089ff;
}

.grade-card .grade-card-header .title {
  color: white;
  font-size: 1.5em;
}

.grade-card .grade-card-body {
  height: 80%;
  cursor: pointer;
  display: grid;
  grid-template-columns: repeat(2, 174.5px);
  grid-template-rows: repeat(3, 102.4px);
  justify-items: center;
  align-items: center;
}

.grade-card .grade-card-body input {
  outline: none;
  width: 74px;
  height: 51px;
  border: 1px solid #707070;
  border-radius: 6px;
  font-size: 1.3em;
  text-align: center;
}

.grade-card .grade-card-body .grade-input:last-child input {
  width: 117px;
  height: 69px;
}
<div class="grade-card">
  <div class="grade-card-header">
    <span class="title">{this.props.title}</span>
  </div>

  <div class="grade-card-body">
    <div class="grade-input">
      <span class="label label-left">I</span>
      <input type="text"/>
      <span class="label label-right">1x</span>
    </div>

    <div class="grade-input">
      <span class="label label-left">I</span>
      <input type="text"/>
      <span class="label label-right">Min</span>
    </div>

    <div class="grade-input">
      <span class="label label-left">I</span>
      <input type="text"/>
      <span class="label label-right">1x</span>
    </div>

    <div class="grade-input">
      <span class="label label-left">I</span>
      <input type="text"/>
    </div>

    <div class="grade-input">
      <span class="label label-left">I</span>
      <input type="text"/>
    </div>
    <div class="grade-input">
      <input type="text"/>
    </div>
  </div>
</div>
Henrique Erzinger
  • 1,077
  • 8
  • 17
0

Because the spans are different values, your .grade-input divs are becoming different widths and that is throwing off your alignment.

EDITED to get inputs aligned exactly centered:

If you make the spans position: absolute;, then you would be able to just align the inputs.

Try below HTML:

<div className="grade-card">
        <div className="grade-card-header">
            <span className="title">{this.props.title}</span>
        </div>
        <div className="grade-card-body">
            <div className="grade-input">
                <span className="left-absolute">I</span>
                <input type="text"/>
                <span className="right-absolute oneX">1x</span>
            </div>
            <div className="grade-input">
                <span className="left-absolute">I</span>
                <input type="text"/>
                <span className="right-absolute min">Min</span>
            </div>
            <div className="grade-input">
                <span className="left-absolute">I</span>
                <input type="text"/>
                <span className="right-absolute oneX">1x</span>
            </div>
            <div className="grade-input">
                <span className="left-absolute">I</span>
                <input type="text"/>
            </div>
            <div className="grade-input">
                <span className="left-absolute">I</span>
                <input type="text"/>
            </div>
            <div className="grade-input">
                <input type="text"/>
            </div>
        </div>
    </div>

Add below to your css file:

.grade-input {
  position: relative;
}

.left-absolute {
    position: absolute;
    left: -7px;
    top: 20px;
}

.right-absolute.oneX {
    position: absolute;
    right: -15px;
    top: 20px;
}
.right-absolute.min {
    position: absolute;
    right: -27px;
    top: 20px;
}
Brice
  • 86
  • 4
  • It works for the first column but the second is still not aligned. I can fix it with some padding but is there another way to handle this? – Arton Hoxha Oct 18 '19 at 06:57
  • I edited the answer based on your comment. Let me know if that works for you. – Brice Oct 18 '19 at 13:04
  • Thanks Brice this works perfect and it think the solution from @Henrique Erzinger is a bit better because it is more dynamic – Arton Hoxha Oct 19 '19 at 22:40