How to make hover state on row table with CSS grid layout

17,320

Solution 1

Here is a trick using pseudo-element. The idea is to use the element as a background and make it overflow on the left and right so that it will cover all the row. Like that if you hover on any element inside a row you change the color and it's like you changed the color of the whole row.

This trick involve few changes on the markup and also more CSS.

.table {
  display: grid;
  grid-template-columns: [col-start] auto [col-end];
  grid-template-rows: [header-start] 50px [header-end row-start] auto [row-end];
  grid-auto-rows: auto;
  grid-auto-columns: auto;
  grid-gap: 1px;
  overflow: hidden;
  background: gray;
}

.table>* {
  padding: 10px;
  position: relative;
}

.heading {
  background: navy;
  color: #fff;
  grid-row: header;
}

.row span {
  position: relative;
  z-index: 2;
}

.row:before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  right: -1000%;
  left: -1000%;
  z-index: 1;
}

.row:after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  right: -1px;
  width: 1px;
  z-index: 2;
  background-color: #fff;
}

.row:nth-child(5n+5)::after {
  bottom: -1px;
  right: 0;
  left: -1000%;
  height: 1px;
  z-index: 3;
  width: auto;
  top: auto;
  background-color: #fff;
}

.row:hover::before {
  background-color: red;
}
<div class="table">
  <div class="heading">Title 1</div>
  <div class="heading">Title 2</div>
  <div class="heading">Title 3</div>
  <div class="heading">Title 4</div>
  <div class="heading">Title 5</div>

  <div class="row"><span>Row 1</span></div>
  <div class="row"><span>Row 1</span></div>
  <div class="row"><span>Row 1</span></div>
  <div class="row"><span>Row 1</span></div>
  <div class="row"><span>Row 1</span></div>

  <div class="row"><span>Row 2</span></div>
  <div class="row"><span>Row 2</span></div>
  <div class="row"><span>Row 2</span></div>
  <div class="row"><span>Row 2</span></div>
  <div class="row"><span>Row 2</span></div>

  <div class="row"><span>Row 3</span></div>
  <div class="row"><span>Row 3</span></div>
  <div class="row"><span>Row 3</span></div>
  <div class="row"><span>Row 3</span></div>
  <div class="row"><span>Row 3</span></div>
</div>

Solution 2

Since you are treating this as a table, where the elements stay in the same row, you can also wrap each row in a DIV with "display" set to "contents." This forms an innocuous parent element that you use for hover, and then style the child elements. (display: contents is not yet supported in Edge, though.)

.table {
  display: grid;
  grid-template-columns: [col-start] auto [col-end];
  grid-template-rows: [header-start] 50px [header-end row-start] auto [row-end];
  grid-auto-rows: auto;
  grid-auto-columns: auto;
  grid-gap: 1px;
  overflow: hidden;
  background: gray;
}

.table .row, .table .heading{
  padding: 10px;
  position: relative;
}

.heading {
  background: navy;
  color: #fff;
  grid-row: header;
}

.row span {
  position: relative;
  z-index: 2;
}

.rowWrapper{
  display: contents;
}

.rowWrapper:hover > div{
  background-color: orange;
}
<div class="table">

        <div class="heading">Title 1</div>
        <div class="heading">Title 2</div>
        <div class="heading">Title 3</div>
        <div class="heading">Title 4</div>
        <div class="heading">Title 5</div>
      
    <div class="rowWrapper">
        <div class="row"><span>Row 1</span></div>
        <div class="row"><span>Row 1</span></div>
        <div class="row"><span>Row 1</span></div>
        <div class="row"><span>Row 1</span></div>
        <div class="row"><span>Row 1</span></div>
    </div>

    <div class="rowWrapper">
        <div class="row"><span>Row 2</span></div>
        <div class="row"><span>Row 2</span></div>
        <div class="row"><span>Row 2</span></div>
        <div class="row"><span>Row 2</span></div>
        <div class="row"><span>Row 2</span></div>
    </div>
      
    <div class="rowWrapper">
        <div class="row"><span>Row 3</span></div>
        <div class="row"><span>Row 3</span></div>
        <div class="row"><span>Row 3</span></div>
        <div class="row"><span>Row 3</span></div>
        <div class="row"><span>Row 3</span></div>
    </div>
    
</div>

Solution 3

Here's my solution, based on sibling combinators.
The main part is:

.datacell:hover ~ .datarow {
    background-color: rgba(255,255,0,0.5);
}
.datacell:hover ~ .datarow + .datacell ~ .datarow{
    background-color: transparent;
}

Snippet:

.datatable{
    display:grid;
    grid-gap: 0;
    grid-template-columns: auto 1fr auto;
    position: relative;
}

.datarow{
    grid-column: 1 / 4;
    z-index: 0;
}

.datacell{
    z-index: 1;
    padding: 8px;
    border-bottom: 1px solid #c0c0c0;
}

.datacell:hover ~ .datarow {
    background-color: rgba(255,255,0,0.5);
}
.datacell:hover ~ .datarow + .datacell ~ .datarow{
    background-color: transparent;
}

.row-1{ grid-row: 1;}
.row-2{ grid-row: 2;}
.row-3{ grid-row: 3;}

.col-1{ grid-column: 1;}
.col-2{ grid-column: 2;}
.col-3{ grid-column: 3;}
<div class="datatable">
   <div class="datacell col-1 row-1">Row 1 Column 1</div>
   <div class="datacell col-2 row-1">Row 1 Column 2</div>
   <div class="datacell col-3 row-1">Row 1 Column 3</div>       
   <div class="datarow row-1"></div>

   <div class="datacell col-1 row-2">Row 2 Column 1</div>
   <div class="datacell col-2 row-2">Row 2 Column 2</div>
   <div class="datacell col-3 row-2">Row 2 Column 3</div>       
   <div class="datarow row-2"></div>

   <div class="datacell col-1 row-3">Row 3 Column 1</div>
   <div class="datacell col-2 row-3">Row 3 Column 2</div>
   <div class="datacell col-3 row-3">Row 3 Column 3</div>       
   <div class="datarow row-3"></div>

</div>

The html must be structured so that a .datarow element closes the virtual grid row and spans all the preceding cells. Explicitation of the positioning inside the grid is needed in order to let cells and rows overlap.

Share:
17,320
Nguyen Trung Hieu
Author by

Nguyen Trung Hieu

I'm like everything about code

Updated on July 30, 2022

Comments

  • Nguyen Trung Hieu
    Nguyen Trung Hieu almost 2 years

    This a table that created with CSS Grid Layout, but I have a problem with it, I can't make hover state on each row.

    I only want use CSS for this.

    Can anyone give me a solution for this?

    .table {
      display: grid;
      grid-template-columns: [col-start] auto [col-end];
      grid-template-rows: [header-start] 50px [header-end row-start] auto [row-end];
      grid-auto-rows: auto;
      grid-auto-columns: auto;
      grid-gap: 1px;
    }
    
    .table>* {
      background: gray;
      padding: 10px;
    }
    
    .heading {
      background: navy;
      color: #fff;
      grid-row: header;
    }
    <div class="table">
      <div class="heading">Title 1</div>
      <div class="heading">Title 2</div>
      <div class="heading">Title 3</div>
      <div class="heading">Title 4</div>
      <div class="heading">Title 5</div>
    
      <div class="row">Row 1</div>
      <div class="row">Row 1</div>
      <div class="row">Row 1</div>
      <div class="row">Row 1</div>
      <div class="row">Row 1</div>
    
      <div class="row">Row 2</div>
      <div class="row">Row 2</div>
      <div class="row">Row 2</div>
      <div class="row">Row 2</div>
      <div class="row">Row 2</div>
    
      <div class="row">Row 3</div>
      <div class="row">Row 3</div>
      <div class="row">Row 3</div>
      <div class="row">Row 3</div>
      <div class="row">Row 3</div>
    </div>

  • Nguyen Trung Hieu
    Nguyen Trung Hieu over 6 years
    Why we need row::after?
  • Temani Afif
    Temani Afif over 6 years
    @NguyenTrungHieu the after is to re-create the border missed by the before
  • Temani Afif
    Temani Afif over 6 years
    @NguyenTrungHieu oh i see, didn't notice this ... will try to fix the span issue
  • Nguyen Trung Hieu
    Nguyen Trung Hieu over 6 years
    @TemaniAfif I see, so weird and I trying to find a solution for this
  • Temani Afif
    Temani Afif over 6 years
    @NguyenTrungHieu not weird but logic :) it's because the element are overlowing and with z-index only the last one is triggered. By the way i find a fix to the issue, you can see .. now i only missed some border
  • Temani Afif
    Temani Afif over 6 years
    @NguyenTrungHieu i find a trick to the border also ;) you can check
  • Temani Afif
    Temani Afif over 6 years
    @NguyenTrungHieu well, if you change the structure you will for sure have some issue :) as the solution it not 100% generic since it rely on some hacky trick, so maybe the code need to adjusted. And for the blink simply remive the transition if you don't need it;)
  • Dragonthoughts
    Dragonthoughts almost 6 years
    Please include an explanation of why this is the answer.
  • dehumanizer
    dehumanizer over 5 years
    this will not work for the set up where grid-template-column has auto, because some content may expand a column in one row more than in the other
  • JohnF
    JohnF almost 5 years
    This is a neat solution. Note to others who accidentally tried to add background to the rowWrapper itself and got confused because it "doesn't exist": Set background on the children of the rowWrapper.
  • user2683246
    user2683246 almost 5 years
    That's buggy when cell contents' text is long enough to wrap over multiple lines.
  • Prinzhorn
    Prinzhorn over 4 years
    You can only slightly notice it in this example, but the hover does not work on the gap (1px in this case) in Firefox. Works in Chrome.
  • nether_cat
    nether_cat over 4 years
    Sorry. I think this absolutely is not an answer at all. I don't see how the proposed attribute would help the author in any way I could think of. Your mentioned class .grid-item was not even specified in the original example, and if you're referring to the grid cells in general, which the author classified with .row, I still don't see how your proposal would achieve anything here.
  • richardaum
    richardaum over 3 years
    Also it works only for solid colors hover effect - if you want to add o shadow on the entire row, it isn't possible using this approach.
  • Vinícius Negrão
    Vinícius Negrão about 3 years
    I really should try to keep up with the new aditions to css, display: contents is a killer feature. Thank you a lot, you saved me!
  • Nathan Goings
    Nathan Goings about 3 years
    display: contents is unsupported in IE11. FYI
  • Maciej Kwas
    Maciej Kwas about 3 years
    @NathanGoings IE11 is unsupported by Microsoft FYI
  • Nathan Goings
    Nathan Goings about 3 years
    @MaciejKwas, I'm seeing June 2022 as end-of-support. Considering that 365 still supports it, I'm not sure where you got your info.
  • Maciej Kwas
    Maciej Kwas about 3 years
    @NathanGoings You mean end-of-technical-support. Official Microsoft Edge docs: "[...]Site developers should focus their testing on Microsoft Edge for new and existing experiences. Internet Explorer 11 will be included for some legacy scenarios [...]". Last feature update for IE11 was in 2015, now it's 2021 and IE is gone for good. 365 support doesn't mean anything, they could support even IE6 if they want to, yet- end of features development is the end of support.: blogs.windows.com/windowsexperience/2021/05/19/…
  • Nathan Goings
    Nathan Goings about 3 years
    @MaciejKwas, feature support and security support are two different things. There are plenty of enterprise web-developers who are stuck with supporting IE11 because it's still usable by their company. Thankfully, in my enterprise, IE11 will be dropped when security support ends.
  • Maciej Kwas
    Maciej Kwas about 3 years
    @NathanGoings nope, they are not stuck. When I was forced to support IE11 in my company- I left it, and it was 2017 back then. It is company problem that it can not port to new technologies easily, not the developers problem. I can't imagine learning new stuff, discovering new technologies and on the other hand still supporting IE11. Cheers :)
  • doctorgu
    doctorgu over 2 years
    This is simplest solution I ever saw. I learned + and ~ sibling combinator from this answer. Thank you.