How do I force css grid items to overlap each other?

72 views Asked by At

I have a row of 5 columns, each holding a red box with some text. When the user shrinks the screen sideways, I want the container to shrink sideways, and I want the boxes to start overlapping each other, so that the text in the boxes are still fully visible. Not sure how to achieve this, I've tried changing the side margins of the boxes to negative but that doesn't seem to work too well.

.container {
  width: 100%;
  height: 100px;
  border: 1px solid brown;
  display: flex;
  flex-flow: column nowrap;
  justify-content: space-between;
  align-items: stretch;
}

.playerRow {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-template-rows: 1fr;
  
  display: flex;
  justify-content: space-around;
  justify-items: center;
  align-items: center;
  text-align: center;
  gap: 0.45em;
}

.playerBox {
  width: 150px;
  height: 100px;
  background-color: red;
  
  display: flex;
  justify-content: center;
  align-items: center;
}

.playerBox:nth-child(1),
.playerBox:nth-child(3),
.playerBox:nth-child(5)
{
  align-items: flex-end;
}
<div class="container">
  <div class="playerRow">
    <div class="playerBox onTop">user 1 ahhahah</div>
    <div class="playerBox onTop">user 2 ahhahah</div>
    <div class="playerBox onTop">user 3 ahhahah</div>
    <div class="playerBox onTop">user 4 ahhahah</div>
    <div class="playerBox onTop">user 5 ahhahah</div>
  </div>
</div>

https://codepen.io/MH-123/pen/vYMJoZR

3

There are 3 answers

2
imhvost On BEST ANSWER

You need to add an extra element to the .playerBox and set a width to it.
Something like this:

.container {
  border: 1px solid brown;
}

.playerRow {
  height: 100px;
  display: flex;
  justify-content: space-around;
  text-align: center;
}

.playerBox {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 0;
  background-color: red;
}

.playerBox span {
  width: 150px;
  flex: auto;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  z-index: 6;
  margin: 0 4px;
}

.playerBox:nth-child(odd) span {
  align-items: flex-end;
}
<div class="container">
  <div class="playerRow">
    <div class="playerBox onTop"><span>user 1 ahhahah</span></div>
    <div class="playerBox onTop"><span>user 2 ahhahah</span></div>
    <div class="playerBox onTop"><span>user 3 ahhahah</span></div>
    <div class="playerBox onTop"><span>user 4 ahhahah</span></div>
    <div class="playerBox onTop"><span>user 5 ahhahah</span></div>
  </div>
</div>

7
A Haworth On

One way is to calculate where each box is to be and position them absolute.

Here's a simple example.

.container {
  width: 100%;
  height: 100px;
  border: 1px solid brown;
  display: flex;
  flex-flow: column nowrap;
  justify-content: space-between;
  align-items: stretch;
}

.playerRow {
  width: 100vw;
  position: relative;
  height: 100px;
  --gap: calc((100vw - (5 * 150px)) / 10);
}

.playerBox {
  width: 150px;
  height: 100px;
  background-color: #ff000008;
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  left: calc((var(--n) - 1) * 20%);
  left: calc((var(--gap) * var(--n)) + ((var(--n) - 1) * (150px + var(--gap))));
}

.playerBox:nth-child(1) {
  --n: 1;
}

.playerBox:nth-child(2) {
  --n: 2;
}

.playerBox:nth-child(3) {
  --n: 3;
}

.playerBox:nth-child(4) {
  --n: 4;
}

.playerBox:nth-child(5) {
  --n: 5;
}

.playerBox:nth-child(1),
.playerBox:nth-child(3),
.playerBox:nth-child(5) {
  align-items: flex-end;
}
<div class="container">
  <div class="playerRow">
    <div class="playerBox onTop">user 1 ahhahah</div>
    <div class="playerBox onTop">user 2 ahhahah</div>
    <div class="playerBox onTop">user 3 ahhahah</div>
    <div class="playerBox onTop">user 4 ahhahah</div>
    <div class="playerBox onTop">user 5 ahhahah</div>
  </div>
</div>

You may want to add a re-setting of the widths (to less than 150px) for when the viewport width gets too small and the overlaps interfere with the text too much.

0
Mark Schultheiss On

Here is another option by adding row containers and making them flex we can space the rows etc. and still adjusts the row content to produce the effect desired.

Note this only collapses to the width of the row content. This could be scaled but that probably gets more than just CSS in play - there are a number of questions existing for that so won't dive into that here.

I did re-structure the content to contain what were even/odd cells as "rows".

I did use the grid to do some "super center" of a few things and gap the rows.

Lots of borders and padding just to show what is where etc. for this demo.

Grid: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout/Realizing_common_layouts_using_grids nth-child: https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child

body,
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-size: 16px;
}

body {
  width: 100vw;
}

.player-container {
  /* super-center in the container */
  display: grid;
  place-items: center;
  border: 1px solid #00FF00;
  padding: 0.25em;
  width: 100%;
}

.player-row-container {
  /* super-center in the container */
  display: grid;
  place-items: center;
  row-gap: 0.25em;
  border: dashed #0000FF 1px;
  width: 100%;
}

.player-row {
  display: flex;
  align-items: center;
  justify-content: space-evenly;
  border: solid #0DD0FF 1px;
  padding: 0.125em;
  width: 100%;
}

.player-row:nth-child(ODD) {
  color: #FF0000;
}

.player-row:nth-child(even) {
  color: #0000FF;
}

.player-box {
  /* super-center the text in the cell only */
  display: grid;
  place-items: center;
  min-height: 2em;
  background-color: #FF000020;
  border: solid 1px #FF0000;
  white-space: nowrap;
  width: min-content;
  padding-left: 0.5em;
  padding-right: 0.5em;
}
<div class="player-container">
  <div class="player-row-container">
    <div class="player-row">
      <div class="player-box">user 2 ahhahah</div>
      <div class="player-box">user 4 ahhahah</div>
    </div>
    <div class="player-row">
      <div class="player-box">user 1 ahhahah</div>
      <div class="player-box">user 3 ahhahah</div>
      <div class="player-box">user 5 I have a really long user name</div>
    </div>
  </div>
</div>