复杂的CSS布局 - 弹性框还是网格?



我希望实现一个复杂的布局(见下面的图 1-4(,其中我有三个主要元素:标题、侧元素和标签。标题应跨越整个宽度,侧元素应向右浮动并跨越容器的整个高度,然后标签(可能有很多(应括在标题下。

___________________________   ____
|                           | |    |
|   lorem ipsum dolor ...   | |    |
|___________________________| |    |
______   _______   ______    | XX |
|      | |       | |      |   |    |
|  ab  | |  cde  | |  fg  |   |    |
|______| |_______| |______|   |____|

先决条件:

  1. .title应尽可能
  2. .side.tag的宽度应该与其内容一样宽,以便尽可能
  3. 任何元素的大小都是未知的,因此我不能使用固定的宽度或百分比(显然 100% 除外(。
  4. 该解决方案应该适用于任何容器宽度。
  5. .side.tag可选的,因此如果缺少它们,解决方案应该有效。
  6. 所有元素都是同级,这意味着我不能将所有.tag都包装在一个div中。
  7. .side元素在源代码中始终排在最后,因此下面的order属性。

请参阅我希望涵盖的用例:

  • 图 1:标题、侧元素和一些标签
  • 图 2:标题、侧元素和更多标签
  • 图 3:仅标题和几个标签
  • 图 4:仅标题和侧面元素

.container {
display: flex;
flex-flow: row wrap;
width: 100%;
}
.title {
order: 1;
flex-grow: 1;
flex-basis: 100%;
}
.side, .tag {
flex-grow: 0;
flex-basis: auto;
}
.side {
order: 2;
}
.tag {
order: 3;
}
/* sample styling - ignore */
.container { width: 100%; }
.title, .tag, .side { padding: 30px; margin: 5px; color: white; font-family: Arial; font-size: 24px; }
.title { background: coral; }
.tag { background: cornflowerblue; }
.side { background: mediumseagreen; }
<h2>Case 1</h2>
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
<div class='tag'>abc</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='side'>XX</div>
</div>
<h2>Case 2</h2>
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
<div class='tag'>abc</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>jkl</div>
<div class='tag'>mno</div>
<div class='tag'>pqr</div>
<div class='side'>XX</div>
</div>
<h2>Case 3</h2>
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
<div class='tag'>abc</div>
<div class='tag'>def</div>
</div>
<h2>Case 4</h2>
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
<div class='side'>XX</div>
</div>

我的问题

实现这种复杂的灵活布局的最佳方法是什么?我可以使用flexbox使上述所有用例都正常工作,还是应该更多地研究网格?

谢谢!

我怀疑flexbox能否满足所有要求。

这是一个缺点很少的CSS网格近似值:

  • 所有标签将具有相同的宽度,并且宽度由容器控制,而不是其内容
  • 如果缺少侧元素,我们将有一个空单元格(正在努力为此找到解决方案(

.container {
display: grid;
border:1px solid;
grid-template-columns:repeat(auto-fit,minmax(100px,1fr));
}
.title {
grid-column:1 / -2;
}
.title + .tag {
grid-column:1;
}
.side {
grid-column:-2;
grid-row: 1/span 1000;
}
/* sample styling - ignore */
.title,
.tag,
.side {
padding: 30px;
margin: 5px;
color: white;
font-family: Arial;
font-size: 24px;
}
.title {
background: coral;
}
.tag {
background: cornflowerblue;
}
.side {
background: mediumseagreen;
}
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
<div class='side'>XX</div>
</div>
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
</div>
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
<div class='tag'>abc</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>gh</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='side'>XX</div>
</div>
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
<div class='tag'>abc</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>ghi</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
</div>

根据这里的评论,这是一个解决方案,其中侧面元素将只占一行:

.container {
display: flex;
flex-wrap:wrap;
border:1px solid;
}
.title {
order:-2;
flex-grow:1;
flex-basis:0;
min-width:0;
}
.side {
order:-1;
}
.container:before {
content:"";
flex-basis:100%;
}
/* sample styling - ignore */
.title,
.tag,
.side {
padding: 30px;
margin: 5px;
color: white;
font-family: Arial;
font-size: 24px;
}
.title {
background: coral;
}
.tag {
background: cornflowerblue;
}
.side {
background: mediumseagreen;
}
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
<div class='side'>XX</div>
</div>
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
</div>
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
<div class='tag'>abc</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>gh</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='side'>XX XX</div>
</div>
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
<div class='tag'>abc</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>ghi</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
</div>


由于我认为仅靠CSS无法实现这一点,因此这里有一个JS解决方案:

var cs = document.querySelectorAll('.container');
cs.forEach((a) => {
var side = a.querySelector('.side');
if(side)
a.style.paddingRight = (side.offsetWidth + 10) + "px";
});
.container {
display: flex;
flex-wrap:wrap;
border:1px solid;
padding-right: 0px;
position:relative;
}
.title {
flex-basis:100%;
}
.side {
position:absolute;
top:0;
bottom:0;
right:0;
}
/* sample styling - ignore */
.title,
.tag,
.side {
padding: 30px;
margin: 5px;
color: white;
font-family: Arial;
font-size: 24px;
}
.title {
background: coral;
}
.tag {
background: cornflowerblue;
}
.side {
background: mediumseagreen;
}
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
<div class='side'>XX</div>
</div>
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
</div>
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
<div class='tag'>abc</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>gh</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='side'>XX XX</div>
</div>
<div class='container'>
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
<div class='tag'>abc</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>ghi</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
</div>

我更改了 HTML,这是我的解决方案,请检查。 希望这对:)有所帮助

.container {
display: flex;
width: 100%;
}
.title {
order: 1;
flex-grow: 1;
flex-basis: 100%;
}
.side, .tag {
flex-grow: 0;
flex-basis: auto;
}
.side {
order: 2;
}
.tag {
order: 3;
}
.content-page {
width: 100%;
}
.content-tags {
display: flex;
flex-wrap: wrap;
}
/* sample styling - ignore */
.container { width: 100%; }
.title, .tag, .side { padding: 30px; margin: 5px; color: white; font-family: Arial; font-size: 24px; }
.title { background: coral; }
.tag { background: cornflowerblue; }
.side { background: mediumseagreen; }
<div class='container'>
<div class="content-page">
<div class='title'>
Lorem ipsum dolor sit amet...
</div>
<div class="content-tags">
<div class='tag'>abc</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>abc</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
<div class='tag'>def</div>
<div class='tag'>ghi</div>
</div>
</div>
<div class='side'>XX</div>
</div>

最新更新