首页 > 解决方案 > 在 CSS Grid 中相互流动的元素

问题描述

有没有更自动的方式让数据围绕元素流动?我觉得我已经非常接近 CSS Grid 了,但是 Grid 中有很多我还没有找到的角落和缝隙,所以也许我只需要添加一些额外的规则。

这是我正在尝试做的事情:

  1. 在右侧显示一个元素
  2. 让其他元素围绕它流动

这将非常类似于在 MS Word 或 Google Docs 中,您在右上角有一个图像,所有文本都围绕它流动,但使用元素而不是文本。

我在下面的片段中所拥有的主要是我想要的,但以下情况除外:

  1. 当第一个section很短时,有足够的空间放置第 4 个部分aside。使用当前方法要使其正常工作,我需要更改grid-row: 1 / 4grid-row: 1 / 5并添加aside ~ section:nth-of-type(4)到窄列表中sections

  2. 当第一个section很高时,section它下面的一个 s 远远超过aside,所以它应该占据完整的 5 个网格列。

在这个片段中,高度是静态的,但在现实世界中它们是动态的。有没有更自动的方法来用 CSS Grid 解决这个问题?我能想到的唯一其他方法是使用 javascript 检测大小并根据各种元素的高度添加类或内联 css。

document.querySelector('button').addEventListener('click', () => {
  const aside = document.querySelector('aside');
  if (aside) {
    aside.remove();
  } else {
    document.querySelector('main').prepend(document.createElement('aside'));
  }
});

document.querySelector('a').addEventListener('click', (event) => {
  event.target.parentElement.classList.toggle('tall');
});
main {
  display: grid;
  padding: 5px;
  margin: 5px;
  grid-gap: 5px;
  background-color: gray;
  
  grid-template-columns: repeat(5, 1fr);
}

aside {
  height: 120px;
  background-color: green;
  
  grid-column: 4 / 6;
  grid-row: 1 / 4;
}

section {
  height: 20px;
  background-color: white;
  
  grid-column-end: span 5;
}

section.tall {
  height: 100px;
}

aside ~ section:nth-of-type(1),
aside ~ section:nth-of-type(2),
aside ~ section:nth-of-type(3) {
  grid-column-end: span 3;
}
<button>Toggle Aside</button>
<main>
  <aside></aside>
  <section><a href="javascript://">Toggle Height</a></section>
  <section></section>
  <section></section>
  <section></section>
  <section></section>
  <section></section>
</main>

标签: csscss-grid

解决方案


看起来这个问题最简单的解决方案是使用 good oldfloat属性,这会导致其他元素“开箱即用”地围绕给定元素流动。唯一需要添加的是使这些部分建立新的块格式上下文,以防止它们与浮动元素重叠(display: block默认情况下元素会这样做)。有几种方法可以做到这一点,包括标准(但不幸的是,还不是跨浏览器)解决方案 - display: flow-root.

document.querySelector('button').addEventListener('click', () => {
  const aside = document.querySelector('aside');
  if (aside) {
    aside.remove();
  } else {
    document.querySelector('main').prepend(document.createElement('aside'));
  }
});

document.querySelector('a').addEventListener('click', (event) => {
  event.target.parentElement.classList.toggle('tall');
});
main {
  /* the display:flow-root alternative with the best balance
     between browser support and unwanted side effects (IMO).
     Other alternatives live comparison: https://codepen.io/SelenIT/pen/qrORXm */
  column-count: 1;

  padding: 5px 5px 0;
  margin: 5px;
  background-color: gray;
}

aside {
  height: 120px;
  width: calc((100% - 20px) * 0.4); /* 2/5 of (100% - 4 gaps of 5px each) */
  background-color: green;
  margin: 0 0 5px 5px;
  float: right;
}

section {
  column-count: 1;
  height: 20px;
  background-color: white;
  margin-bottom: 5px;
}

section.tall {
  height: 100px;
}
<button>Toggle Aside</button>
<main>
  <aside></aside>
  <section><a href="javascript://">Toggle Height</a></section>
  <section></section>
  <section></section>
  <section></section>
  <section></section>
  <section></section>
</main>


推荐阅读