Home > Back-end >  responsive grid template columns with fixed percentage width for one column and auto width for secon
responsive grid template columns with fixed percentage width for one column and auto width for secon

Time:10-27

How can I make a responsive grid that has 2 columns? One should take max 20% of the width and the other should take the rest of the width. This is the CSS that I have so far for that kind of row:

const StyledRow = styled.div`
  display: grid;
  grid-template-columns: 20% auto;
  align-items: center;
  margin-bottom: 15px;
`

And the html is this:

    <StyledRow>
      <label htmlFor="firstEmail" style={{justifySelf: 'end', paddingRight: 10}}>Email:</label>
      <Input id="firstEmail" type="email" value={firstEmail} onChange={handleChangeFirstEmail}/>
    </StyledRow>

This is not responsive, since on the small width screen the label is still in the same row as the input. How can I achieve that the second column goes under the first column. I have tried also with:

grid-template-columns: repeat(auto-fill, minmax(20%, 80%));

Then both columns take 80% of the width, so they end up one over another on big screens.

How can I achieve then that the first column is max 20% wide and the other takes up the rest, while being responsive on small screens?

CodePudding user response:

You can use the "fr" unit to take up a fraction of remaining space. So for your second column you use 1fr to take up 1 part of the remain space, or 100%. The fr unit will take into consideration the gaps you have between columns/rows.

grid-template-columns: 20% 1fr;

As for responsive for small screens use @media queries. https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries

@media screen and (max-width: 1024px) {
   grid-template-columns: 1fr;  
}

CodePudding user response:

body {
  padding: 2rem;
  margin: 0 auto;
  max-width: 60rem;
}

.container {
  display: flex;
  flex-wrap: wrap;
  --gutter: 1rem;
  margin: calc(var(--gutter) / 2 * -1);
  
  --breakpoint: 40rem;
  color:white;
}

.container > * {
  background-color: #000;
  min-width: clamp(var(--min-width, 0px), (var(--breakpoint) - 100%) * 999, 100% - var(--gutter));
  min-height: 20vh;
  margin: calc(var(--gutter) / 2);
}

.container > *:first-child {
 width:30%;
}


.container > *:nth-child(2) {
  flex-grow:1;
}
<div class="container">
  <div>One</div>
  <div>Two</div>
</div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

We provide a negative margin to the container to make up for the extra margin of the container child.
The min-width is the key to this approach. The middle value of the clamp acts as a switch to identify the breakpoints and exaggerate the effect, while the min and max values can have an effect according to the switch. So when the switch is on i.e. breakpoint is greater than 40rem, if we subtract 100%( width of parent), we get a positive number and we exaggerate it by multiplying by 999 so that the transition is not smooth but abrupt. Then max value of the clamp takes effect. And if we go to switch off i.e. negative, the min value of clamp is in effect.
I hope the rest of the code is self-explanatory.

  • Related