Position the div beneath another div using the display:grid property

I can't seem to figure out how to position a div below another div using display:grid. The div is appearing on top instead of below.

The "app-bm-payment-card-item" is actually a custom Angular component.

Here's the HTML file:

//div wrapper
<div *ngIf="pageReady && myProfiles" class="ion-padding">

//div showing the cards stacked or collapsed
<div *ngIf="!inEditMode" class="card_container_stacked_main">
  <app-bm-payment-card-item *ngFor="let card of myProfiles" [card]="card" [editMode]="inEditMode"
    (onDeleteClick)="removeCard(card)" (onSelect)="selectCard(card)" (onEditClick)="editCardInfo(card)">
  </app-bm-payment-card-item>
</div>

//div showing the cards expanded
<div *ngIf="inEditMode" class="card_container_expanded_main">
  <app-bm-payment-card-item *ngFor="let card of myProfiles" [card]="card" [editMode]="inEditMode"
    (onDeleteClick)="removeCard(card)" (onSelect)="selectCard(card)" (onEditClick)="editCardInfo(card)">
  </app-bm-payment-card-item>
</div>

//div that should be positioned below the other ones
<div class="div">
  TEXT
</div>

</div>

Here's the SCSS file:

.card_container_stacked_main {
display:grid;
position: relative;
grid-auto-rows:30px; /* a fixed height to create an overflow */ 
}

.card_container_expanded_main {
position: relative;
max-width: 400px !important;
//margin-bottom: 15px;
}

.div {
position: relative;
}

Essentially, when clicking on any card, the card list should either stack or collapse. This is determined by the inEditMode boolean. When displaying the expanded card list, the div (TEXT) is correctly positioned below the list. However, when the stacked card list is displayed, the div appears on top of the list instead of below it. Refer to the images for clarification:

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

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

Answer №1

A fascinating puzzle to solve, given the variability in the number of cards that can exist within the "wallet," ranging from 1, 2 to N, and the necessity for explicit specification of a tracking size in the CSS properties grid-auto-rows and/or grid-template-rows.

Several solutions at hand (all while utilizing grid efficiently)

https://i.sstatic.net/eHCTcm.pnghttps://i.sstatic.net/vPzlym.png

#1 A straightforward yet inelegant approach

The simple fix involves adding a margin-top: 200px; to the TEXT div specifically when the cards are stacked.

This solution may not be ideal as it's more of a quick workaround rather than a refined design choice.

function expandStackCards() {
  var wrapper = document.getElementById("wrapper");
  if (wrapper.classList.contains("stacked")) {
    wrapper.classList.remove("stacked");
  } else {
    wrapper.classList.add("stacked");
  }
}
button {
  width: 400px;
  margin-bottom: 10px;
}
#wrapper {
  display: grid;
  grid-template-columns: 400px;
  gap: 10px;
}
#wrapper.stacked  {
  grid-auto-rows: 30px;
  gap: 0px;
}
.card {
  width: 100%;
  height: 200px;
  background-color: grey;
  border-radius: 20px;
  padding: 6px 20px;
  box-sizing: border-box;
}
.card span {
  font-family: sans-serif;
  text-transform: uppercase;
  color: white;
}
.card.green {
  background-color: green;
}
.card.blue {
  background-color: blue;
}
.my-text {
  margin: 10px;
}
.stacked .my-text {
  margin-top: 200px;
}
<button onclick="expandStackCards()">Expand / Stack</button>
<div id="wrapper" class="stacked">
  <div class="card green"><span>Card #1</span></div>
  <div class="card blue"><span>Card #2</span></div>
  <div class="my-text">TEXT</div>
</div>

Alternatively, check out the Codepen code here

#2 Leveraging JavaScript for dynamic adjustment of grid-auto-rows

In my view, this is the most effective solution as it entails no reliance on margin adjustments but solely utilizes grid CSS.

To implement this method, a bit of JavaScript is required to determine the card count and accordingly set the value of grid auto rows.

function stackedCards() {
  var wrapper = document.querySelector('#wrapper.stacked');
  if (wrapper) {
    var num_cards = wrapper.querySelectorAll(':scope .card').length;

    let style = getComputedStyle(wrapper);
    row_height_str = style.gridAutoRows;

    var new_grid_auto_rows = row_height_str.concat(' ').repeat(num_cards - 1);

    new_grid_auto_rows = new_grid_auto_rows.concat('auto');

    wrapper.style.gridAutoRows = new_grid_auto_rows;
  }
}

// The function below is designed solely for DEMO purposes
function expandStackCards() {
  var wrapper = document.getElementById("wrapper");
  if (wrapper.classList.contains("stacked")) {
    wrapper.classList.remove("stacked");
    wrapper.style.removeProperty("grid-auto-rows");
  } else {
    wrapper.classList.add("stacked");
    stackedCards();
  }
}

stackedCards();
button {
  width: 400px;
  margin-bottom: 10px;
}
#wrapper {
  display: grid;
  grid-template-columns: 400px;
  gap: 10px;
}
#wrapper.stacked {
  grid-auto-rows: 30px;
  gap: 0px;
}
.card {
  width: 100%;
  height: 200px;
  background-color: grey;
  border-radius: 20px;
  padding: 6px 20px;
  box-sizing: border-box;
}
.card span {
  font-family: sans-serif;
  text-transform: uppercase;
  color: white;
}
.card.green {
  background-color: green;
}
.card.blue {
  background-color: blue;
}
.my-text {
  margin: 10px;
}
<button onclick="expandStackCards()">Expand / Stack</button>
<div id="wrapper" class="stacked">
  <div class="card green"><span>Card #1</span></div>
  <div class="card blue"><span>Card #2</span></div>
  <div class="my-text">TEXT</div>
</div>

For the corresponding implementation, feel free to explore the Codepen code here

#3 Employing JavaScript to assign a class to the #wrapper

An additional strategy involves using JavaScript to identify the number of cards and subsequently apply an appropriate class to the grid container (#wrapper).

This method resembles the previous one but refrains from setting CSS styles via JavaScript; however, your CSS file needs declarations like the following:

.wallet-1-cards {
  grid-auto-rows: auto;
}
.wallet-2-cards {
  grid-auto-rows: 30px auto;
}
.wallet-3-cards {
  grid-auto-rows: 30px 30px auto;
}
.wallet-4-cards {
  grid-auto-rows: 30px 30px 30px auto;
}

// etc...

By opting for this third approach, you steer clear of incorporating CSS within your JS code (instead, applying a class to a div), which proves advantageous provided the likelihood of exceeding a certain card limit is minimal—thereby preventing CSS clutter with numerous redundant definitions.

Answer №2

To reposition the text below the final card, I implemented a solution that proved effective during testing:

Define a property like 'stackedContainerHeight' and calculate the container height as follows ->

stackedContainerHeight = height of a stacked card in pixels * (length of card/profile array - 1) + full card height + adjustments such as margins

For instance:

stackedContainerHeight = 30 * (this.myProfiles.length-1) + 50 +15;

Dynamically set the height of the stacked container for the container element

[style.height.px]="stackedContainerHeight"

The original issue: Grid-auto-rows was cutting off the container height causing part of the last complete card to overflow the container. This solution ensures the correct height calculation so that the text div is properly rendered below the container.

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

Dynamic Rendering of Object Arrays in Table Columns using JavaScript

In the process of developing an appointment slot selection grid, I have successfully grouped all appointments by dates. However, I am facing challenges in displaying this array of Objects as a clickable grid with columns. The current output can be viewed h ...

What is the best way to send messages between different sections on the same page?

Basically, in the following code: <?php $hostname = ''; $username = ''; $password = ''; $dbn = ''; try { $dbh = mysqli_connect($hostname , $username, $password ,$dbn); //echo 'Connected to database'; } ...

Navbar collapse not functioning properly on HTML, CSS, and JavaScript

I have developed a CSS code snippet: .nav{ right: 0px; left: 0px; margin-top: 0px; margin-bottom:20px; height: 35px; text-align: center; background-color: red; z-index: 1; } .sticky { background: #000; text-align: center; ...

Troubles with CSS in MUI Component Integration

How can I successfully implement a vertical timeline using Material UI in React? I've set it up, but the CSS isn't functioning as expected. Is there an error in my implementation? List of Dependencies: "@emotion/react": "^11.11.1& ...

Adding a .PHP File to Two Separate DIVs

I am using wordpress to create a custom theme. I'm interested in placing all the content from my slider.php file inside a div box on my index.php page. How would I go about doing this? SLIDER.PHP <div class="slider"> // All the image tags wit ...

I am struggling to make my button hover effects to function properly despite trying out numerous suggestions to fix it

As a newcomer, this is my first real assignment. I've managed to tackle other challenges successfully, but this one seems a bit more complex and I'm struggling to pinpoint where I'm going wrong. Despite googling various solutions, none of th ...

Challenges with Adjusting Background Opacity in CSS

My text has a white background with an opacity of .3, but it's affecting the foreground due to CSS repositioning. Even though the HTML is in a different division, I struggle with certain aspects of CSS and would appreciate guidance from those more exp ...

Personalize the material design datatable checkbox option

Recently, I delved into the world of material-ui design in conjunction with ReactJS. However, I have encountered a roadblock while attempting to customize the style of a checkbox that is being displayed under the <TableRow /> component. (Check out th ...

What is the process for disabling the CSS module feature in Next.js?

In Next.js, Global CSS can only be imported in _App.js. However, importing global CSS in every component is not allowed, so we have to use CSS modules to comply with this restriction imposed by Next.js. Currently, I am in the process of migrating a large ...

Incorporating multiple CSS style sheets within a single HTML document

As part of my assignment, I have successfully created two different CSS style sheets. The next step is to link both style sheets to a single HTML page and provide users with the option to switch between the two styles. I am wondering how to achieve this. ...

Issue with Angular: Attempting to assign a value to a property that is undefined within

While utilizing a common method to call a service that executes two functions upon success and failure, I encountered an issue. Despite the call executing correctly, I faced an error when trying to assign a value from the service result to a variable withi ...

External style sheet link is not operational

Inside base.php <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8> <title>Base</title> <style> body { background: blue; } </style> </head> <body> &l ...

general declarations take precedence over media queries

One of my usual CSS rules looks something like this: #dayslist > div { height: 51px; } Then there's the media query CSS rule: @media (max-width: 979px){ #dayslist > div { height: 44px; } } However, whenever I resize my bro ...

line of checkboxes aligned horizontally with the help of Bootstrap

My goal is to create a horizontal row of checkboxes within a form. I've been able to achieve a functional but unattractive version by using the following code: div.form-group(ng-show = 'avariable') label 1 input(type = 'checkbo ...

The concept of CSS background-position

Hey there, I have a query regarding a sprite image that contains icons with both normal and hover effects. Here is the current CSS code I am using: .wi{ background-image:url(images/icons/small/wi.png); background-repeat:no-repeat; display:blo ...

Ways to attain a similar format - input map

After pressing the save button, I am aiming to achieve the following effect: "timeTable":{ "0": [{"from":"08:00","to":"12:00"}, {"from":"14:00","to":"18:20&q ...

Integrate a JS file into my Angular 4 project

For one of my components, I am looking to implement a specific effect: https://codepen.io/linrock/pen/Amdhr Initially, I attempted to convert the JavaScript code to TypeScript, but faced challenges. Eventually, I decided to directly copy the JS file from ...

Implement jQuery to toggle a class on click for added functionality

I am attempting to create a box that changes color when clicked. When the box is first clicked, it will turn red by adding the class red, and if clicked again, it will change to blue. The colors alternate with each click, but I am unsure of how to achieve ...

How to position div elements side by side using CSS and center them, even on IE8

UPDATE: I have discovered that implementing Bart's solution is the correct one. With a 264px wide div containing the other divs and their 1px borders, I achieved the desired effect. I have updated my code to include his answer. Thank you, Bart. Once ...

What methods can be used to control access to document.styleSheets data, and what is the purpose behind doing so?

Recently, I came across the document.styleSheets API, which allows you to access stylesheets used by a website. Using this API is simple, for example, document.styleSheets[0].cssRules will provide all CSS rules for the first stylesheet on a page. When I t ...