CSS: Strategies for eliminating empty cells within a grid layout by filtering out rows that contain partial or incomplete content

I am in need of creating a grid layout where each div is a specific width, and the number of rows depends on how many items there are. The twist is that I am unsure of the width of the outer container. My initial solution was to use CSS grid:

#container {
  resize: both;
  overflow: auto;
  width: 170px;

  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(50px, 1fr));
  
}

#container div {
  border: 1px solid red;
}
<div id="container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
</div>

However, my challenge now is to eliminate any empty cells in the grid for aesthetic reasons. To achieve this, I want to hide all elements on the last row, similar to the image below:

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

This scenario with fitting three columns into the grid serves as only one example of the issue. If five columns can fit into the grid, then I aim to remove all items from the second row.

Is there a way to accomplish this using CSS without manually adding breakpoints or hiding items? Alternatively, could JavaScript provide a solution?

Please note that while I used css display:grid in my demonstration, it is not mandatory - my main goal is achieving a grid-like appearance.

Answer №1

This task cannot be accomplished using CSS alone. One approach could involve organizing the HTML into separate rows like this:

<div class="row">
    <div class="cell">1</div>
    <div class="cell">2</div>
    <div class="cell">3</div>
</div>
<div class="row">
    <div class="cell">4</div>
    <div class="cell">5</div>
    <div class="cell">6</div>
</div>
<div class="row">
    <div class="cell"></div>
    <div class="cell">7</div>
    <div class="cell">8</div>
</div>

Ensure that the first cell in each row is intentionally left empty. Then you can utilize CSS selectors with pseudo-class :empty and general sibling selector ~

.row {
  display: block;
}

.cell {
  display: inline-block;
  width: 70px;
  height: 25px;
  background: yellow;
}

.cell:empty,
.cell:empty ~ .cell {
  display: none;
}
<div class="row">
    <div class="cell">1</div>
    <div class="cell">2</div>
    <div class="cell">3</div>
</div>
<div class="row">
    <div class="cell">4</div>
    <div class="cell">5</div>
    <div class="cell">6</div>
</div>
<div class="row">
    <div class="cell"></div>
    <div class="cell">7</div>
    <div class="cell">8</div>
</div>

Alternatively, JavaScript can be used for this purpose which would be relatively straightforward.

const hideRowIfAnyCellEmpty = () => {
  const rows = document.querySelectorAll('.row');
  rows.forEach((row) => {
    if (hasRowEmptyCell(row)){
      row.classList.add('has-empty-cell');
    }
  });
}

const hasRowEmptyCell = (row) => {
  return row.querySelectorAll('.cell:empty').length;
};

hideRowIfAnyCellEmpty();
.row {
  display: block;
}

.row.has-empty-cell {
  display: none;
}

.cell {
  display: inline-block;
  width: 70px;
  height: 25px;
  background: yellow;
}
<div class="row">
    <div class="cell">1</div>
    <div class="cell">2</div>
    <div class="cell">3</div>
</div>
<div class="row">
    <div class="cell">4</div>
    <div class="cell">5</div>
    <div class="cell">6</div>
</div>
<div class="row">
    <div class="cell"></div>
    <div class="cell">7</div>
    <div class="cell">8</div>
</div>

Answer №2

Try this clever trick: include a pseudo element to conceal unwanted elements. The downside is that you may lose transparency and the element might not align perfectly with the container's height.

#container {
  resize: both;
  overflow: hidden;
  width: 170px;

  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(50px, 1fr));
  
}

#container div {
  border: 1px solid red;
}

#container:after {
  content:"";
  background:#fff;
  margin-left:-100vw;
  margin-right:20px;
  
}
<div id="container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
</div>

Answer №3

After realizing that achieving the desired result solely with CSS was not feasible, I made the decision to tackle the issue using JavaScript instead:

var cg = document.getElementById('container');

var style = document.createElement('style');
document.head.appendChild(style);

var hideHalfEmptyColumns = function() {
  // Calculating the number of columns
  var columns = Math.floor(cg.offsetWidth / 50);
  // Determining the number of visible elements
  var elements = cg.childElementCount;
  // Finding the total cells on completely filled rows
  var elementsToShow = columns * Math.floor(elements / columns);
  style.innerHTML = `
            #container>div:nth-child(n + ${elementsToShow+1}) {
                display: none;
            }`;
}

// Ideally this function should also run on window resize event in a real-world scenario, but since elements lack this functionality, the example is somewhat flawed
hideHalfEmptyColumns();
#container {
  resize: both;
  overflow: auto;
  width: 170px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(50px, 1fr));
}

#container div {
  border: 1px solid red;
}
<div id="container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</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

Get rid of the folder from the URL using an <a> tag

I have both an English and French version of my website located at: *website.com/fr/index.php *website.com/index.php Currently, I have a direct link to switch between the two versions: -website.com/fr/index.php -website.com/index.php. However, I ...

Avoiding duplicate touch events with an if statement

I am currently working on a module for a responsive website that involves tapping the initial screen to reveal a panel from the right. The user can then tap a close button to hide the panel. However, there is an issue where if the user taps multiple times ...

Basic AngularJS framework with minimal external dependencies

I have been searching for an AngularJS skeleton to set up my project, but it seems like all the skeletons I find online require the installation of numerous dependencies through npm and/or bower. Due to security concerns at the firm where I am working on ...

parsing a TypeScript query

Is there a simpler way to convert a query string into an object while preserving the respective data types? Let me provide some context: I utilize a table from an external service that generates filters as I add them. The challenge arises when I need to en ...

Retrieving the link to share for every video located in the Dropbox folder

My Dropbox folder contains a set of videos labeled "v1.avi, v2.avi, ....., vn.avi". I am looking to automate the process of extracting the share link for each video in the folder so that I can easily use it as a source value for HTML video. . . . Is ther ...

Storing a jquery ajax response for faster retrieval in javascript/browser

Is there a way to implement caching for ajax responses in JavaScript or the browser? According to the jquery.ajax documentation: The default behavior is that requests are always issued, but the browser may serve results from its cache. To prevent the ...

Issue with Submit Button Functionality following an Ajax Request

I am facing an issue where the submit button does not work after an ajax call, but works fine if I reload the page. The problem arises when a modal is displayed for email change confirmation. If the user confirms the change, the form submits successfully. ...

Encountering a blank page and error message on Vue JS while attempting to generate a JSON file within the

Recently, I encountered a peculiar problem while working on my Vue project using Vue UI in Visual Studio. Before connecting my API, I wanted to prototype and experiment with fake data. So, I decided to create a JSON file in the assets folder to store my m ...

Floating Action Button is not properly attached to its parent container

When developing my React Js app, I decided to utilize the impressive libraries of Material UI v4. One particular component I customized is a Floating Action Button (FAB). The FAB component, illustrated as the red box in the image below, needs to remain p ...

What is the best way to insert a new item into an array that is nested within an object?

Currently, I am delving into the world of using $resource in angularjs and finding great examples in this answer AngularJS $resource RESTful example. Fetching and creating records is working fine, but now my challenge lies in adding a "section" to an exist ...

In some cases, the Ajax reading or fetching variable may have difficulty retrieving the precise variable when working with CodeIgn

I've encountered a puzzling issue with my ajax code, or perhaps it's related to ajax itself. My code retrieves a value from a label and combines it with fresh data from the database. Strangely enough, every time I refresh the page, the output var ...

Validate and submit form using mootools when a link is clicked

Is there a way to validate my form and submit it when a link is clicked? I have included my code below: new Element('a',{ 'html': "To cart", 'class': 'shop ...

Struggling to create an access token with the Slack API

My goal is to retrieve an access token from the Slack API. When I use the code provided below, it generates an authorization URL containing a temporary code in the query string. Once permissions are granted, the process redirects to /slack/oauthcallback. ...

What is the best way to combine elements from different arrays to create a comprehensive listing?

My current function successfully pulls data from another source to create a listing. However, the data I require is spread across multiple arrays, causing some items to be returned as "undefined." At the moment, I am only fetching data from the products a ...

There is no 'Access-Control-Allow-Origin' header found on the requested resource in Heroku for Node.js

Here is the header setup in my Node.js API app: res.header("Access-Control-Allow-Origin", "*"); res.header( "Access-Control-Allow-Headers", "Origin, X-Requested, Content-Type, Accept Authorization" ); ...

Save property using the useState hook

I am working on implementing a sorting function in the child component, where the props are passed in from the parent through an axios call. Should I: Store the prop in the child component's useState? Pass the parent's setState function as a pro ...

Divergent behavior of jQuery AJAX when used with a standard form versus when called in a popup within a div

Why does the jQuery AJAX work perfectly when submitting a form using the normal method, but not when submitting the same form within a popup? Below is the code for reference. Form submission script: $("#submit").click(function (e) { /* $('form&a ...

"Enhance your listening experience with an audio player featuring album covers as captivating

Is there a way to create an audio player with the album cover image serving as the background, while ensuring all control buttons are displayed on top of that same image? I attempted using the following code snippet: <audio controls = 'controls&ap ...

What is the best way to make content stretch to 100% width when there is no content in the sidebar?

As I work on developing my custom theme for Drupal, I am seeking a solution that will allow the content width to adjust depending on the presence of a sidebar. When there is no sidebar, I want the content width to be 100%, and when a sidebar is present, I ...

What is the method for aligning text to the right side within a ListItem?

Currently, I have these elements where the "YoYo" text is aligned to the left by default. However, I am looking to adjust the positioning of some "YoYo" texts so that they can appear on the right side. I attempted to provide a style object with justifyCon ...