Is there a method in CSS Grids to wrap the implicit grid while employing grid-auto-flow: column?

How can I achieve a layout consisting of two 4x2 grids that flow into each other, instead of being positioned side by side? Essentially, I want to split an 8x2 grid into two halves and stack them vertically. Is there a way to make the layout wrap around itself seamlessly?

Currently, my grid is set up as follows:

grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(2, 1fr);

The child nodes are categorized into small, medium, and large classes:

.c-small { }

.c-medium {
  grid-row: auto / span 2;
}

.c-large {
  grid-column: auto / span 2;
  grid-row: auto / span 2;
}

Is there a way to wrap the content from the top grid around to the bottom grid, instead of having it overflow to the right-hand side?

I'm not sure if this layout is achievable without JavaScript. Currently, I'm considering a solution where I manually move items from one grid to a second grid when they overflow, but I'm unsure how to detect when a grid item has overflowed into the implicit grid.

Check out the Codepen example here

Answer №1

To start, you must conceal all overflowing elements in the grids. I have made adjustments to the grid styles for this purpose.

.l-grid {
  height: calc(50vh - 70px - 32px);
  display: grid;
  /* fixed percentage minus (n-1)/n * column gap, n is column count */
  /* with calc to include gaps instead of flexible fr units */
  grid-template-columns: repeat(4, calc(25% - 12px));
  grid-template-rows: repeat(2, 1fr);
  /* set auto generated column width to 0 */ 
  grid-auto-columns: 0;
  /* hide when overflow */
  overflow: hidden;
  grid-gap: 16px;
  grid-auto-flow: column;
  margin: 16px;
}

I have introduced the JavaScript function changeSize to adjust the size based on the CSS class.

Furthermore, the function isHidden has been included to determine if a grid item is hidden based on the coordinate of the right side (as two-column items may be cropped with overflow).

Lastly, the function moveHiddenElementsToNextGrid reinstates the original layout and transfers invisible items to the second grid.

$(".a-grid__item").click(function() {
  var $gridItem = $(this);
  changeSize($gridItem);
  moveHiddenElementsToNextGrid();
});

function changeSize($gridItem) {
  if ($gridItem.hasClass("c-small")) {
    $gridItem.removeClass("c-small");
    $gridItem.addClass("c-medium");
  } else if ($gridItem.hasClass("c-medium")) {
    $gridItem.removeClass("c-medium");
    $gridItem.addClass("c-large");
  } else if ($gridItem.hasClass("c-large")) {
    $gridItem.removeClass("c-large");
    $gridItem.addClass("c-small");
  }
}

function isHidden($gridItem) {
    var elementRight = $gridItem.position().left + $gridItem.width();
    var parentWidth = $gridItem.parent().width();
    var parentMarginRight = parseInt($gridItem.parent().css("margin-right"));
    return elementRight - parentWidth > parentMarginRight;
};

function moveHiddenElementsToNextGrid() {
  $(".a-grid__item").appendTo("#js-grid1");
  $(".a-grid__item").filter(function() { return isHidden($(this)); }).appendTo("#js-grid2");
}

moveHiddenElementsToNextGrid();
/* OVERRIDES */

body {
  font-family: sans-serif;
  margin: 0;
}


/* LAYOUTS */

.l-canvas {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: calc(100vh - 70px);
  background-color: rgba(0, 0, 0, 0.05);
}

.l-grid {
  height: calc(50vh - 70px - 32px);
  /* 100vh */
  display: grid;
  grid-template-columns: repeat(4, calc(25% - 12px));
  grid-template-rows: repeat(2, 1fr);
  grid-auto-columns: 0;
  overflow: hidden;
  grid-gap: 16px;
  grid-auto-flow: column;
  margin: 16px;
}

.l-buttons {
  position: fixed;
  bottom: 0;
  right: 0;
  height: 56px;
  padding: 16px 16px;
}


/* ATOMS */

.a-grid__item {
  background-color: rgba(0, 0, 0, 0.2);
  /* height: 200px; */
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 10px;
  min-width: 0;
}


/* COMPONENTS */

.c-title {
  font-size: 24px;
  font-weight: bold;
  line-height: 28px;
  padding-bottom: 8px;
  margin: 16px 8px;
  border-bottom: 2px solid #333;
}

.c-small {
  /* auto */
}

.c-medium {
  grid-row: auto / span 2;
}

.c-large {
  grid-column: auto / span 2;
  grid-row: auto / span 2;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="c-title">
  CSS Grids
</div>
<div class="l-canvas">
  <div id="js-grid1" class="l-grid">
    <div class="a-grid__item c-small">
      1
    </div>
    <div class="a-grid__item c-small">
      2
    </div>
    <div class="a-grid__item c-medium">
      3
    </div>
    <div class="a-grid__item c-small">
      4
    </div>
    <div class="a-grid__item c-medium">
      5
    </div>
    <div class="a-grid__item c-small">
      6
    </div>
    <div class="a-grid__item c-large">
      7
    </div>
    <div class="a-grid__item c-medium">
      8
    </div>
  </div>
  <div id="js-grid2" class="l-grid">
  </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 NodeJS environment is experiencing issues with async JavaScript functions returning undefined

I'm struggling to call a function that fetches data from an API, compares it with input, and should return either 0 or 1 for use in my code. However, the function is currently returning undefined. I can't seem to wrap my head around it. async fu ...

Receiving the latest global variable in JavaScript using jQuery

I keep receiving undefined type for: $(".ui-slider-handle").attr("title", '"'+current+'"'); Even though I can successfully alert the updated value of current on line 29, it seems to not be working with .at ...

Establishing standard emit actions in a Vue JS component layout

I am dealing with a complex situation involving two nested Vue JS components. The child component is emitting certain events to the parent function, which I have defined within the parent component declaration. The issue here is that these events are being ...

Applying a class in jQuery to an element when the data attribute aligns with the current slide in Slick

I need to compare the data-group attribute of the current slide to the equivalent attribute in a navigation list. If they match, the anchor element in the navigation list should be given an active class. How can I achieve this using jQuery? Navigation Li ...

When working with AngularJS routing, utilize a function for the templateUrl to dynamically load the appropriate template

Can a function be used as the templateUrl in angularjs routing? The $routeProvider official documentation states: templateUrl – {string=|function()=} Check out the $routeProvider official documentation here In javascript, a function is typically def ...

Removing a single object from an array of objects using MongooseJS

Hello to all the MongooseJS experts out there! I'm a newcomer to MongooseJS, and I've been trying to solve this problem for the past two days but haven't found a solution yet. Thank you in advance for any help! The Issue with My Delete me ...

Repeating X and Y Axis Labels on Highcharts

Highchart is new to me. I recently created a basic chart showing the count of males and females over the past five years. I have included a screenshot for reference. I am wondering if it's possible to remove duplicate labels from both axes? Below is ...

Passing a Ruby session variable to a JavaScript tag: a step-by-step guide

I'm currently collaborating with a vendor who utilizes a JavaScript tag for sale attribution, and I need to pass session variables to the tag. The tag appears to be firing properly, as I can see the variables in the logs, but they aren't reflecte ...

Is it possible for me to access information from an external URL using JSON?

As I delve into learning about JSON for app development, I've encountered an issue with a JSON and PHP-based chat system. While the code functions properly for the same origin policy, when it comes to sending and receiving data from an external URL, i ...

Tips for sending a callback function in Angular following an HTTP request

Currently, I am leveraging an angular controller to make an http post request to my express route. Subsequently, data is dispatched to my Gmail client via nodemailer. Although the $http request functions properly and emails can be received in my Gmail acco ...

Tips for automatically populating a form in React with specified values

Here is the code I have written: .... const { userProfile, getUserProfile } = useContext(UserContext); useEffect(() => { getUserProfile(); //eslint-disable-next-line }, []); const [user, setUser] = useState({ ...

Unleash the power of CSS3 to style this button

I received an image of a button that I need to replicate on a website, but unfortunately, only the image was provided without any information about the font-family or size. Despite not being a designer or CSS expert, I attempted to create a CSS style that ...

What is the preferred method of compiling Sass: utilizing the Live Sass Compiler extension in VS Code, or setting up and running Sass through npm? (Including guidance on transitioning from node-sass to dart-sass)

As I delve into an online course focused on Advanced CSS and Sass, I have noticed that the techniques being taught seem a bit outdated. The course heavily relies on node-sass in its dependencies, which is now considered deprecated. An alternative solution ...

Switch up the picture when you press on it

I have a task involving a table where I want to switch out an image in the <td> when it is clicked, using a URL that I specify beforehand. The URL of the image will be provided when clicking on a link within the page. For example: index.html?type=d ...

Create an array in JavaScript using the JSON data that was returned

After receiving some JSON data from a REST call, I have successfully parsed and added totals to the data. The results can be viewed on the page (refer to this post: json sibling data). However, now I want to further break down the totals. Here is the initi ...

tracking scroll position within div on main page

I have a div tag enclosed within a content tag due to the implementation of a masterpage containing the forms and body tags. <asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder2" Runat="Server"> <div id="xxx" style="overflow:s ...

Keep label at the forefront once input field is completed

Is it possible to keep my label positioned on top of the input field even after filling in data? I attempted using the valid function in CSS, but did not achieve the desired functionality. .txt_field input { width: 100%; padding: 0 5px; height: 4 ...

The Strapi plugin seems to be encountering an issue as the API is not reachable, leading to a

In an attempt to create a custom API in Strapi backend, I developed a plugin called "test" for testing purposes. However, when trying to access the test response in Postman, it displays a 404 error stating that it is not accessible. Let me provide you wit ...

"Customize your Vuetify v-card with uniquely styled rounded corners on only

I am seeking to create a unique v-card design where only two corners are rounded. Despite my attempts, the card ended up rotated by 90° and didn't achieve the desired outcome. DESIGN ATTEMPT: <div class="text-center rotate-ninety ml-n6" ...

Creating consistent row spacing between Bootstrap 5 rows that matches the spacing in Bootstrap 4

Is it possible to adjust the site.css file in order to achieve a similar row spacing effect as Bootstrap 5 when working with existing HTML code? ...