Akash
Akash

Reputation: 834

Fix/Improve Responsive CSS Grid

I'm building an app that needs a grid system, here's how far I've come:

enter image description here

I have a problem: Each of the blocks should fill up the entire space of the grid

As you can see, the black block is not occupying the rest of the space. I want the boxes to occupy the rest white space(but all their widths should be the same).

I've read Expand a div to fill the remaining width and Make last element take remaining width with wrapping (and with IE9 support), but they don't answer the case of the dynamically wrapping grid that is here the important part since they are made for float and display: block.

Now let's look at the code:

HTML:

<div className='container'>
 <div className="item"></div>
 <div className="item"></div>
 <div className="item"></div>
 <div className="item"></div>
 <div className="item"></div>
 <div className="item"></div>
 <div className="item"></div>           
</div>

CSS:

    container {
        overflow: hidden;
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    }


    .item {
    height: 300px;
    min-width: 300px;
    background-color: red;
    border: 2px solid yellow;
 }

.container is the grid parent and .items are the children. Keep in mind that the solution should work with any number of children(.item). Thank you in advance!

Upvotes: 1

Views: 95

Answers (1)

biberman
biberman

Reputation: 5767

I think with plain css this is not possible using grid. You could use flexbox with flex-grow instead of grid but when two items wrap in the next line they both are expanded.

Working example (a bit smaller then your example):

I don't know what that className attribute in your divs is for, i presume you meant just "class" and used that, respectively an id in the container for simplicity.

#container {
  overflow: hidden;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
}

.item {
  height: 120px;
  min-width: 120px;
  background-color: red;
  border: 2px solid yellow;
  flex-grow: 1;
}

#last {
  flex-grow: 2;
}
<div id='container'>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item" id="last"></div>
</div>


If it is important to use grid it can be done with a small javascript function. Find out how many columns the grid has and in which column the item starts and set its gridColumnStart and gridColumnEnd so that it uses all the remaining grid areas. For beeing responsive you have to add an event listener that reacts on resize and calls the expand function.

Working example:

const container = document.querySelector('#container');
const last_item = document.querySelector('#last');

function expandLastItem() {
  const container_style = window.getComputedStyle(container);
  const item_style = window.getComputedStyle(last_item);
  const offset_left = last_item.offsetLeft;
  const grid_width = parseInt(container_style.width);
  const item_width = parseInt(item_style.width);
  const row_length = Math.floor(grid_width / item_width);
  const grid_column = Math.floor(offset_left / item_width) + 1;

  last_item.style.gridColumnStart = grid_column;
  last_item.style.gridColumnEnd = row_length + 1;
}

window.addEventListener('resize', function() {
  last_item.style.gridColumnStart = '';
  last_item.style.gridColumnEnd = '';
  expandLastItem();
});

expandLastItem();
#container {
  overflow: hidden;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
}

.item {
  height: 120px;
  min-width: 120px;
  background-color: red;
  border: 2px solid yellow;
}
<div id='container'>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item" id="last"></div>
</div>


If you are using jQuery the code gets a bit simpler.

Working example:

function expandLastItem() {
  const offset_left = $('#last').offset().left;
  const grid_width = parseInt($('#container').width());
  const item_width = parseInt($('#last').width());
  const row_length = Math.floor(grid_width / item_width);
  const grid_column = Math.floor(offset_left / item_width) + 1;

  $('#last')[0].style.gridColumnStart = grid_column;
  $('#last')[0].style.gridColumnEnd = row_length + 1;
}

$(window).on('resize', function() {
  $('#last')[0].style.gridColumnStart = '';
  $('#last')[0].style.gridColumnEnd = '';
  expandLastItem();
});

expandLastItem();
#container {
  overflow: hidden;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
}

.item {
  height: 120px;
  min-width: 120px;
  background-color: red;
  border: 2px solid yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id='container'>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item" id="last"></div>
</div>

Upvotes: 1

Related Questions