Avoid filling the container with an excessive amount of grids while maintaining the correct aspect ratio

I encountered a situation where I needed to dynamically create a grid with square grids of dimensions MxN. Below is the code snippet for achieving this:

rerender = (event) => {
  const height = document.getElementById("y-input").value;
  const width = document.getElementById("x-input").value;

  console.log(`${height} :: ${width}`);

  const cellContainer = document.getElementById("cell-container");

  cellContainer.style.gridTemplateRows = `repeat(${height}, 1fr)`;
  cellContainer.style.gridTemplateColumns = `repeat(${width}, 1fr)`;

  cellContainer.innerHTML = "";
  [...Array(height * width).keys()]
    .map(() => document.createElement('div'))
    .map((e) => {
      e.className = "cell";
      return e
    })
    .map((e) => cellContainer.appendChild(e))
}
#grid-container {
  width: 500px;
  height: 500px;
  background-color: aqua;
  padding: 8px;
}

#cell-container {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: repeat(2, 1fr);
}

.cell {
  background-color: blue;
  min-width: 4px;
  min-height: 4px;
  margin: 1px;
  aspect-ratio: 1/1;
}
<div>
  <label for="x-input">width</label>
  <input value=2 min=1 max=50 type="number" name="x" id="x-input" style="width: 4ch;" onchange="rerender(event)">
  <label for="y-input">height</label>
  <input value=2 min=1 max=50 type="number" name="y" id="y-input" style="width: 4ch;" onchange="rerender(event)">
</div>

<div id="grid-container">
  <div id="cell-container">
    <div class="cell"></div>
    <div class="cell"></div>
    <div class="cell"></div>
    <div class="cell"></div>
  </div>
</div>

I am utilizing a grid layout where the number of rows and columns can be adjusted dynamically using the following code:

cellContainer.style.gridTemplateRows = `repeat(${height}, 1fr)`;
cellContainer.style.gridTemplateColumns = `repeat(${width}, 1fr)`;

The cells are kept square by using the aspect-ratio property. This approach works well for square grids and also when dealing with rectangular cases where the width is greater than the height.

In cases where the height is greater than the width (rectangular), there is an overflow issue. How can this overflow be prevented?

View Example Here

https://i.sstatic.net/Y56mm.png

Answer №1

Summary

To solve this problem where everything is a square, we can use fake rows and columns to properly size the cells. The solution is provided at the end of this post.

Explanation

Problem Overview

From what I gather, the requirement is to have

  • a grid of W×H cells
  • fitting within an N×N pixels square
  • where each cell is a square

Current Working State

In the scenario where you have a working solution, like say W=3; H=2, the output resembles this:

https://i.sstatic.net/HX7Pu.png

CSS Refactoring Approach

Assuming we aim for a pure-CSS solution, the plan is to modify the JS to provide CSS custom properties and then continue with CSS reasoning:

  • setting --per-row as the number of cells in a row,
  • setting --per-col as the number of cells in a column.
grid.style.setProperty('--per-row', width);
grid.style.setProperty('--per-col', height);
#grid {
  --per-row: 2;
  --per-col: 2;
  grid-template-columns: repeat(var(--per-row), 1fr);
  grid-template-rows: repeat(var(--per-col), 1fr);
}

PS: irrelevant lines have been omitted from code snippets.

Addressing the Problem

The issue arises when H > W, as seen in the W=2; H=3 example. The goal is to achieve proper grid alignment. To resolve this, we utilize the CSS max() function:

#grid {
  --per-row: 2;
  --per-col: 2;
  --max: max(var(--per-row), var(--per-col));
  grid-template-columns: repeat(var(--max), 1fr);
  grid-template-rows: repeat(var(--max), 1fr);
}
...

Solution

Below is your original code with the modifications described in this post.

rerender = (event) => {
  const height = document.getElementById("y-input").value;
  const width = document.getElementById("x-input").value;
  const grid = document.getElementById("grid");

  grid.style.setProperty('--per-row', width);
  grid.style.setProperty('--max', Math.max(width, height));

  grid.innerHTML = "";
  [...Array(height * width).keys()]
    .forEach(() => {
      const e = document.createElement('div')
      e.className = "cell";
      grid.appendChild(e)
    })
}
#container {
  width: 500px;
  height: 500px;
  background-color: aqua;
  padding: 8px;
}

#grid {
  display: grid;
  height: 100%;
  --per-row: 2;
  --max: 2;
  grid-template-columns: repeat(var(--per-row), calc(100% / var(--max)));
  grid-auto-rows: calc(100% / var(--max));
  gap: 2px;
}

.cell {
  background-color: blue;
  aspect-ratio: 1/1;
}
<div>
  <label for="x-input">width</label>
  <input value=2 min=1 max=50 type="number" name="x" id="x-input" style="width: 4ch;" onchange="rerender(event)">
  <label for="y-input">height</label>
  <input value=2 min=1 max=50 type="number" name="y" id="y-input" style="width: 4ch;" onchange="rerender(event)">
</div>

<div id="container">
  <div id="grid">
    <div class="cell"></div>
    <div class="cell"></div>
    <div class="cell"></div>
    <div class="cell"></div>
  </div>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The x-axis in c3.js is experiencing issues with plotting when there is interval data in DST time

Trying to create a graph using the c3.js library with an x-axis interval of time. The intervals are determined by selecting a date range in the date picker. For example, if we select the dates 2016-03-13 00:00 to 2016-03-13 04:00, we add 15 minutes to ...

Emphasize rows in the MUI-Datatables framework

A table was created using React.js and MUI-Datatables: import MUIDataTable from "mui-datatables"; const columns = ["Name", "Company", "City", "State"]; const data = [ ["Joe James", "Test Corp", "Yonkers", "NY"], ["John Walsh", "Test Corp", "Hartford", ...

Obtaining Data from an Array with Reactive Forms in Angular 4

Just starting out with Angular 4 and trying to figure out how to populate input fields with information based on the selection made in a dropdown. <select formControlName="selectCar" class="form-field"> <option value="">Choose a car&l ...

The Angular $http.jsonp() function can only be executed one time

Upon the first response being successful (alert->done), any subsequent hits will result in an 'error' response. I attempted to resolve this issue by adding some config parameters with 'cache: false', but it still only works the firs ...

Tips for creating a horizontal list within a collapsible card

When a user clicks on a button, I am dynamically populating a list of items. Despite using list-group-horizontal, I am unable to make it display horizontally. HTML code <div id="textarea_display" class="mt-2 "> <label&g ...

Creating a nested list component using an array of objects

Seeking guidance for a coding task I recently completed. I was tasked with creating a multiple nested list from an array of objects. While I achieved the expected result, my code ended up being overly complicated and not very clean. I used a combination of ...

Issues with IE7 related to Jquery and potentially HTML as well

I am currently working on a website project for a local charity organization, and I am encountering technical issues with compatibility in IE7. The website functions perfectly in all other browsers I have tested, and it even passes the validation process o ...

Adding a personalized service into a separate service within Angular 2

I am having trouble injecting my own service into another service. While I can inject standard Angular services like Http without any issues, attempting to inject custom services results in an exception. For example, here is how MyService is set up: impo ...

Can you provide guidance on showcasing mongodb data in a flask template with flask_pymongo?

Apologies if my question seems a bit unclear. I am struggling to display data from MongoDB in a Flask template. The code I have currently isn't working as expected. Here's what I've attempted so far: (I tried to get creative) @app.route(&apo ...

Is it possible to continuously generate webpages using AJAX?

Is there a way to achieve an infinite scrolling effect in all directions using ajax requests without the need for flash or silverlight? If anyone has an example of this, I would love to see it! Thank you for your time. ...

there is no minimum height specified for the table

Hey there! I'm working on a dynamic table that I populate using data from my API. However, I'm facing an issue where I want the table to maintain a minimum height when there are only a few results, but I can't seem to make it work. I attemp ...

The modal appears on the screen prior to the content being shown

While attempting to render a bootstrap modal with content from a REST call, I am encountering an issue where the modal appears before the content has finished populating. The modal is triggered by a button click event. If I click the button again after wa ...

Inquiry about how TypeScript handles object property references when passed into functions

As a newcomer to TypeScript, I am exploring the creation of a range slider with dual handles using D3.js. I have developed a simple class for managing the slider objects: export class VerticalRangeSlider{ private sliderContainer: d3.Selection<SVGG ...

Make sure to deselect all other radio buttons when selecting one, running into difficulties

Having an issue with my UI when selecting radio buttons by clicking on a div: A loop that displays different radio buttons: {% for product in collections.regalos.products %} <li class="grid__item large--one-third gift-card"> <div class="gift-s ...

variable containing a combination of left-to-right and right-to-left characters

I am working on a piece of text which contains Hebrew (rtl) and English (ltr) letters. It is a song with chords placed above the words. The issue I am facing has to do with the chords - because the site is rtl, the chords appear messy. Is there a way to h ...

What is the best way to assign a single class from an array to every list item in a particular sequence?

html <ul class="logoUl"> <li class="orange"></li> <li class="blue"></li> <li class="green"></li> <li class="pink"></li> </ul> SCRIPT if (selectedCategory == 'currentAll&apo ...

Activate the toggle menu

Hi there! I'm currently working on a menu and I want the clicked item to become active, switching the active state to another item when clicked. However, my current implementation is not working as expected. Any assistance would be greatly appreciated ...

The SourceMap in DevTools encountered a parsing error with the message: "chrome-extension

It's been about a week since I first noticed warning messages appearing in my Google Chrome console. https://i.sstatic.net/Aurgz.png Clearing the cache hasn't made a difference; the messages only vanish when in incognito mode. Any suggestio ...

Managing varied PHP submissions using a single 'isset' declaration

I'm working on loading data from a MySQL database with PHP and displaying images in HTML. When a specific image is clicked, I want to show text associated with that image using MySQL/PHP. I'm looking for a way to achieve this without having multi ...

Skipping the validation of a variable in a return statement with Angular and Javascript

Is there a way to exclude level a.3 from the return in the completion form if a.3 is undefined? scope.isValid = function() { return a.1 && a.2 && a.3; }; ng-disabled="!isValid()" ...