CSS gap属性介绍及在布局中的使用
CSS 中的 gap 属性是 row-gap 和 column-gap 的简写,它指定间距的大小,即 grid、flex 和 multi-column 布局中行和列之间的空间。
/* Grid layout */ .container { display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: 1fr 2fr 1fr; gap: 30px 20px; } /* Flex layout */ .container { display: flex; gap: 10%; } /* Multi-column layout */ .container { column-count: 5; gap: 20px; }
下面通过实例查看实际的 gap 属性(感兴趣的小伙伴可以拿到本地看看,代码我已贴出):
HTML 结构
<input type="range" min="0" max="10" step="0.1" value="1"> <div class="container"> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> </div>
CSS 结构
.container { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 12.5rem; gap: 1rem; width: 100%; max-width: 37.5rem; padding: 0.5rem; margin: 0 auto; box-sizing: border-box; } @media (max-width: 27em) { .container { grid-template-columns: repeat(2, 1fr); } } body { display: flex; flex-direction: column; gap: 1rem; margin: 0; min-height: 100vh; background: linear-gradient(-45deg, #ff9f4d 10%, #ffc857 0, #ffc857 90%, #ff9f4d 0, #ff9f4d 100%); } input[type="range"] { display: block; margin: 2rem auto; } .item { border-radius: 15px; background-color: #faf7fa; background-image: linear-gradient(#fdeae3, #fdeae3), linear-gradient(#f8c966,#f8c966), linear-gradient(#f1d6c3,#f1d6c3), linear-gradient(90deg, transparent 20px, #f9e5c7 0, #f9e5c7 calc(100% - 20px), transparent 0); background-size: 100% 50px, 50px 10px, 60px 10px, auto 50px; background-position: 0 0, 20px 80px, 20px 100px, left 0 bottom 20px; background-repeat: no-repeat; } @supports not (gap: 1px) { body { padding-top: 2em; } body::before { content: "Your browser doesn't support gap property"; display: block; color: #e43; font-weight: bold; position: fixed; top: 1.5em; left: 0; right: 0; z-index: 1; text-align: center; } }
JS 结构
var container = document.querySelector('.container'), slider = document.querySelector('input'); slider.addEventListener('input', function () { container.style.gap = this.value + 'rem'; }, false);
GIF 效果展示:
语法
gap 接受一个或两个值:
- 单个值可同时设置 row-gap 和设置 column-gap 相同的值。
- 当使用两个值时,第一个设置 row-gap,第二个设置 column-gap。
.container { gap: 1rem; /* 相当于: * row-gap: 1rem; * column-gap: 1rem */ gap: 10px 15%; /* 相当于: * row-gap: 10px; * column-gap: 15%; */ }
CSS 网格布局模块的规范使用 grid-gap 属性定义了网格轨道之间的空间。gap 是旨在取代它,这样的间距可以在多个 CSS 布局的方法来定义,像 Flexbox 的,但 grid-gap 仍需要在实例被用在浏览器可能已经实现了 grid-gap,但还没有开始支持新 gap 特性。
取值
gap 接受以下值:
normal
:(默认)浏览器将为多列布局指定一个使用的值为1em
,为所有其他布局上下文(即网格和弹性)指定一个0px
的使用值。<length>
:任何有效的和非负CSS
的长度,如px
,em
,rem
和%
,等等。<percentage>
:间隙的大小,以相对于元素尺寸的非负百分比值表示。initial
:应用属性的默认设置,即normal
。inherit
:采用父级的间隙值。unset
:从元素中删除当前间隙。
gap 特性百分比
当gap
维度中容器的大小是确定的时,gap
会根据任何布局类型中容器内容框的大小来解析百分比。
换句话说,当浏览器知道容器的大小时,它可以计算的百分比值gap
。例如,当容器的高度为 100px 并将其gap
设置为 10%时,浏览器就会知道 100px 中的 10%为 10px。
但是当浏览器不知道大小时,会想知道“10%是什么?”在这些情况下,gap 行为会因布局类型而异。
在网格布局中,百分比解析为零以确定内部大小贡献,但是在布置框的内容时相对于元素的内容框,这意味着它将在项目之间放置空间,但该空间不会影响容器的尺寸。
在接下来的实例中,容器的高度不确定。查看增加 gap 大小时会发生什么。然后设置 gap 像素单位,然后重试:
Html 结构
<div class="control"> <input type="checkbox" id="switch" checked/> <label for="switch" class="switch"> <span class="eye"></span> </label> <input type="range" min="0" max="100" step="1" value="0"> </div> <div class="container"> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> </div>
CSS 结构
.control { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; width: 100%; max-width: 37.5rem; margin: 2rem auto 0; } .container { display: grid; grid-template-columns: repeat(3, 100px); grid-auto-rows: 100px; justify-content: space-between; row-gap: 0%; width: 100%; max-width: 37.5rem; padding: 0.5rem; margin: 0 auto; box-sizing: border-box; border: 2px dashed #fdeae3; border-radius: 15px; } body { display: flex; flex-direction: column; gap: 1rem; margin: 0; min-height: 100vh; background: linear-gradient(-45deg, #ff9f4d 10%, #ffc857 0, #ffc857 90%, #ff9f4d 0, #ff9f4d 100%); } input[type="range"] { display: block; margin-right: 2em; } .item { border-radius: 15px; background-color: #faf7fa; background-image: linear-gradient(#ff5e49,#ff5e49), linear-gradient(#4d004c,#4d004c); background-size: 50px 10px, 60px 10px; background-position: 20px 40px, 20px 60px; background-repeat: no-repeat; } #switch { position: absolute; left: -9999px; } .switch { display : block; position: relative; width : 7.5em; flex-shrink: 0; padding : 3px; cursor : pointer; border-radius : 33px; background : #ff5d47; box-shadow : 0 1px 1px 0 rgba(0,0,0,.3); transform: scale(0.7); } .switch:before , .switch:after { display : block; color : #fff; position : absolute; font-size : 30px; top : 15px; z-index : 0; font-family: monospace; } .switch:before { left : 15px; content : '%'; } .switch:after { right : 15px; content : 'PX'; } .eye { display : block; width : 39px; height : 41px; border : 7px solid #4d004b; border-radius : 50%; position : relative; left : 0; z-index: 1; transition : 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) transform; transform: translateX(1px); } .eye:after , .eye:before { display : block; content : ''; position: absolute; z-index : 999; transition : 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all; } .eye:before { width : 100%; height : 34px; top : 0; left : 0; background-color: #fff; border-radius : inherit; border-top : 4px solid #ff5d47; border-bottom : 3px solid #ff5d47; } .eye:after { width : 3px; height : 3px; top : 0; left : 0; bottom : 0; right : 0; margin : auto; background-color: #000; box-shadow : -2px -2px 0 0px #fff , 0 0 1px 3px #4e341c ; border-radius : 50%; } #switch:checked + .switch .eye { transform: translateX(67px); } #switch:checked + .switch .eye:before { transition : 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all; border-top-width : 20px; height : 19px; } #switch:checked + .switch .eye:after{ transition : 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all; top : 10px; left : -20px; } @supports not (gap: 1px) { body { padding-top: 2em; } body::before { content: "Your browser doesn't support gap property"; display: block; color: #e43; font-weight: bold; position: fixed; top: 1.5em; left: 0; right: 0; z-index: 1; text-align: center; } }
JS 结构
var container = document.querySelector('.container'), slider = document.querySelector('input[type="range"]'); checkbox = document.querySelector('input[type="checkbox"]'); slider.addEventListener('input', function () { if(checkbox.checked) { container.style.rowGap = this.value + '%'; }else { container.style.rowGap = this.value + 'px'; } }, false);
GIF 效果展示
在弹性版式中,百分比在所有情况下均会归零,这意味着当浏览器不知道容器的大小时,gap 将不适用:
CSS 结构
.control { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; width: 100%; max-width: 37.5rem; margin: 2rem auto 0; } .container { display: flex; flex-wrap: wrap; column-gap: 2rem; row-gap: 0%; width: 100%; max-width: 37.5rem; padding: 0.5rem; margin: 0 auto; box-sizing: border-box; border: 2px dashed #fdeae3; border-radius: 15px; } body { display: flex; flex-direction: column; gap: 1rem; margin: 0; min-height: 100vh; background: linear-gradient(-45deg, #ff9f4d 10%, #ffc857 0, #ffc857 90%, #ff9f4d 0, #ff9f4d 100%); } input[type="range"] { display: block; margin-right: 2em; } .item { width: 100px; height: 100px; border-radius: 15px; background-color: #faf7fa; background-image: linear-gradient(#ff5e49,#ff5e49), linear-gradient(#4d004c,#4d004c); background-size: 50px 10px, 60px 10px; background-position: 20px 40px, 20px 60px; background-repeat: no-repeat; } #switch { position: absolute; left: -9999px; } .switch { display : block; position: relative; width : 7.5em; flex-shrink: 0; padding : 3px; cursor : pointer; border-radius : 33px; background : #ff5d47; box-shadow : 0 1px 1px 0 rgba(0,0,0,.3); transform: scale(0.7); } .switch:before , .switch:after { display : block; color : #fff; position : absolute; font-size : 30px; top : 15px; z-index : 0; font-family: monospace; } .switch:before { left : 15px; content : '%'; } .switch:after { right : 15px; content : 'PX'; } .eye { display : block; width : 39px; height : 41px; border : 7px solid #4d004b; border-radius : 50%; position : relative; left : 0; z-index: 1; transition : 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) transform; transform: translateX(1px); } .eye:after , .eye:before { display : block; content : ''; position: absolute; z-index : 999; transition : 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all; } .eye:before { width : 100%; height : 34px; top : 0; left : 0; background-color: #fff; border-radius : inherit; border-top : 4px solid #ff5d47; border-bottom : 3px solid #ff5d47; } .eye:after { width : 3px; height : 3px; top : 0; left : 0; bottom : 0; right : 0; margin : auto; background-color: #000; box-shadow : -2px -2px 0 0px #fff , 0 0 1px 3px #4e341c ; border-radius : 50%; } #switch:checked + .switch .eye { transform: translateX(67px); } #switch:checked + .switch .eye:before { transition : 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all; border-top-width : 20px; height : 19px; } #switch:checked + .switch .eye:after{ transition : 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all; top : 10px; left : -20px; } @supports not (gap: 1px) { body { padding-top: 2em; } body::before { content: "Your browser doesn't support gap property"; display: block; color: #e43; font-weight: bold; position: fixed; top: 1.5em; left: 0; right: 0; z-index: 1; text-align: center; } }
GIF 效果如下:
结合使用 calc()函数和 gap
可以使用 calc()函数来指定的大小,但是,gap 在撰写本文时,Safari 和 iOS 尚不支持该功能。关于 calc()知识介绍大家可以看这篇文章《css3 calc()属性介绍以及自适应布局使用方法》
.flex-layout { display: flex; gap: calc(5vh + 5px) calc(5vw + 5px); } .grid-layout { display: grid; grid-template-columns: repeat(3, 1fr); gap: calc(5vmin + 5px); }
例子
该 gap 属性设计用于网格,伸缩和多列布局。让我们看看一些例子。
网格布局
在下面的演示中,您可以看到 gap 用于指定网格容器上的row-gap
和column-gap
属性,分别定义了网格行和网格列之间的装订线:
HTML 结构
<div class="container"> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> </div>
CSS 结构
.container { display: grid; grid-template-columns: repeat(auto-fit, 100px); grid-auto-rows: 100px; justify-content: center; gap: 2rem 1rem; } body { display: flex; align-items: center; margin: 0; min-height: 100vh; background: linear-gradient(-45deg, #ff9f4d 10%, #ffc857 0, #ffc857 90%, #ff9f4d 0, #ff9f4d 100%); } .container { width: 100%; max-width: 37.5rem; padding: 0.5rem; margin: 0 auto; box-sizing: border-box; } .item { width: 100px; height: 100px; border-radius: 15px; background-color: hsl(300deg 23% 97%); background-image: linear-gradient(hsl(7deg 100% 64%),hsl(7deg 100% 64%)), linear-gradient(hsl(301deg 100% 15%),hsl(301deg 100% 15%)); background-size: 50px 10px, 60px 10px; background-position: 20px 40px, 20px 60px; background-repeat: no-repeat; }
效果如下:
Flex 布局
在伸缩容器的主轴上施加间隙表示伸缩布局的单行中伸缩项目之间的间距。
这里在column-gap
行方向使用:
HTML 结构
<div class="container"> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> </div>
CSS 结构
.container { display: flex; flex-wrap: wrap; column-gap: 1rem; } body { padding: 1em; margin: 0; background-color: #ffc857; } .item { width: 100px; height: 100px; border-radius: 15px; background-color: #faf7fa; background-image: linear-gradient(#ff5e49,#ff5e49), linear-gradient(#4d004c,#4d004c); background-size: 50px 10px, 60px 10px; background-position: 20px 40px, 20px 60px; background-repeat: no-repeat; }
效果如下:
在 row-gap 列方向上使用
HTML 结构同上
CSS 结构如下
.container { display: flex; flex-wrap: wrap; flex-direction: column; align-content: flex-start; height: 350px; row-gap: 1rem; } body { padding: 1em; margin: 0; background-color: #ffc857; } .item { width: 100px; height: 100px; border-radius: 15px; background-color: #faf7fa; background-image: linear-gradient(#ff5e49,#ff5e49), linear-gradient(#4d004c,#4d004c); background-size: 50px 10px, 60px 10px; background-position: 20px 40px, 20px 60px; background-repeat: no-repeat; }
效果如下:
将gap
应用于flex
容器的横轴表示flex
布局的flex
线之间的间距。
这是row-gap
行方向
CSS 结构
.container { display: flex; flex-wrap: wrap; row-gap: 1rem; } body { padding: 1em; margin: 0; background-color: #ffc857; } .item { width: 100px; height: 100px; border-radius: 15px; background-color: #faf7fa; background-image: linear-gradient(#ff5e49,#ff5e49), linear-gradient(#4d004c,#4d004c); background-size: 50px 10px, 60px 10px; background-position: 20px 40px, 20px 60px; background-repeat: no-repeat; }
效果如下:
在 column-gap 列方向
CSS 结构
.container { display: flex; flex-direction: column; flex-wrap: wrap; align-content: flex-start; height: 350px; column-gap: 1rem; } body { padding: 1em; margin: 0; background-color: #ffc857; } .item { width: 100px; height: 100px; border-radius: 15px; background-color: #faf7fa; background-image: linear-gradient(#ff5e49,#ff5e49), linear-gradient(#4d004c,#4d004c); background-size: 50px 10px, 60px 10px; background-position: 20px 40px, 20px 60px; background-repeat: no-repeat; }
效果如下:
column-gap
会出现在多列布局中以在列框之间创建间隙,但是请注意,row-gap
由于仅在列中工作,因此没有任何效果。gap
仍然可以在这种情况下使用,但是只应用列gap
。
在下一个例子中可以看到,尽管该gap
属性的值为2rem
,但是由于我们在列中进行工作,因此它仅水平分隔项目,而不是双向分隔项目:
延伸
使用 gap 属性有几点值得注意。
这是防止不必要间距的好方法
不知道你有没有用边距来创造元素之间的间距?如果我们不小心,我们可能会在一组项目前后留出额外的间距。
HTML 结构
<section> <div class="container margin"> <div class="item"></div> <div class="item"></div> <div class="item"></div> </div> </section>
CSS 结构
.margin .item, .negative-margin .item { margin: 0 1rem; } .negative-margin { margin: 0 -1rem; } .gap { gap: 1rem; } section { max-width: 100%; margin: 0 auto; border: 2px dashed #4c004c; } .container { display: flex; margin-top: 1rem; margin-bottom: 1rem; box-sizing: border-box; } body { display: flex; align-items: center; justify-content: center; margin: 0; min-height: 100vh; background: linear-gradient(-45deg, #ff9f4d 10%, #ffc857 0, #ffc857 90%, #ff9f4d 0, #ff9f4d 100%); } .item { flex: auto 1 1; padding: 50px; border-radius: 15px; background-color: hsl(300deg 23% 97%); background-image: linear-gradient(hsl(7deg 100% 64%),hsl(7deg 100% 64%)), linear-gradient(hsl(301deg 100% 15%),hsl(301deg 100% 15%)); background-size: 50px 10px, 60px 10px; background-position: 20px 40px, 20px 60px; background-repeat: no-repeat; } * { box-sizing: border-box; }
效果如下:
解决这一问题通常需要添加负的页边距或求助于伪选择器来删除特定项的边距。但是在更现代的布局方法中使用 gap 的好处是,项目之间只有空格。在开始和结束时多余的东西永远不会成为问题!
HTML 结构
<section> <div class="container margin"> <div class="item"></div> <div class="item"></div> <div class="item"></div> </div> <div class="container negative-margin"> <div class="item"></div> <div class="item"></div> <div class="item"></div> </div> <div class="container gap"> <div class="item"></div> <div class="item"></div> <div class="item"></div> </div> </section>
CSS 结构
.margin .item, .negative-margin .item { margin: 0 1rem; } .negative-margin { margin: 0 -1rem; } .gap { gap: 1rem; } section { max-width: 100%; margin: 0 auto; border: 2px dashed #4c004c; } .container { display: flex; margin-top: 1rem; margin-bottom: 1rem; box-sizing: border-box; } body { display: flex; align-items: center; justify-content: center; margin: 0; min-height: 100vh; background: linear-gradient(-45deg, #ff9f4d 10%, #ffc857 0, #ffc857 90%, #ff9f4d 0, #ff9f4d 100%); } .item { flex: auto 1 1; padding: 50px; border-radius: 15px; background-color: hsl(300deg 23% 97%); background-image: linear-gradient(hsl(7deg 100% 64%),hsl(7deg 100% 64%)), linear-gradient(hsl(301deg 100% 15%),hsl(301deg 100% 15%)); background-size: 50px 10px, 60px 10px; background-position: 20px 40px, 20px 60px; background-repeat: no-repeat; } * { box-sizing: border-box; }
效果如下:
但是,如果你想在使用时在项目周围留出空间 gap,请padding
像这样放置容器:
.container { display: flex; gap: 1rem; padding: 1rem; }
Gutter 大小并不总是等于间隙值
gap 属性并不是唯一可以在项目之间放置空间的东西。同时也会影响内容的实际边距和对齐大小。
在下面的示例中,我们设置了一个 1em 间距,但是正如您所看到的,由于使用了分布式对齐(如对齐内容和对齐内容),项目之间的空间要大得多:
HTML 结构
<input type="range" min="0" max="10" step="0.1" value="1"> <div class="container"> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> <div class="item"></div> </div>
CSS 结构
.container { display: grid; grid-template-columns: repeat(3, 100px); grid-auto-rows: 100px; justify-content: space-between; align-content: space-between; gap: 1rem; width: 100%; max-width: 37.5rem; min-height: 20rem; padding: 0.5rem; margin: 0 auto; box-sizing: border-box; border: 2px dashed #fdeae3; border-radius: 15px; } body { display: flex; flex-direction: column; gap: 1rem; margin: 0; min-height: 100vh; background: linear-gradient(-45deg, #ff9f4d 10%, #ffc857 0, #ffc857 90%, #ff9f4d 0, #ff9f4d 100%); } input[type="range"] { display: block; margin: 2rem auto; } .item { border-radius: 15px; background-color: #faf7fa; background-image: linear-gradient(#ff5e49,#ff5e49), linear-gradient(#4d004c,#4d004c); background-size: 50px 10px, 60px 10px; background-position: 20px 40px, 20px 60px; background-repeat: no-repeat; } @supports not (gap: 1px) { body { padding-top: 2em; } body::before { content: "Your browser doesn't support gap property"; display: block; color: #e43; font-weight: bold; position: fixed; top: 1.5em; left: 0; right: 0; z-index: 1; text-align: center; } }
JS 结构
var container = document.querySelector('.container'), slider = document.querySelector('input'); slider.addEventListener('input', function () { container.style.gap = this.value + 'rem'; }, false);
GIF 效果图如下:
浏览器支持
特征查询通常是检查浏览器是否支持特定特性的好方法,但在这种情况下,如果在 flexbox 中检查 gap 属性,则可能会得到误报,因为特征查询无法区分布局模式。换句话说,它可能在 flex 布局中得到支持,这会导致一个积极的结果,但是如果在网格布局中使用它,它实际上是不受支持的。
Grid 布局
具有 calc()值的 Grid 布局
具有百分比值的 grid 布局
Flex 布局
与 flexbox 一起使用 gap 的规范目前处于工作草案状态。
此浏览器支持数据来自 Caniuse,它有更详细的信息。数字表示浏览器支持该版本及更高版本的功能。
多列布局
码云笔记 » CSS gap属性介绍及在布局中的使用