Jon Kyte
Jon Kyte

Reputation: 2020

Target CSS grid column within a single element

I'm building a comparison chart and I need to fix the first column to the left-hand side and the last row to the bottom of the view, whilst respecting the col width and row heights of neighbouring cells.

The height of each row should grow based on the max-data in any given cell. I put together this basic version which shows what I have so far (apologies for the repetition of the <div class="items"> I needed enough to show the sticky footer):

* {
  box-sizing: border-box;
}

body {
  overflow: hidden;   
}

.container {
  overflow: auto;
  height: calc(100vh - 80px);
  margin-top: 80px;
  padding-left: 15px;
}

.heading {
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: absolute;
  top: 0;
  left: 0;
  height: 80px;
  z-index: 1;
  background: white;
  right: 0;
  padding: 15px;
} 

.compare {
  width: max-content;
}

.grid {
  display: grid;
  position: relative;
  grid-template-columns: repeat(6, 300px);
  align-items: stretch;
}

.item {
  padding: 10px;
}

.title {
  position: sticky;
  left: 0;
  background-color: red;
}

.section span {
  position: sticky;
  left: 0;
  background-color: green;
}

.footer {
  position: sticky;
  bottom: 0;
  background: yellow;
}

// To highlight the problem I'm trying to solve

.item:nth-child(3),
.item:nth-child(9),
.item:nth-child(15),
.item:nth-child(21) {
  border: 1px dashed blue;
  border-top: none;
  border-bottom: none;
}

.item:nth-child(3) {
  border-top: 1px dashed blue;
}

.item:nth-child(21) {
  border-bottom: 1px dashed blue;
}
<div class="container">
  <div class="heading">
    <h1>Compare</h1>
    <button>Back</button>
  </div>
  <div class="compare">
      <div class="section">
        <span>Section title</span>
      </div>
      <div class="grid">
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value </div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
      </div>
      <div class="section">
        <span>Section title</span>
      </div>
      <div class="grid">
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value </div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
      </div>
      <div class="section">
        <span>Section title</span>
      </div>
      <div class="grid">
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value </div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
      </div>
      <div class="section">
        <span>Section title</span>
      </div>
      <div class="grid">
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value Value </div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item title">Key</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
        <div class="item">Value</div>
      </div>
    <div class="grid footer">
      <div class="item title">Key</div>
      <div class="item">CTA</div>
      <div class="item">CTA</div>
      <div class="item">CTA</div>
      <div class="item">CTA</div>
      <div class="item">CTA</div>
    </div>
  </div>
</div>

I would like to enable drag/drop sorting for each column and would like to contain each column within a single element (so I can target e.g. <div class="col-2">...all <div class="items"> within this col...</div>). Is it possible to achieve this with grid markup? Or is the best way to target every individual <div class="items"></div> which make up a column with Javascript.

Upvotes: 2

Views: 613

Answers (1)

the Hutt
the Hutt

Reputation: 18398

In grid layout you can wrap cells in a div using display:contents:

:root {
  --col-no: 1;
}

.wrapper {
  height: 300px;
  width: 100vw;
  display: grid;
  grid-template-columns: 100px repeat(6, 150px);
  grid-auto-flow: column;
  overflow: scroll;
}

.section {
  background-color: lightgreen;
}

.title {
  background-color: orange !important;
}

.col {
  /* disply contents */
  display: contents;
}

.col:nth-child(2n + 2)>* {
  background-color: #ddd;
}

.col:first-child>div {
  position: sticky;
  left: 0;
}

.col>* {
  grid-column: var(--col-no);
}

.footer {
  display: contents;
}

.footer>div {
  background-color: yellow;
  grid-row: 1000;
  position: sticky;
  bottom: 0;
}

.col:nth-child(1) {
  --col-no: 1;
}

.col:nth-child(2) {
  --col-no: 2;
}

.col:nth-child(3) {
  --col-no: 3;
}

.col:nth-child(4) {
  --col-no: 4;
}

.col:nth-child(5) {
  --col-no: 5;
}

.col:nth-child(6) {
  --col-no: 6;
}
<div class="wrapper">
  <div class="col">
    <div class="section">
      <span>Section title1</span>
    </div>
    <div class="item title">Key</div>
    <div class="item title">Key</div>
    <div class="item title">Key</div>
    <div class="item title">Key</div>
    <div class="section">
      <span>Section title2</span>
    </div>
    <div class="item title">Key</div>
    <div class="item title">Key</div>
    <div class="item title">Key</div>
    <div class="item title">Key</div>
    <div class="section">
      <span>Section title3</span>
    </div>
    <div class="item title">Key</div>
    <div class="item title">Key</div>
    <div class="item title">Key</div>
    <div class="item title">Key</div>
  </div>
  <div class="col">
    <div class="items"></div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value value value =</div>
    <div class="items">value</div>
    <div class="items"></div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items"></div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
  </div>

  <div class="col">
    <div class="items"></div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items"></div>
    <div class="items">value abc abc efgh hijk lmin = =</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items"></div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
  </div>

  <div class="col">
    <div class="items"></div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items"></div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items"></div>
    <div class="items">value</div>
    <div class="items">value value value value value===</div>
    <div class="items">value</div>
    <div class="items">value</div>
  </div>

  <div class="col">
    <div class="items"></div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value value value value value</div>
    <div class="items">value</div>
    <div class="items"></div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items"></div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
  </div>

  <div class="col">
    <div class="items"></div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value value value</div>
    <div class="items">value</div>
    <div class="items"></div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items"></div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
    <div class="items">value</div>
  </div>


  <div class="grid footer">
    <div class="item title">Foot Key</div>
    <div class="item">CTA</div>
    <div class="item">CTA</div>
    <div class="item">CTA</div>
    <div class="item">CTA</div>
    <div class="item">CTA</div>
  </div>
</div>

By accessing .col elements you can control grid columns. Also, drag events do get fired on .col elements.

  <script>
    let cols = document.querySelectorAll('.col');
    cols.forEach(c => c.addEventListener('dragstart', () => {
      console.log('dragstarted')
    }));
  </script>

Upvotes: 2

Related Questions