使用 CSS 网格折叠边框
Collapsing borders using CSS Grid
我很高兴了解新的 CSS 网格规范,但我 运行 遇到了边界问题。
是否可以折叠 CSS 网格中的边框,或者有什么方法可以设置装订线的样式吗?
正如您在下面的代码片段中看到的,块之间的 10px
边界堆栈(总共 20px
个)。
我知道这个问题不是 CSS 网格独有的,但我希望它能提供新的解决方案,在所有框之间和外边缘上创建统一的 10px 边框。
我的实际用例是我制作的日历,用于练习使用网格和 React 组件。您可以在此处查看我 运行 遇到的问题:
.
由于每个月都不一样,我会考虑很多不同的边缘情况。
.container {
display: grid;
grid-template-columns: 120px 120px;
box-sizing: border-box;
}
.block {
width: 100px;
height: 100px;
background-color: lightgrey;
border: 10px solid palegreen;
}
.first {
grid-column: 2 / span 1;
}
<div class='container'>
<div class='block first'>1</div>
<div class='block'>2</div>
<div class='block'>3</div>
</div>
您可以使用 grid-gap 和 box-shadow:
.container {
display: grid;
grid-template-columns: 100px 100px;
box-sizing: border-box;
grid-gap:10px;
}
.block {
width: 100px;
height: 100px;
background-color: lightgrey;
box-shadow:0 0 0 10px palegreen;
}
.first {
grid-column: 2 / span 1;
}
<div class='container'>
<div class='block first'>1</div>
<div class='block'>2</div>
<div class='block'>3</div>
</div>
或合并行列模板设置:
.container {
display: grid;
grid-template-columns: 110px 110px;
grid-template-rows:110px;
box-sizing: border-box;
}
.block {
width: 100px;
height: 100px;
background-color: lightgrey;
border:solid 10px palegreen;
}
.first {
grid-column: 2 / span 1;
}
<div class='container'>
<div class='block first'>1</div>
<div class='block'>2</div>
<div class='block'>3</div>
</div>
请注意,当框设置为 100px 时,120px 的列和行将显示两侧边框...
如果 fr
值用于列,则不要在框上设置宽度(行将遵循相同的限制)。
.container {
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-template-rows: 110px;
/*whatever else */
box-sizing: border-box;
}
.block {
margin: 0 -10px 0 0;/* fixed width value missing */
height: 100px;
background-color: lightgrey;
border: solid 10px palegreen;
}
.first {
grid-column: 2 / span 1;
}
<div class='container'>
<div class='block first'>1</div>
<div class='block'>2</div>
<div class='block'>3</div>
<div class='block'>4</div>
<div class='block'>5</div>
<div class='block'>6</div>
<div class='block'>7</div>
</div>
考虑在网格容器级别而不是在网格项目级别控制所有大小和间距。删除应用于项目的边框和尺寸。
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); /* 1 */ /* 2 */
grid-auto-rows: 100px; /* 3 */
grid-gap: 5px; /* 4 */
padding: 5px;
background-color: tomato;
}
.block {
background-color: lightgrey;
}
/* for demo only */
.block:nth-child(-n + 2) {
visibility: hidden;
}
<div class='container'>
<div class='block'>0</div>
<div class='block'>0</div>
<div class='block'>1</div>
<div class='block'>2</div>
<div class='block'>3</div>
<div class='block'>4</div>
<div class='block'>5</div>
<div class='block'>6</div>
<div class='block'>7</div>
<div class='block'>8</div>
<div class='block'>9</div>
<div class='block'>10</div>
<div class='block'>11</div>
<div class='block'>12</div>
<div class='block'>13</div>
<div class='block'>14</div>
<div class='block'>15</div>
<div class='block'>16</div>
<div class='block'>17</div>
<div class='block'>18</div>
<div class='block'>19</div>
<div class='block'>20</div>
<div class='block'>21</div>
<div class='block'>22</div>
<div class='block'>23</div>
<div class='block'>24</div>
<div class='block'>25</div>
<div class='block'>26</div>
<div class='block'>27</div>
<div class='block'>28</div>
<div class='block'>29</div>
<div class='block'>30</div>
<div class='block'>31</div>
</div>
jsFiddle demo
备注:
auto-fit
:在该行中填写尽可能多的列。溢出列将换行。
minmax()
:每列的最小宽度为 120px,最大宽度为可用的 space。 fr
单位相当于 flex 布局的 flex-grow
属性.
grid-auto-rows
:自动创建的行(隐式 行)的高度为 100 像素。
grid-gap
: 周围有 5px 的排水沟。 Shorthand grid-column-gap
和 grid-row-gap
.
如果您认为间隙边框颜色与不属于当月的日期单元格相同,您可以采取的另一种方法是将 div
包裹在整个网格容器周围,然后将其 background-color
设置为您希望边框的颜色,并给它 1px 的 padding
和 grid-gap
的 1px。通过这种方法,您可以实现统一边框的网格,而无需使用框阴影的复杂性,这对我来说就像是一种 hack。
我刚刚找到了一个简单的方法来实现这一点,使用 css outline
而不是 border
。
outline
属性 在元素外部画了一条线,因此,1px 的间隙会折叠两条线。
.container {
display: grid;
grid-template-columns: 100px 100px 100px;
gap: 1px; /* you can use gap instead of grid-gap */
}
.block {
width: 100px;
height: 100px;
background-color: lightgrey;
outline: 1px solid darkgreen; /* Use outline instead of border */
}
.first {
grid-column: 2 / span 1;
}
<div class='container'>
<div class='block first'>1</div>
<div class='block'>2</div>
<div class='block'>3</div>
<div class='block'>4</div>
<div class='block'>5</div>
<div class='block'>6</div>
</div>
正如 TylerH 评论的那样,轮廓不占用 space 并且可以重叠,这就是为什么你需要为它使用间隙,如果你想要一条 5px 的线,你应该为两个属性都写 5px,轮廓和间隙。
.container {
display: grid;
grid-template-columns: 100px 100px 100px;
gap: 5px;
}
.block {
width: 100px;
height: 100px;
background-color: lightgrey;
outline: 5px solid darkgreen; /* The same width as the gap */
}
我一直在寻找一种纯粹的 CSS 折叠网格边界的方法,但由于我能找到 none,所以我制作了一个小原型。
HTML
<div class="container">
<div id="grid" class="grid">
<div class="element">1</div>
<div class="element">2</div>
<div class="element">3</div>
<div class="element">4</div>
<div class="element">5</div>
<div class="element">6</div>
<div class="element">7</div>
<div class="element">8</div>
<div class="element">9</div>
<div class="element">10</div>
<div class="element">11</div>
</div>
</div>
CSS
.container {
max-width: 720px;
margin: 0 auto;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}
.element {
text-align: center;
padding: 20px;
background: #f4f4f4;
border-bottom: 1px solid black;
border-right: 1px solid black;
}
.border-top {
border-top: 1px solid black;
}
.border-left {
border-left: 1px solid black;
}
.border-top-left-rounded {
border-top-left-radius: 8px;
}
.border-top-right-rounded {
border-top-right-radius: 8px;
}
.border-bottom-left-rounded {
border-bottom-left-radius: 8px;
}
.border-bottom-right-rounded {
border-bottom-right-radius: 8px;
}
JS
function dynamicRoundedCorners() {
// get
const grid = document.getElementById("grid");
const elements = grid.children;
const gridStyle = getComputedStyle(grid);
// reset
for (element of elements) {
element.classList = "";
element.classList.add("element");
}
// analyze
const elementsPerRowCount = gridStyle.gridTemplateColumns
.split(" ")
.filter((element) => Number(element.replace("px", ""))).length;
const rowCount = Math.ceil(elements.length / elementsPerRowCount);
const rowsFirstAndLastElements = [];
let firstAndLastElementIndex = 0;
for (let i = 1; i <= rowCount; i++) {
const rowFirstAndLastElements = [firstAndLastElementIndex];
if (i === rowCount && rowCount > 1) {
rowFirstAndLastElements.push(
firstAndLastElementIndex + (elements.length % elementsPerRowCount) - 1
);
} else {
rowFirstAndLastElements.push(
firstAndLastElementIndex + elementsPerRowCount - 1
);
}
rowsFirstAndLastElements.push(rowFirstAndLastElements);
firstAndLastElementIndex += elementsPerRowCount;
}
// apply
// -> add border-top on the first row
for (let i = 0; i <= rowsFirstAndLastElements[0][1]; i++) {
elements[i].classList.add("border-top");
}
// -> add border-left on every first element of a row
for (let i = 0; i < rowCount; i++) {
elements[rowsFirstAndLastElements[i][0]].classList.add("border-left");
}
// -> add top-left rounded corner on first element of first row
elements[0].classList.add("border-top-left-rounded");
// -> add top-right rounder corner on last element of first row
elements[rowsFirstAndLastElements[0][1]].classList.add(
"border-top-right-rounded"
);
// -> add bottom-left rounded corner on first element of last row
elements[rowsFirstAndLastElements[rowCount - 1][0]].classList.add(
"border-bottom-left-rounded"
);
// -> add bottom-right rounder corner on last element of last row
elements[elements.length - 1].classList.add("border-bottom-right-rounded");
// -> if elements.length % elementsPerRowCount != 0, add bottom-right rounder corner on last element of second to last row
if (elements.length % elementsPerRowCount !== 0) {
elements[
rowsFirstAndLastElements[rowsFirstAndLastElements.length - 2][1]
].classList.add("border-bottom-right-rounded");
}
}
// call
dynamicRoundedCorners();
window.addEventListener("resize", dynamicRoundedCorners);
我很高兴了解新的 CSS 网格规范,但我 运行 遇到了边界问题。
是否可以折叠 CSS 网格中的边框,或者有什么方法可以设置装订线的样式吗?
正如您在下面的代码片段中看到的,块之间的 10px
边界堆栈(总共 20px
个)。
我知道这个问题不是 CSS 网格独有的,但我希望它能提供新的解决方案,在所有框之间和外边缘上创建统一的 10px 边框。
我的实际用例是我制作的日历,用于练习使用网格和 React 组件。您可以在此处查看我 运行 遇到的问题:
由于每个月都不一样,我会考虑很多不同的边缘情况。
.container {
display: grid;
grid-template-columns: 120px 120px;
box-sizing: border-box;
}
.block {
width: 100px;
height: 100px;
background-color: lightgrey;
border: 10px solid palegreen;
}
.first {
grid-column: 2 / span 1;
}
<div class='container'>
<div class='block first'>1</div>
<div class='block'>2</div>
<div class='block'>3</div>
</div>
您可以使用 grid-gap 和 box-shadow:
.container {
display: grid;
grid-template-columns: 100px 100px;
box-sizing: border-box;
grid-gap:10px;
}
.block {
width: 100px;
height: 100px;
background-color: lightgrey;
box-shadow:0 0 0 10px palegreen;
}
.first {
grid-column: 2 / span 1;
}
<div class='container'>
<div class='block first'>1</div>
<div class='block'>2</div>
<div class='block'>3</div>
</div>
或合并行列模板设置:
.container {
display: grid;
grid-template-columns: 110px 110px;
grid-template-rows:110px;
box-sizing: border-box;
}
.block {
width: 100px;
height: 100px;
background-color: lightgrey;
border:solid 10px palegreen;
}
.first {
grid-column: 2 / span 1;
}
<div class='container'>
<div class='block first'>1</div>
<div class='block'>2</div>
<div class='block'>3</div>
</div>
请注意,当框设置为 100px 时,120px 的列和行将显示两侧边框...
如果 fr
值用于列,则不要在框上设置宽度(行将遵循相同的限制)。
.container {
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-template-rows: 110px;
/*whatever else */
box-sizing: border-box;
}
.block {
margin: 0 -10px 0 0;/* fixed width value missing */
height: 100px;
background-color: lightgrey;
border: solid 10px palegreen;
}
.first {
grid-column: 2 / span 1;
}
<div class='container'>
<div class='block first'>1</div>
<div class='block'>2</div>
<div class='block'>3</div>
<div class='block'>4</div>
<div class='block'>5</div>
<div class='block'>6</div>
<div class='block'>7</div>
</div>
考虑在网格容器级别而不是在网格项目级别控制所有大小和间距。删除应用于项目的边框和尺寸。
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); /* 1 */ /* 2 */
grid-auto-rows: 100px; /* 3 */
grid-gap: 5px; /* 4 */
padding: 5px;
background-color: tomato;
}
.block {
background-color: lightgrey;
}
/* for demo only */
.block:nth-child(-n + 2) {
visibility: hidden;
}
<div class='container'>
<div class='block'>0</div>
<div class='block'>0</div>
<div class='block'>1</div>
<div class='block'>2</div>
<div class='block'>3</div>
<div class='block'>4</div>
<div class='block'>5</div>
<div class='block'>6</div>
<div class='block'>7</div>
<div class='block'>8</div>
<div class='block'>9</div>
<div class='block'>10</div>
<div class='block'>11</div>
<div class='block'>12</div>
<div class='block'>13</div>
<div class='block'>14</div>
<div class='block'>15</div>
<div class='block'>16</div>
<div class='block'>17</div>
<div class='block'>18</div>
<div class='block'>19</div>
<div class='block'>20</div>
<div class='block'>21</div>
<div class='block'>22</div>
<div class='block'>23</div>
<div class='block'>24</div>
<div class='block'>25</div>
<div class='block'>26</div>
<div class='block'>27</div>
<div class='block'>28</div>
<div class='block'>29</div>
<div class='block'>30</div>
<div class='block'>31</div>
</div>
jsFiddle demo
备注:
auto-fit
:在该行中填写尽可能多的列。溢出列将换行。minmax()
:每列的最小宽度为 120px,最大宽度为可用的 space。fr
单位相当于 flex 布局的flex-grow
属性.grid-auto-rows
:自动创建的行(隐式 行)的高度为 100 像素。grid-gap
: 周围有 5px 的排水沟。 Shorthandgrid-column-gap
和grid-row-gap
.
如果您认为间隙边框颜色与不属于当月的日期单元格相同,您可以采取的另一种方法是将 div
包裹在整个网格容器周围,然后将其 background-color
设置为您希望边框的颜色,并给它 1px 的 padding
和 grid-gap
的 1px。通过这种方法,您可以实现统一边框的网格,而无需使用框阴影的复杂性,这对我来说就像是一种 hack。
我刚刚找到了一个简单的方法来实现这一点,使用 css outline
而不是 border
。
outline
属性 在元素外部画了一条线,因此,1px 的间隙会折叠两条线。
.container {
display: grid;
grid-template-columns: 100px 100px 100px;
gap: 1px; /* you can use gap instead of grid-gap */
}
.block {
width: 100px;
height: 100px;
background-color: lightgrey;
outline: 1px solid darkgreen; /* Use outline instead of border */
}
.first {
grid-column: 2 / span 1;
}
<div class='container'>
<div class='block first'>1</div>
<div class='block'>2</div>
<div class='block'>3</div>
<div class='block'>4</div>
<div class='block'>5</div>
<div class='block'>6</div>
</div>
正如 TylerH 评论的那样,轮廓不占用 space 并且可以重叠,这就是为什么你需要为它使用间隙,如果你想要一条 5px 的线,你应该为两个属性都写 5px,轮廓和间隙。
.container {
display: grid;
grid-template-columns: 100px 100px 100px;
gap: 5px;
}
.block {
width: 100px;
height: 100px;
background-color: lightgrey;
outline: 5px solid darkgreen; /* The same width as the gap */
}
我一直在寻找一种纯粹的 CSS 折叠网格边界的方法,但由于我能找到 none,所以我制作了一个小原型。
HTML
<div class="container">
<div id="grid" class="grid">
<div class="element">1</div>
<div class="element">2</div>
<div class="element">3</div>
<div class="element">4</div>
<div class="element">5</div>
<div class="element">6</div>
<div class="element">7</div>
<div class="element">8</div>
<div class="element">9</div>
<div class="element">10</div>
<div class="element">11</div>
</div>
</div>
CSS
.container {
max-width: 720px;
margin: 0 auto;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}
.element {
text-align: center;
padding: 20px;
background: #f4f4f4;
border-bottom: 1px solid black;
border-right: 1px solid black;
}
.border-top {
border-top: 1px solid black;
}
.border-left {
border-left: 1px solid black;
}
.border-top-left-rounded {
border-top-left-radius: 8px;
}
.border-top-right-rounded {
border-top-right-radius: 8px;
}
.border-bottom-left-rounded {
border-bottom-left-radius: 8px;
}
.border-bottom-right-rounded {
border-bottom-right-radius: 8px;
}
JS
function dynamicRoundedCorners() {
// get
const grid = document.getElementById("grid");
const elements = grid.children;
const gridStyle = getComputedStyle(grid);
// reset
for (element of elements) {
element.classList = "";
element.classList.add("element");
}
// analyze
const elementsPerRowCount = gridStyle.gridTemplateColumns
.split(" ")
.filter((element) => Number(element.replace("px", ""))).length;
const rowCount = Math.ceil(elements.length / elementsPerRowCount);
const rowsFirstAndLastElements = [];
let firstAndLastElementIndex = 0;
for (let i = 1; i <= rowCount; i++) {
const rowFirstAndLastElements = [firstAndLastElementIndex];
if (i === rowCount && rowCount > 1) {
rowFirstAndLastElements.push(
firstAndLastElementIndex + (elements.length % elementsPerRowCount) - 1
);
} else {
rowFirstAndLastElements.push(
firstAndLastElementIndex + elementsPerRowCount - 1
);
}
rowsFirstAndLastElements.push(rowFirstAndLastElements);
firstAndLastElementIndex += elementsPerRowCount;
}
// apply
// -> add border-top on the first row
for (let i = 0; i <= rowsFirstAndLastElements[0][1]; i++) {
elements[i].classList.add("border-top");
}
// -> add border-left on every first element of a row
for (let i = 0; i < rowCount; i++) {
elements[rowsFirstAndLastElements[i][0]].classList.add("border-left");
}
// -> add top-left rounded corner on first element of first row
elements[0].classList.add("border-top-left-rounded");
// -> add top-right rounder corner on last element of first row
elements[rowsFirstAndLastElements[0][1]].classList.add(
"border-top-right-rounded"
);
// -> add bottom-left rounded corner on first element of last row
elements[rowsFirstAndLastElements[rowCount - 1][0]].classList.add(
"border-bottom-left-rounded"
);
// -> add bottom-right rounder corner on last element of last row
elements[elements.length - 1].classList.add("border-bottom-right-rounded");
// -> if elements.length % elementsPerRowCount != 0, add bottom-right rounder corner on last element of second to last row
if (elements.length % elementsPerRowCount !== 0) {
elements[
rowsFirstAndLastElements[rowsFirstAndLastElements.length - 2][1]
].classList.add("border-bottom-right-rounded");
}
}
// call
dynamicRoundedCorners();
window.addEventListener("resize", dynamicRoundedCorners);