CSS 是Web 开发中不可或缺的一部分,随着 Web 技术的不断革新,CSS 也变得更加强大。CSS 的众多属性你知道了多少?具体开发中该使用什么属性才最适合恰当?如今的一些 CSS 属性可以让我们节约更多的时间。比如在 Web 布局中,现代 CSS 特性就可以更好的帮助我们快速实现如等高布局,水平垂直居中,经典的圣杯布局、宽高比例、页脚保持在底部等效果。淘系前端技术专家大漠将详细介绍一些不同的 CSS 属性来实现这些效果,希望对同学们有所帮助。
来源公众号:阿里技术
<!-- HTML -->
<div class="flex__container">
<div class="flex__item"></div>
</div>
/* CSS */
.flex__container {
display: flex;
justify-content: center;
align-items: center;
}
效果如下:
<!-- HTML -->
<div class="flex__container">
<svg> </svg>
</div>
/* CSS */
.flex__container {
display: inline-flex;
align-items: center;
justify-content: center;
}
效果如下:
<!-- HTML -->
<div class="flex__container">
<div class="avatar">:)</div>
<div class="media__heading"></div>
<div class="media__content"></div>
<div class="action"></div>
</div>
/* CSS */
.flex__container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
效果如下:
<!-- HTML -->
<div class="flex__container">
<div class="flex__item"></div>
</div>
/* CSS */
.flex__container {
display: flex; // 或 inline-flex
justify-content: center;
}
.flex__item {
align-self: center;
}
效果如下:
.flex__container {
display: flex; // 或 inline-flex
justify-content: center;
}
.flex__container > * {
align-self: center;
}
比如下面这个效果:
.flex__container {
display: flex;
place-content: center;
}
.flex__item {
align-self: center;
}
效果如下:
.flex__container {
display: flex;
place-content: center;
place-items: center;
}
效果如下:
.flex__container {
display: flex;
flex-direction: column;
place-content: center;
}
.flex__container > * {
align-self: center;
}
// 或
.flex__container {
display: flex;
flex-direction: column;
place-content: center;
place-items: center;
}
效果如下:
.flex__container {
place-content: center;
place-items: center;
}
.flex__container {
align-content: center;
justify-content: center;
align-items: center;
justify-items: center;
}
虽然扩展出来有四个属性,但最终等效于:
.flex__container {
display: flex;
align-items: center;
justify-content: center;
}
// 多行
.flex__container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
在 Flex 项目上设置 margin: auto
.flex__container {
display: flex; // 或 inline-flex
}
.flex__item {
margin: auto;
}
效果如下:
<!-- HTML -->
<div class="grid__container">
<div class="grid__item"></div>
</div>
/* CSS */
.grid {
display: grid; // 或 inline-grid
place-items: center
}
效果如下:
<!-- HTML -->
<div class="grid__container">
<div class="avatar">:)</div>
<div class="media__heading"></div>
<div class="media__content"></div>
<div class="action"></div>
</div>
这个时候你看到的效果如下:
<!-- HTML -->
<div class="grid__container">
<div class="grid__item">
<h3>Special title treatment</h3>
<p>With supporting text below as a natural lead-in to additional content.</p>
<div class="action">Go somewhere</div>
</div>
</div>
/* CSS */
.grid__container {
display: grid;
place-items: center;
grid-template-columns: repeat(2, 1fr);
gap: 2vh;
}
.grid__item {
display: grid;
place-items: center;
}
效果如下:
<!-- Flexbox -->
<flex__container>
<flex__item></flex__item>
<flex__item></flex__item>
<flex__item></flex__item>
</flex__container>
/* CSS */
.flex__container {
display: flex; // 或 inline-flex
}
简单地说,在容器上显式设置了 display 的值为 flex 或 inline-flex,该容器的所有子元素的高度都相等,因为容器的 align-items 的默认值为 stretch。
<!-- HTML -->
<grid__container>
<grid__item></grid__item>
<grid__item></grid__item>
<grid__item></grid__item>
</grid__container>
/* CSS */
.grid__container {
display: grid;
grid-template-columns: 20vw 1fr 20vw; /* 根据需求调整值*/
}
效果如下:
<!-- HTML -->
<flex__container>
<flex__item>
<content></content>
</flex__item>
</flex__container>
/* CSS */
.flex__container {
display: flex;
}
.content {
height: 100%
}
// 或
.grid__container {
display: grid;
grid-auto-flow: column;
}
.content {
height: 100%;
}
效果如下:
<!-- HTML -->
<header></header>
<main></main>
<footer></footer>
先来看 Flexbox 布局模块中的实现方案:
body {
display: flex;
flex-direction: column;
}
footer {
margin-top: auto;
}
body {
display: flex;
flex-direction: column;
}
main {
flex: 1 0 auto;
}
效果如下:
main {
flex-grow: 1; /*容器有剩余空间时,main 区域会扩展*/
flex-shrink: 0; /*容器有不足空间时,main 区域不会收缩*/
flex-basis: auto; /*main 区域高度的基准值为 main 内容自动高度*/
}
如果你想省事的话,可以在 main 上显式设置 flex-grow:1,因为 flex-shrink 和 flex-basis 的默认值为 1 和 auto。
.grid__container {
display: grid;
grid-template-rows: auto 1fr auto;
}
效果如下:
<!-- HTML -->
<container>
<column></column>
<column></column>
<column></column>
</container>
/* CCSS */
.container {
inline-size: 50vw;
min-inline-size: 320px;
display: flex-row;
}
.column {
float: left;
width: calc(100% / 3);
}
效果如下:
<!-- HTML -->
<flex__container>
<flex__item></flex__item>
<flex__item></flex__item>
<flex__item></flex__item>
</flex__container>
/* CSS */
.flex__container {
inline-size: 50vw;
display: flex;
}
.flex__item {
flex: 1;
}
效果如下:
<!-- HTML -->
<grid__container>
<grid__item></grid__item>
<grid__item></grid__item>
<grid__item></grid__item>
</grid__container>
/* CSS */
.grid__container {
display: grid;
grid-template-columns: repeat(3, 1fr); /*这里的 3 表示具体的列数*/
}
最终的效果是相同的:
.flex__container {
min-inline-size: 300px;
}
不过话又说回来,比如我们的 Flex 项目(或 Grid 项目)是一个卡片,每张卡片宽度是相等之外,更希望容器没有足够空间时,Flex 项目(或 Grid 项目)会自动断行排列。
.flex__container {
display: flex;
flex-wrap: wrap;
}
.flex__item {
flex: 0 1 calc((100vw - 18vh) / 4); /* calc(100vw -18vh) / 4 是 flex-basis 的基准值 */
}
.flex__item {
flex: 0 0 400px;
}
.flex__item {
flex: 1 0 400px;
}
当 Flex 容器没有足够空间排列 Flex 项目时,Flex 项目会按 flex-basis: 400px 计算其宽度,Flex 会断行,并且同一行出现剩余空间时,Flex 项目会扩展,占满整个 Flex 容器:
.grid__container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2vh;
}
<!-- HTML -->
<header></header>
<main>
<article></article> <!-- 主内容 -->
<nav></nav>
<aside></aside>
</main>
<footer></footer>
body {
width: 100vw;
display: flex;
flex-direction: column;
}
main {
flex: 1;
min-height: 0;
display: flex;
align-items: stretch;
width: 100%;
}
footer {
margin-top: auto;
}
nav {
width: 220px;
order: -1;
}
article {
flex: 1;
}
aside {
width: 220px;
}
效果如下:
nav {
order: 0;
}
aside {
order: -1;
}
效果如下:
注意,order 的默认值为 0,值越大越排在后面!
@media screen and (max-width: 800px) {
main {
flex-direction: column;
}
nav, aside {
width: 100%;
}
}
<!-- HTML -->
<body>
<header></header>
<main></main>
<nav></nav>
<aside></aside>
<footer></footer>
</body>
在 CSS 方面有很多种方案可以实现圣杯布局效果。我们先来看第一种:
body {
display: grid;
grid-template: auto 1fr auto / 220px 1fr 220px;
}
header {
grid-column: 1 / 4;
}
main {
grid-column: 2 / 3;
grid-row: 2 / 3;
}
nav {
grid-column: 1 / 2;
grid-row: 2 / 3;
}
aside {
grid-column: 3 / 4;
grid-row: 2 / 3;
}
footer {
grid-column: 1 / 4;
}
@media screen and (max-width: 800px) {
body {
grid-template-rows: auto;
grid-template-columns: auto;
}
header,
main,
nav,
aside,
footer {
grid-column: 1 / 2;
min-height: auto;
}
main {
grid-row: 3 / 4;
margin: 0;
}
nav {
grid-row: 2 / 3;
}
aside {
grid-row: 4 / 5;
}
footer {
grid-row: 5 / 6;
}
}
body {
display: grid;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
}
header {
grid-area: header;
}
main {
grid-area: main;
}
nav {
grid-area: nav;
}
aside {
grid-area: aside;
}
footer {
grid-area: footer;
}
@media screen and (max-width: 800px) {
body {
grid-template-areas:
"header"
"nav"
"main"
"aside"
"footer";
}
}
body {
display: grid;
grid-template-areas:
"header header header header header"
"nav main main main aside"
"footer footer footer footer footer";
}
body {
display: grid;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
grid-template-columns: 220px 1fr 220px;
grid-template-rows: auto 1fr auto;
}
header {
grid-area: header;
}
main {
grid-area: main;
}
nav {
grid-area: nav;
}
aside {
grid-area: aside;
}
footer {
grid-area: footer;
}
@media screen and (max-width: 800px) {
body {
grid-template-areas:
"header"
"nav"
"main"
"aside"
"footer";
grid-template-columns: 1fr;
grid-template-rows: auto auto 1fr auto auto;
}
main {
margin-left: 0;
margin-right: 0;
}
}
效果如下:
<!-- HTML -->
<flex__grid>
<flex__row>
<flex__item col4></flex__item col4>
<flex__item col4></flex__item col4>
<flex__item col4></flex__item col4>
</flex__row>
</flex__grid>
:root {
--gutter: 10px;
--columns: 12;
--span: 1;
}
.flex__container {
display: flex;
flex-direction: column;
padding-left: var(--gutter);
padding-right: var(--gutter);
}
.flex__row {
display: flex;
margin-left: calc(var(--gutter) * -1);
margin-right: calc(var(--gutter) * -1);
}
.flex__row + .flex__row {
margin-top: 2vh;
}
.flex__item {
flex: 1 1
calc((100% / var(--columns) - var(--gutter)) * var(--span));
margin: 0 var(--gutter);
}
.flex__item1 {
--span: 1;
}
.flex__item2 {
--span: 2;
}
.flex__item3 {
--span: 3;
}
.flex__item4 {
--span: 4;
}
.flex__item5 {
--span: 5;
}
.flex__item6 {
--span: 6;
}
.flex__item7 {
--span: 7;
}
.flex__item8 {
--span: 8;
}
.flex__item9 {
--span: 9;
}
.flex__item10 {
--span: 10;
}
.flex__item11 {
--span: 11;
}
.flex__item12 {
--span: 12;
}
<!-- HTML -->
<grid__container>
<grid__item></grid__item>
</grid__container>
-
使用 fr 将网格均分为相等的值,即每列宽度都是 1 个 fr;配合 repeat() 函数,即repeat(12, 1fr) 创建了 12 列网格。
-
使用 gap 可以用来控制网格之间的间距。
-
配合 minmax() 还可以设置网格最小值。
:root {
--columns: 12;
--gap: 10px;
--span: 1;
}
.grid__container {
display: grid;
grid-template-columns: repeat(var(--columns), 1fr);
grid-template-rows: 1fr;
gap: var(--gap);
padding-left: calc(var(--gap) / 2);
padding-right: calc(var(--gap) / 2);
}
.grid__item {
min-block-size: 10vh;
grid-column: span var(--span);
}
.col1 {
--span: 1;
}
.col2 {
--span: 2;
}
.col3 {
--span: 3;
}
.col4 {
--span: 4;
}
.col5 {
--span: 5;
}
.col6 {
--span: 6;
}
.col7 {
--span: 7;
}
.col8 {
--span: 8;
}
.col9 {
--span: 9;
}
.col10 {
--span: 10;
}
.col11 {
--span: 11;
}
.col12 {
--span: 12;
}
.grid__container {
padding: 1em;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(60px, 1fr));
gap: 1em;
grid-auto-flow: dense;
}
.flex__container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
width: 100%;
}
但在末尾行,如果和前面行的个数不相同(Flex 项目)就会出现下图这样的效果:
.flex__container::after {
content: "";
display: flex;
flex: 0 1 32vw;
}
注意,伪元素的 flex-basis 建议设置的和卡片的 flex-basis(或宽度)等同。这个时候你将看到像下面这样的示例:
占位符元素数量 = 每行最大的列数 – 2
body {
padding: 1vh;
}
.flex__container {
display: flex;
flex-wrap: wrap;
gap: 2vh;
width: 100%;
}
.flex__item {
flex: 0 1 calc((100vw - 8vh) / 4);
}
body {
padding: 1vh;
}
.grid__container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1vh;
}
效果如下:
-
如果 VAL 在 MIN 和 MAX 之间,则使用 VAL 作为函数的返回值。
-
如果 VAL 大于 MAX,则使用 MAX 作为函数的返回值。
-
如果 VAL 小于 MIN,则使用 MIN 作为函数的返回值。
.element {
/**
* MIN = 100px
* VAL = 50vw ➜ 根据视窗的宽度计算
* MAX = 500px
**/
width: clamp(100px, 50vw, 500px);
}
比如浏览器视窗现在所处的位置是 1200px 的宽度,那么 .element 渲染的结果如下:
-
元素 .element 的宽度不会小于 100px(有点类似于元素设置了 min-width: 100px)。
-
元素 .element 的宽度不会大于 500px(有点类似于元素设置了 max-width: 500px)。
-
首选值 VAL 为 50vw,只有当视窗的宽度大于 200px 且小于 1000px 时才会有效,即元素.element 的宽度为 50vw(有点类似于元素设置了 width:50vw)。
<!-- HTML -->
<ul class="brands">
<li class="brands__item">
<a href="#">
<img src="img/logo.png" alt="">
</a>
</li>
<li> <!-- ... --> </li>
</ul>
居中对齐前面已经介绍过了,这里主要是看图像大小方面的处理:
.brands {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
grid-gap: 1rem;
}
.brands__item {
background: #eee;
}
.brands__item a {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.brands__item img {
width: 130px;
height: 75px;
object-fit: contain;
}
这样就能实现上图的效果。你可能发现了,有些 Logo 图像带有背景颜色,如果让效果更好一些,可以把 CSS 混合模式相关的特性运用进来:
.brands__item img {
width: 130px;
height: 75px;
object-fit: contain;
mix-blend-mode: multiply;
}
这个时候,你看到的效果如下: