网格单元格上 100% 宽度的水平滚动

horizontal scroll with 100% width on grid cell

我想要一个 css 网格,在网格的每个单元格内,我想要一个最大尺寸为单元格宽度 100% 的标题。如果标题太长,我想滚动。

这是目前滚动行为正确但长标题宽度固定的情况。我想要的不是固定宽度,而是单元格宽度的 100%(因此灰色块应该与红色框一样长)

codePen: https://codepen.io/vincent2303/pen/ExwZEpW

* {
  margin: 0;
  padding: 0;
}

body {
  padding: 50px;
}

h2 {
  font-size: 2em;
  white-space: nowrap;
}

.grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  width: 800px;
  gap: 20px;
}

.box {
  background-color: #e74c3c;
  height: 30vh;
}

.title-wrapper {
  background-color: #bdc3c7;
  width: 300px;
  overflow-x: scroll;
}
<div class=grid>

  <div>
    <div class="title-wrapper">
      <h2>long title, i can scroll---------</h2>
    </div>

    <div class="box"></div>
  </div>

  <div>
    <h2>Short title</h2>
    <div class="box"></div>
  </div>

</div>

有人有想法吗?

注意:为了简化代码示例,.grid class 的宽度为 800px 但实际上,它的宽度由其 parent 定义我无法预测宽度(我正在开发一个 React 应用程序,这段代码将实现一个在多个不同大小的地方使用的组件)。

正如这里评论的那样,有可能:

* {
  margin: 0;
  padding: 0;
}

body {
  padding: 50px;
}

h2 {
  font-size: 2em;
  
  white-space: nowrap;
}

.grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  width: 800px;
  gap: 20px;
}

.box {
  background-color: #e74c3c;
  height: 50vh;
  max-width: 400px;
}

.title-wrapper {
  background-color: #bdc3c7;
  width: 100%;
  overflow-x: scroll;
}
<div class=grid >

    <div>
    

      <div class="box" >
          <div class="title-wrapper" >
        <h2>long title, i can scroll---------------------------------</h2>
      </div>
      </div>
    </div>

    <div>
    
      <div class="box" >
          <h2>Short title</h2>
      </div>
    </div>

 </div>

没有 JavaScript 似乎很难,Dev 他的答案有效,但它涉及固定的最大宽度。

我有一个 JavaScript 的解决方案似乎有效。

    /* Execute when the DOM is loaded, because otherwise the HTML elements might nog be in the DOM. */
    window.addEventListener( 'DOMContentLoaded', () => {

        generateGridItemsWidthVariable()

    } )

    /* Execute when the window is resized, because the width of the boxes might change. */
    window.addEventListener( 'resize', () => {

        generateGridItemsWidthVariable()

    } )

    /* Generate the variable for the grid items. */
    function generateGridItemsWidthVariable() {

        /* Select all the grid items and create an array to loop trough. */
        let gridItems = Array.from( document.getElementsByClassName( 'grid__item' ) )

        /* Loop trough the grid items. */
        gridItems.forEach( gridItem => {

            /* Reset the grid item width, because otherwise the item won't resize. */
            gridItem.style.setProperty( '--grid-item--width', '' )

            /* Get the width of the grid item. */
            let gridItemWidth = gridItem.clientWidth.toString()
            /* Set the width of the grid item as a CSS variable. */
            gridItem.style.setProperty( '--grid-item--width', gridItemWidth + 'px' )

        } )

    }
    * {
        margin: 0;
        padding: 0;
    }

    body {
        padding: 50px;
    }

    h2 {
        font-size: 2em;
        white-space: nowrap;
    }

    .grid {
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        width: 100%;
        max-width: 800px;
        gap: 20px;
    }

    .grid__item {
        --grid-item--width: 10px;
    }

    .box {
        background-color: #e74c3c;
        height: 30vh;
    }

    .title-wrapper {
        background-color: #bdc3c7;
        width: 100%;
    }
    .title-wrapper h2 {
        max-width: var(--grid-item--width);
        overflow-x: scroll;
    }
<div class=grid >

    <div class="grid__item">
        <div class="title-wrapper" >
            <h2>long title, i can scroll-----------------------</h2>
        </div>

        <div class="box" ></div>
    </div>

    <div class="grid__item">
        <h2>Short title</h2>
        <div class="box" ></div>
    </div>

</div>

如果您的网格可能包含溢出的内容,您将无法使用 1fr,原因如下:

  • 1fr 只是 minmax(auto, 1fr).
  • 的缩写
  • minmax(a, b) 变为 a(没有任何 minmax)当 a >= btrue.
  • 因此在您的情况下,您的网格的行为就好像您将其定义为 grid-template-columns: auto 1fr;,因为第一列的 auto 大于 1fr

要解决这个问题,您需要告诉您的网格,当内容变得太宽时不允许扩展单元格。

使用minmax(0, 1fr)代替1fr:

* {
  margin: 0;
  padding: 0;
}

body {
  padding: 50px;
}

h2 {
  font-size: 2em;
  white-space: nowrap;
}

.grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  width: 800px;
  gap: 20px;
}

.box {
  background-color: #e74c3c;
  height: 30vh;
}

h2 {
  background-color: #bdc3c7;
  overflow-x: scroll;
}
<div class=grid>

  <div>
    <h2>long title, i can scroll------------------ - - - - ----</h2>
    <div class="box"></div>
  </div>

  <div>
    <h2>Short title</h2>
    <div class="box"></div>
  </div>

</div>

那么 1fr 解析为 minmax(auto, 1fr),这意味着网格列的最小宽度为 min-content,即大于 1fr。有一个快速解决这个问题的方法,只需将 1fr 替换为 minmax(0px, 1fr),这样,父级的宽度就分为两列,这样你就可以得到你想要的滚动条。

* {
  margin: 0;
  padding: 0;
}

body {
  padding: 50px;
}

h2 {
  font-size: 2em;
  white-space: nowrap;
}

.grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
}

.box {
  background-color: #e74c3c;
  height: 30vh;
}

h2 {
  background-color: #bdc3c7;
  overflow-x: auto;
}
<div class=grid>

  <div>
    <h2>long title, i can scroll----------------------------</h2>
    <div class="box"></div>
  </div>

  <div>
    <h2>Short title</h2>
    <div class="box"></div>
  </div>

</div>