使用网格在列之前生成行



我有一个元素数量可变的网格,但它应该总是有3列:

<div class="grid grid-cols-3">
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
<span>5</span>
<span>6</span>
<span>7</span>
<span>8</span>
<span>9</span>
<span>10</span>
<span>11</span>
<span>12</span>
<span>13</span>
</div>

通过上面的内容,我得到了3列,但元素首先被放入列中,如下所示:

1   2   3
4   5   6
7   8   9
10  11  12
13

然而,我希望元素先放入行中,如下所示:

1   6   11
2   7   12
3   8   13
4   9   
5   10 

这是否可能只使用网格,而不必修改类,因为元素的数量不同?(没有JavaScript!)

尝试网格行-3和grid-flow-col

span {
border: 1px solid red;
}
<script src="https://cdn.tailwindcss.com"></script>
<div class="grid grid-rows-3 grid-flow-col">
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
<span>5</span>
<span>6</span>
<span>7</span>
<span>8</span>
<span>9</span>
</div>

使用尾风属性grid-rows-3grid-flow-col生成如下列表:

<div class="grid grid-rows-3 grid-flow-col gap-4">
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
<span>5</span>
<span>6</span>
<span>7</span>
<span>8</span>
<span>9</span>
</div>

最简单的方法是简单地使用CSS多列布局。以下演示使用JavaScript允许用户调整内容的列数,并向其中添加更多元素,但除此之外,布局只是CSS,依赖于行:

column-count: var(--columns, 1);

其中,我们指定列数必须等于--columns的CSS自定义属性(JavaScript允许您调整),或者——如果该属性不存在或无效——或者1的默认值。

多列布局还将尝试均匀地平衡列的高度。

下面的代码具有解释性的代码注释,以深入了解其工作原理:

// retrieves the first/only <input> element in the document of "type=number":
const input = document.querySelector('input[type=number]'),
// retrieves the first/only element in the document with the class of "multicol":
multicol = document.querySelector('.multicol');
// we set the value of the <input> to the value held in the current `--columns`
// custom property:
input.value = multicol.style.getPropertyValue('--columns');
// we select all <button> elements in the document, and iterate over that
// NodeList using NodeList.prototype.forEach():
document.querySelectorAll('button').forEach(
// we use EventTarget.addEventListener() to bind an anonymous Arrow
// function as the event-handler for the 'click' event on the <button>
// element(s):
(btn) => btn.addEventListener('click', () => {
// creating a <span> element:
let span = document.createElement('span'),
// from the btn (<button>) element passed into the function-body
// of the Arrow function we navigate to the parent-node of that
// <button> element, and from there we find the '.multicol'
// element:
spanParent = btn.parentNode.querySelector('.multicol');
// we then append the new <span> to that element:
spanParent.append(span);
})
);
// here we bind an anoymous Arrow function as the event-handler for a
// 'change' event on the <input>:
input.addEventListener('change', (e) => {
// we get a reference to that <input>, using the Event.currentTarget()
// property:
let changed = e.currentTarget,
// from there we navigate from the <input> to the closest <main>
// element, and retrieve the first/only element with a class of
// "multicol":
columnElement = changed.closest('main').querySelector('.multicol');
// we then use the CSSStyleDeclaration.setProperty() method, to update
// the value of '--columns' custom CSS property to the current value
// of the <input>:
columnElement.style.setProperty('--columns', changed.value);
});
/* custom properties used through the stylesheet: */
:root {
--columns: 1;
--colGap: 0.5em;
--rowGap: 0.25em;
}

/* a hugely naive, simple CSS reset/normalisation to
ensure consistent base-styles for cross-browser
normalisation: */
*,
::before,
::after {
box-sizing: border-box;
font-family: Roboto, Montserrat, system-ui;
font-size: 16px;
font-weight: 400;
margin: 0;
padding: 0;
}
main {
display: grid;
gap: 1em;
margin-block: 1em;
margin-inline: auto;
/* setting an ideal width of 60vw (60 percent of the viewport-width,
with a minimum size of 20em and a maximum size of 800px: */
width: clamp(20em, 60vw, 800px);
}
h2 {
font-size: 1.2em;
font-weight: 600;
text-align: start;
}
label,
div {
border: 1px solid #000;
padding: 0.5em;
}
label {
/* a habit from positioning the label-text after the associated <input>
in order to style that text based on status of the <input>, but not
needed in this instance: */
display: flex;
flex-direction: row-reverse;
gap: var(--colGap);
align-items: center;
justify-content: center;
}

/* garish, but it does ensure that people can see when the <input> is focused: */
label:focus-within {
background-image: linear-gradient(45deg, hsl(0 100% 50% / 0.4), hsl(60 100% 50% / 0.6));
}
label input {
padding-block: var(--rowGap);
padding-inline-start: var(--colGap);
}
label span::after {
content: ':';
}
main>div {
margin: auto;
}
.multicol {
counter-reset: spanCount;
/* setting the number of columns in the element to be equal
to the --columns custom-property, or a default-value of 1: */
column-count: var(--columns, 1);
column-gap: var(--colGap);
max-width: 100%;
width: 100%;
}
.multicol span {
display: block;
padding-block: var(--rowGap);
}
.multicol span:nth-child(odd) {
background-color: palegreen;
}
.multicol span::before {
counter-increment: spanCount;
content: counter(spanCount);
}
<main>
<h2>Custom columns:</h2>
<label>
<input type="number" min="1" step="1" value="1">
<span>Set number of columns</span>
</label>
<button>Add new element</button>
<div class="multicol" style="--columns: 3">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</main>

JS Fiddle演示。

参考文献:

  • column-count
  • 自定义CSS属性--*
  • CCD_ 8函数

参考书目:

  • "CSS Multicol布局">
  • "何时以及如何使用CSS多列布局;Rachel Andrew,粉碎杂志,2019-01-11

这可能很麻烦,但您可以通过ordercss属性更改视觉顺序。(我希望有人能找到用JS实现同样方法的自动化)。

.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr); }
.grid-container span:nth-of-type(1) { order: 1; }
.grid-container span:nth-of-type(2) { order: 4; }
.grid-container span:nth-of-type(3) { order: 7; }
.grid-container span:nth-of-type(4) { order: 10; }
.grid-container span:nth-of-type(5) { order: 13; }
.grid-container span:nth-of-type(6) { order: 2; }
.grid-container span:nth-of-type(7) { order: 5; }
.grid-container span:nth-of-type(8) { order: 8; }
.grid-container span:nth-of-type(9) { order: 11; }
.grid-container span:nth-of-type(10) { order: 3; }
.grid-container span:nth-of-type(11) { order: 6; }
.grid-container span:nth-of-type(12) { order: 9; }
.grid-container span:nth-of-type(13) { order: 12; }
<div class="grid-container">
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
<span>5</span>
<span>6</span>
<span>7</span>
<span>8</span>
<span>9</span>
<span>10</span>
<span>11</span>
<span>12</span>
<span>13</span>
</div>

最新更新