2

I have a grid of cells. I'd like to create an effect of raised green cells and "pressed in" red. For the raised effect box-shadow on outside bottom-right works great, because next cell covers previous cell shadow. For the "pressed in" effect box-shadow: inset on top-left corner seems to be a good choice, however, I'm struggling make it work with touching cells, they show shadow between the cells.

const list = [],
      type = {red:[2,5,6,16,17,11,12,13,36,46,38,48,21,22,23,31,32,33], green:[37,47,39,49,65,66,67,75,76,77,85,86,87,81,82,92,93]},
      width = 10,
      height = 10;

for(let i = 0, t; i < 100; i++)
{
  t = type.red.includes(i) ? "red" : type.green.includes(i) ? "green" : "";
  list[i] = t;
  const c = document.createElement("div");
  if (list[i])
    c.className = list[i];

// add class for each side outside of the cluster
  if (t = type[t])
  {
    if (!t.includes(getIndexOffset(i, 0, -1)))
      c.classList.add("top");

    if (!t.includes(getIndexOffset(i, 1, 0)))
      c.classList.add("right");

    if (!t.includes(getIndexOffset(i, 0, 1)))
      c.classList.add("bottom");

    if (!t.includes(getIndexOffset(i, -1, 0)))
      c.classList.add("left");
  }
  table.appendChild(c);
}

function getIndexOffset(index, offsetX, offsetY)
{
  return (~~(index / width) + offsetY) * width + (index % width + offsetX);
}
#table
{
  display: flex;
  flex-wrap: wrap;
  width: 11em;
}

#table > *
{
  width: 1em;
  height: 1em;
  border: 1px solid black;
  margin: -1px 0 0 -1px;
  background-color: white;
}

#table > .green
{
  background-color: lightgreen;
  box-shadow: 0.2em 0.2em 5px 0 black;
  z-index: 1;
}

#table > .red
{
  background-color: pink;
  box-shadow: 0.2em 0.2em 5px 0 black inset;
  z-index: 3;
}
<div id="table"></div>

Any suggestion how to fix the issue with shadow shown between cells? [EDIT] added class name for each side that requires a shadow

vanowm
  • 9,466
  • 2
  • 21
  • 37
  • How general do you need the solution to be? Could we always assume the overall width is an exact multiple of cell size? – A Haworth Apr 27 '22 at 06:08

1 Answers1

1

If you know the number of cells in a row (n) or can work it out then instead of always adding the top and left shadow to a red cell you could add left, top or both shadow styling.

This snippet uses linear-gradients instead of inset shadows (because I find inset shadows too confusing....)

const n = 10; //number of cells in a row

for (let i = 0, r = [2, 5, 6, 16, 17, 11, 12, 13, 36, 46, 38, 48, 21, 22, 23, 31, 32, 33], g = [37, 47, 39, 49, 65, 66, 67, 75, 76, 77, 85, 86, 87, 81, 82, 92, 93]; i < 100; i++) {
  const c = document.createElement("div");

  if (r.includes(i)) {
    c.classList.add('red');
    // r - n is the position of the cell immediately vertically above (if there is one else < 0)
    // if (!r%n == 0) r - 1 is the position of the cell immediately horizontally to the left 
    if (!r.includes(i - n) && (i % n == 0 || !r.includes(i - 1))) {
      c.classList.add('bothShadows');
    } else {
      if (!r.includes(i - n)) c.classList.add('topShadow');
      if (!r.includes(i - 1)) c.classList.add('leftShadow');
    }
  }

  if (g.includes(i))
    c.className = "green";

  table.appendChild(c);
}
#table {
  display: flex;
  flex-wrap: wrap;
  width: 11em;
}

#table>* {
  width: 1em;
  height: 1em;
  border: 1px solid black;
  margin: -1px 0 0 -1px;
  background-color: white;
}

#table>.green {
  background-color: lightgreen;
  box-shadow: 0.2em 0.2em 5px 0 black;
  z-index: 1;
}

#table>.red {
  background-color: pink;
  background-repeat: no-repeat;
  z-index: 3;
}

#table>.topShadow {
  background-image: linear-gradient(black, transparent);
  background-size: 100% 5px;
}

#table>.leftShadow {
  background-image: linear-gradient(to right, black, transparent);
  background-size: 5px 100%;
}

#table>.bothShadows {
  background-image: linear-gradient(to right, black, transparent), linear-gradient(black, transparent);
  background-size: 5px 100%, 100% 5px;
}
<div id="table"></div>
vanowm
  • 9,466
  • 2
  • 21
  • 37
A Haworth
  • 30,908
  • 4
  • 11
  • 14
  • I can even add separate class name for each side that is "outside" of the cluster, (for examle cell @ index 5 would have `top`, `bottom`, `left` and @ index 6 would have `top`, `right`) that still doesn't help without proper style.... – vanowm Apr 27 '22 at 10:38
  • Sorry, not sure what you are saying. The code above adds the separate styles for you. You just have to define each style with left shadow or whatever. Lots of hints on how to do that e.g. at https://stackoverflow.com/questions/5115427/how-can-i-add-a-box-shadow-on-one-side-of-an-element#:~:text=The%20fourth%20property%20there%20-2px%20is%20the%20shadow,%28vertical%20offset.%29%205px%20is%20the%20blur%20radius%20%3A%29 though I might just do it with linear-gradient backgrounds. – A Haworth Apr 27 '22 at 10:59
  • Well, that's the thing I'm struggling with the style, not the javascript part... – vanowm Apr 27 '22 at 11:05
  • Sorry, had misinterpreted the problem. Have added those shadow classes now - using linear-gradients. – A Haworth Apr 27 '22 at 11:40
  • Thank you. this is almost perfect. There is one little issue if the cells create a corner (I've modified my example, added cell 2). The shadow looks clipped at cell 3 – vanowm Apr 27 '22 at 13:18