如何使用CSS网格布局在表格行上创建悬停状态

50

这是使用CSS网格布局创建的表格,但我遇到了问题,无法对每行进行悬停状态的设置。

我只想使用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;
}

.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>

7个回答

73

由于您将其视为表格,其中元素保持在同一行中,因此您还可以将每一行包装在“display”设置为“contents”的DIV中。这形成了一个无害的父元素,您可以用于悬停,然后样式化子元素。(但是,在Edge中不支持"display: contents"。)

.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>


3
这是一个巧妙的解决方案。提醒其他误将背景添加到rowWrapper本身并感到困惑的人:在rowWrapper的子元素上设置背景。 - JohnF
1
在这个例子中,你只能稍微注意到它,但在 Firefox 中,悬停在空隙(在本例中为 1px)上是不起作用的。在 Chrome 中可以工作。 - Prinzhorn
1
@NathanGoings FYI,微软已经不再支持IE11。 - Maciej Kwas
1
@NathanGoings 你的意思是技术支持结束了。微软官方Edge文档中写道:“[...]网站开发人员应该将测试重点放在Microsoft Edge上,以获得新的和现有的体验。Internet Explorer 11将包括一些传统场景[...]”。IE11的最后一个功能更新是在2015年,现在已经是2021年了,IE已经彻底消失了。365的支持并不意味着什么,如果他们愿意,甚至可以支持IE6,然而,功能开发的终止就是支持的终止。:https://blogs.windows.com/windowsexperience/2021/05/19/the-future-of-internet-explorer-on-windows-10-is-in-microsoft-edge/ - Maciej Kwas
2
@NathanGoings 不,他们并没有被困住。当我被迫在公司支持IE11时,我离开了它,那时是2017年。这是公司无法轻松移植到新技术的问题,而不是开发人员的问题。我无法想象学习新东西、发现新技术,同时还要支持IE11。干杯 :) - Maciej Kwas
显示剩余5条评论

18
这里有一个使用伪元素的技巧。想法是将该元素用作背景,并使其向左和向右溢出,以便覆盖整个行。这样,如果你悬停在一行内的任何元素上,你就可以改变颜色,就像你改变了整行的颜色。
这个技巧涉及对标记的一些更改以及更多的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>


为什么我们需要使用row::after? - Nguyen Trung Hieu
1
@NguyenTrungHieu,接下来需要重新创建之前遗漏的边框。 - Temani Afif
@NguyenTrungHieu 不是奇怪,而是逻辑 :) 这是因为元素溢出,并且只有最后一个被触发了 z-index。顺便说一下,我找到了解决问题的方法,你可以看到..现在我只错过了一些边框。 - Temani Afif
@NguyenTrungHieu 我发现了一个边框的技巧 ;) 你可以看一下。 - Temani Afif
当单元格内容的文本足够长以至于需要换行时,那就会出现错误。 - user2683246
显示剩余4条评论

7

以下是我基于兄弟组合器的解决方案。
主要部分如下:

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

片段:

.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>

HTML必须被结构化,以便.datarow元素关闭虚拟网格行并延伸到所有前置单元格。在网格内明确定位是必要的,以便让单元格和行重叠。


这是我见过的最简单的解决方案。我从这个答案中学到了+~兄弟组合器。谢谢。 - doctorgu

1

我最终采用了不同的解决方案。我的表格看起来像这样:

.table {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
<div class="table">
  <span>head1</span>
  <span>head2</span>
  <span>head3</span>
  <span>row1 col1</span>
  <span>row1 col2</span>
  <span>row1 col3</span>
  <span>row2 col1</span>
  <span>row2 col2</span>
  <span>row2 col3</span>
</div>

现在您想要每一行的悬停状态。添加包装每一行的元素会破坏父网格,因为它们实际上是您尝试在网格中布置的那些行包装器的子级。此外,我更喜欢:
- 不使用<table>,这大约使所需的行数增加了一倍,并需要更多的样式。 - 不使用令人困惑的nth-child。 - 我没有尝试过的一个不错的选择似乎是将每一行包装在一个div中,添加一个类.rowdisplay: contents,然后使用.row:hover > span作为选择器,您可以添加opacity: 0.6。看起来不错!其他一些答案也朝着这个方向发展。
最终,我采用了以下方法,我认为它更简单:

.row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.row:hover {
  opacity: 0.6
}
<div class="row">
  <span>head1</span>
  <span>head2</span>
  <span>head3</span>
</div>
<div class="row">
  <span>row1 col1</span>
  <span>row1 col2</span>
  <span>row1 col3</span>
</div>
<div class="row">
  <span>row2 col1</span>
  <span>row2 col2</span>
  <span>row2 col3</span>
</div>


0
如今的解决方案是子网格。它解决了主网格中间隙的问题,标记语言与和有些相似,意味着你可以嵌套使用。
<div class="my-subgrid-row">
  <div class="cell-col1"></div>
  <div class="cell-col2"></div>
  ...
</div>

而且CSS非常直接,没有太多的技巧。


-3
我有解决您问题的方案。以下是示例:

.grid .row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-bottom: 1px solid gray;
}
.grid .row div {
  padding: 10px;
  display: flex;
  align-items: center;
}
.grid .row:last-child {
  border: none;
}
.grid .row:hover {
  background-color: #cccccc;
  transition: .2s all;
}
<div class='grid'>
  <div class='row'>
    <div>Header</div>
    <div>Header</div>
    <div>Header</div>
    <div>Header</div>
  </div>
  <div class='row'>
    <div>Content</div>
    <div>Content</div>
    <div>Content</div>
    <div>Content</div>
  </div>
  <div class='row'>
    <div>Content</div>
    <div>Content</div>
    <div>Content</div>
    <div>Content</div>
  </div>
  <div class='row'>
    <div>Content</div>
    <div>Content</div>
    <div>Content</div>
    <div>Content</div>
  </div>
</div>


请提供答案解释。 - Dragonthoughts
5
这种设置中,如果grid-template-column使用了auto,则此方法无法正常工作,因为某些内容在一行中可能会比另一行更多地扩展列。 - dehumanizer

-5

我曾经遇到过这个问题。首先,我很好奇如果你正在使用display grid,为什么不使用grid-item类呢?这不是必要的吗?我认为是的。无论如何,答案是,你需要给所有的div元素添加grid-item类,并将位置设置为相对定位。

.grid-item {
  position: relative;
}

抱歉。我认为这根本不是一个答案。我无法看出提出的属性如何帮助作者,即使我能想到任何方式。您提到的类 .grid-item 在原始示例中甚至未被指定,如果您正在引用一般的网格单元格,该作者使用 .row 进行分类,我仍然看不到您的建议如何在这里实现任何东西。 - nether_cat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接