布局取决于元素的数量
Posted
技术标签:
【中文标题】布局取决于元素的数量【英文标题】:Layout depending on number of elements 【发布时间】:2019-07-14 14:17:24 【问题描述】:我有一个可以包含 2、3 或 4 个元素的包装器(我事先不知道,因为每个元素都会呈现自己,具体取决于 API 响应)。
如果有 3 个(或更少),我希望它们像这样堆叠:
没什么大不了的。但是当有 4 个时,我需要这个其他布局:
到目前为止,我认为 CSS Grid 是可行的方法,我尝试了:
/* Just to add some interaction to the demo */
const w = document.getElementById("wrapper");
let x;
function toggle(event)
const d = document.getElementById("D");
return d
?
x = d.cloneNode() && w.removeChild(d)
: w.appendChild(x);
#wrapper
width: 100%;
max-width: 500px;
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 10px;
.item
grid-column-start: span 2
.item:nth-last-child(1),
.item:nth-last-child(2)
grid-column-start: auto;
/* Non-relevant CSS here: */
button
margin: 20px auto;
font-size: 16px;
padding: 3px 6px;
border-radius: 6px;
#A background: #7984f7
#B background: #cb8af8
#C background: #8cd4fb
#D background: #97f8d8
.item
border-radius: 6px;
padding: 10px 0;
font-family: sans-serif;
font-weight: bold;
color: white;
text-align: center;
<div id="wrapper">
<div id="A" class="item">A</div>
<div id="B" class="item">B</div>
<div id="C" class="item">C</div>
<div id="D" class="item">D</div>
</div>
<button onclick="toggle()">Click me!</button>
但它不适用于 3 个元素...事实上,我已经尝试了很多东西(所有 CSS 网格相关)并且可能有一个更简单的解决方案我现在看不到...任何帮助都会非常感谢!
【问题讨论】:
【参考方案1】:您可以使用:nth-child(n+4)
选择第三个孩子之后的元素,使用:nth-child(n+3)
选择第二个孩子之后的元素,然后变出:
.item:nth-child(n+4):nth-last-child(1),
.item:nth-child(n+3):nth-last-child(2)
grid-column-start: auto;
现在您已经获得了您搜索的网格配置 - 这将适用于 任何 个 item
元素 - 请参见下面的演示:
/* Just to add some interaction to the demo */
const w = document.getElementById("wrapper");
let x;
function toggle(event)
const d = document.getElementById("D");
return d ?
x = d.cloneNode() && w.removeChild(d) :
w.appendChild(x);
#wrapper
width: 100%;
max-width: 500px;
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 10px;
.item
grid-column-start: span 2;
/* CHANGED THIS */
.item:nth-child(n+4):nth-last-child(1),
.item:nth-child(n+3):nth-last-child(2)
grid-column-start: auto;
/* Non-relevant CSS here: */
button
margin: 20px auto;
font-size: 16px;
padding: 3px 6px;
border-radius: 6px;
#A
background: #7984f7
#B
background: #cb8af8
#C
background: #8cd4fb
#D
background: #97f8d8
.item
border-radius: 6px;
padding: 10px 0;
font-family: sans-serif;
font-weight: bold;
color: white;
text-align: center;
<div id="wrapper">
<div id="A" class="item">A</div>
<div id="B" class="item">B</div>
<div id="C" class="item">C</div>
<div id="D" class="item">D</div>
</div>
<button onclick="toggle()">Click me!</button>
【讨论】:
【参考方案2】:我建议使用 flexbox。对于给定的三种可能性,请在下面的 sn-p 中使用这个简单的 css。
基本上,您可以使项目连续显示,但如果它们不合适,则进行包装。您使前两个元素占据所有宽度,以便每行只有一个。对于第 3 次和第 4 次,您将它们的 flex-basis(初始宽度)设置为更小,并在有空间的情况下使它们增长(flex-grow:1)。
.examples
display: flex;
flex-direction: row;
align-items: flex-start;
.container
width: 200px;
border: 1px solid red;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: flex-start;
.box
height: 50px;
background-color: blue;
margin: 5px;
border-radius: 5px;
flex-basis: 200px;
.box:nth-child(3), .box:nth-child(4)
flex-basis: 50px;
flex-grow: 1;
<div class="examples">
<div class="container">
<div class="box"></div>
<div class="box"></div>
</div>
<div class="container">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
<div class="container">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</div>
解决方案也在这里:JSFiddle
【讨论】:
如果您不必去其他网站就可以看到答案,答案会更好。考虑使用Stack Snippets 在 Stack Overflow 上嵌入一个可运行的 sn-p。请注意,您可以单击 Copy sn-p to answer 按钮以使其更容易。 好电话,@HereticMonkey。我添加了 sn-p - 感谢您的提示。【参考方案3】:或者,您可以使用 flexbox 来做类似的事情,而不是使用网格设置。 我个人认为 flexbox 是一个更有用/更强大的工具,它可以让事情变得响应而不以丑陋的方式破坏。添加响应式样式以进行相应修改很容易。
你可以这样做:
#wrapper
width: 100%;
max-width: 500px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
.item:first-of-type
width: 100%;
.item:nth-of-type(2)
width: 100%;
.item:nth-of-type(3):last-of-type
width: 100%;
.item:nth-of-type(3)
width: 50%;
.item:nth-of-type(4)
width: 50%;
这样,如果您有第 5 或第 6(或等)项,并且您希望它们的宽度根据元素的数量而变化,您可以在这里做类似的事情。如果您查看我的演示,如果您删除第 4 项,则作为最后一个元素的第 3 项将具有 100% 的宽度。
CodePen rough example
【讨论】:
如果您不必去其他网站就可以看到答案,答案会更好。考虑使用 Stack Snippets 在 Stack Overflow 上嵌入可运行的 sn-p。【参考方案4】:这是一个有效的技巧。
第三个孩子也是倒数第二个,第四个孩子的 grid-column-start 将设置为 auto。
.item:nth-child(3):nth-last-child(2),
.item:nth-child(4)
grid-column-start: auto;
如果您希望将第 4 位以上的所有孩子分成两列,请稍作调整。
.item:nth-child(3):nth-last-child(2),
.item:nth-child(n+4)
grid-column-start: auto;
/* Just to add some interaction to the demo */
const w = document.getElementById("wrapper");
let x;
function toggle(event)
const d = document.getElementById("D");
return d
?
x = d.cloneNode() && w.removeChild(d)
: w.appendChild(x);
#wrapper
width: 100%;
max-width: 500px;
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 10px;
.item
grid-column-start: span 2
.item:nth-child(3):nth-last-child(2),
.item:nth-child(n+4)
grid-column-start: auto;
/* Non-relevant CSS here: */
button
margin: 20px auto;
font-size: 16px;
padding: 3px 6px;
border-radius: 6px;
#A background: #7984f7
#B background: #cb8af8
#C background: #8cd4fb
#D background: #97f8d8
.item
border-radius: 6px;
padding: 10px 0;
font-family: sans-serif;
font-weight: bold;
color: white;
text-align: center;
<div id="wrapper">
<div id="A" class="item">A</div>
<div id="B" class="item">B</div>
<div id="C" class="item">C</div>
<div id="D" class="item">D</div>
</div>
<button onclick="toggle()">Click me!</button>
【讨论】:
【参考方案5】:使用 CSS 网格:
-
默认在两列中显示所有项目
在单列中显示项目 1 和 2
仅当第 3 项为最后一项时,才将第 3 项显示在单列中
一个副作用是,如果超过 4 个项目,额外的项目将显示在两列中。
/* Just to add some interaction to the demo */
const w = document.getElementById("wrapper");
let x;
function toggle(event)
const d = document.getElementById("D");
return d
?
x = d.cloneNode() && w.removeChild(d)
: w.appendChild(x);
#wrapper
width: 100%;
max-width: 500px;
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 10px;
.item
grid-column-start: auto;
.item:nth-child(1),
.item:nth-child(2),
.item:nth-child(3):last-child
grid-column-start: span 2;
/* Non-relevant CSS here: */
button
margin: 20px auto;
font-size: 16px;
padding: 3px 6px;
border-radius: 6px;
#A background: #7984f7
#B background: #cb8af8
#C background: #8cd4fb
#D background: #97f8d8
.item
border-radius: 6px;
padding: 10px 0;
font-family: sans-serif;
font-weight: bold;
color: white;
text-align: center;
<div id="wrapper">
<div id="A" class="item">A</div>
<div id="B" class="item">B</div>
<div id="C" class="item">C</div>
<div id="D" class="item">D</div>
</div>
<button onclick="toggle()">Click me!</button>
【讨论】:
以上是关于布局取决于元素的数量的主要内容,如果未能解决你的问题,请参考以下文章
如何添加多个图像/元素,其中数量取决于 user.variable?
CSS中Flex布局控制每row的元素数量(没行3个)的问题