CSS布局技巧 | 豆包MarsCode AI刷题

53 阅读8分钟

概述

SS是Web开发中不可或缺的一部分,随着Web技术的不断革新,CSS也变得更加强大。CSS的众多属性你知道了多少?具体开发中该使用什么属性才最适合恰当?如今的一些CSS属性可以让我们节约更多的时间。比如在Web布局中,现代CSS特性就可以更好的帮助我们快速实现如等高布局,水平垂直居中,经典的圣杯布局、宽高比例、页脚保持在底部等效果。这篇文章将给大家解释几种常用css布局技巧

一、水平居中

利用Flexbxo布局模块和CSS Grid布局模块来实现

Flexbox中实现水平垂直居中

在Flexbox布局模块中,不管是单行还是多行,要让它们在容器中水平垂直居中都是件易事,而且方法也有多种。最常见的是在Flex容器上设置对齐方式,在Flex项目上设置 margin:auto。

你可能已经知道在Flex容器上设置 justify-content、align-items 的值为 center 时,可以让元素在Flex容器中达到水平垂直居中的效果。来看一个示例:

 
<!-- HTML -->
<div class="flex__container">
    <div class="flex__item"></div>
</div>
 
/* CSS */
.flex__container {
    display: flex;
    justify-content: center;
    align-items: center;
}

效果如下: f1b10d66d93d10181f795a8e11a6f229_c98aa4f3e6d6f6cba9c8b78c5b036711.png 这种方式特别适应于让Icon图标在容器中水平垂直居中,不同的是在Icon图标容器上显示设置display: inline-flex。比如下面这个示例:

 
<!-- HTML -->
<div class="flex__container">
    <svg> </svg>
</div>
 
/* CSS */
.flex__container {
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

效果如下:

899b28bc48f8ccea3dec3769d5663ff4_958252aa0dcdfdaf8cfdfe74d4a442e6.png 在这种模式之下,如果要让多个元素实现水平垂直居中的效果,那还需要加上 flex-direction: column,比如:

 
<!-- 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;
}

效果如下: d32ff6c3e77efef48ad17692d7a4bd85_9cde02f62b3607cd4549295177155913.png 在Flexbox布局中,还可以像下面这样让Flex项目在Flex容器中达到水平垂直居中的效果:

 
<!-- 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;
}

效果如下: 46d68c32b70ebbbe2817c5783a67166e_69ed4c48fc988b11633870a535fc69f9.png 如果在Flex容器中有多个Flex项目时,该方法同样有效:

 
.flex__container {
    display: flex; // 或inline-flex
    justify-content: center;
}
 
.flex__container > * {
    align-self: center;
}

61ec9d436907ce0f81e1bbdda04a96e9_1112f795498c3149f5f38fa8ad419de1.png 除此之外,还可以使用 place-content: center 让Flex项目实现水平垂直居中:

 
.flex__container {
    display: flex;
    place-content: center;
}
 
.flex__item {
    align-self: center;
}

0934df65d805f39a9a946236963489e9_15ef5124e8fa26ca9a305cad592d6e98.png 或者

 
.flex__container {
    display: flex;
    place-content: center;
    place-items: center;
}

f596d051bf7f81f44c279484a5330432_d31341a08f8319c768d4c8726e985735.png 这两种方式同样适用于Flex容器中有多个Flex项目的情景:

 
.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;
}

330e1a2d3ccfc8a0c29659538917a993_cd65990b63a43b3337c1b0eb0f61e77b.png place-content 是 align-content 和 justify-content 的简写属性;而 place-items 是 align-items 和 justify-items 的简写属性。即:

.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容器中只有一个Flex项目,还可以显式在Flex项目中显式设置 margin 的值为auto,这样也可以让Flex项目在Flex容器中水平垂直居中。例如:

 
.flex__container {
    display: flex; // 或 inline-flex
}
 
.flex__item {
    margin: auto;
}

1c6cc89380162531224d72392d44647d_4dca19d06799ffdcd986c96fa99f6fe1.png

Grid中实现水平垂直居中

CSS Grid布局可以说是现代Web布局中的银弹。它也是到目前为止布局系统中唯一一个二维布局系统。 在CSS Grid布局中,只需要仅仅的几行代码也可以快速的帮助我们实现水平垂直居中的效果。比如下面这个示例:

<!-- HTML -->
<div class="grid__container">
    <div class="grid__item"></div>
</div>
 
/* CSS */
.grid {
    display: grid; // 或 inline-grid
    place-items: center
}

91230e99e67b8439c95bb831b0ad5cb3_210ae4133c41beb31487c7c69d564479.png 在CSS Grid布局模块中,只要显式设置了 display: grid(或 inline-grid)就会创建Grid容器和Grid项目,也会自动生成网格线,即行和列(默认为一行一列)。

5d373e55bf84da9eaec3dea27e5a16b9_48b7c11a8a53f3863b13688d2a827d79.png 在没有显式地在Grid容器上设置 grid-template-columns 和 grid-template-rows,浏览器会将Grid容器默认设置为Grid内容大小:

8643a4b19e490c4efe1bb68b2633a982_50444b722dbb4d0d86d7bac7d3a447b6.png 这种方法也适用于CSS Grid容器中有多个子元素(Grid项目),比如:

 
<!-- HTML -->
<div class="grid__container">
    <div class="avatar">:)</div>
    <div class="media__heading"></div>
    <div class="media__content"></div>
    <div class="action"></div>
</div>

fc692cb90775212be7d484b712b55ec4_215a83e8f9e46716f790a223d2c825ea.png 而且 palce-items 适用于每个单元格。这意味着它将居中单元格的内容。比如下面这个示例:

 
<!-- 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;
}

b76814c851765f08196eb1e0e9ddca98_f2674b3e0f1b1d15b77c5faa94eecb63.png

等高布局

等高布局也是Web中非常常见的一种布局方式,而且实现等高布局的方案也有很多种。这里我们主要来看Flexbox布局模块和Grid布局模块给我们带来了什么样的变化。

在Flexbox和Grid布局模块中,让我们实现等高布局已经是非常的简单了,比如:

 
<!-- 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。

0e9d8fc39035ec5570967260c7229a54_12d461e3aaa4e92d784118b132f5463b.png 这种方式特别适用于卡片组件中:

bd4b48a97a1f31c14a913fc996474d7b_517f579a0e88f901c4a9efe455959d1f.png

在Grid布局模块中类似:

 
<!-- 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; /* 根据需求调整值*/
}

205bad71599c0f15ebebb600053aaf79_1be345e245cad3141993495c2dd6f6b8.png

82f186249c2ca574b41e9546371eb149_f18b2445c6a0a63e100928c6b66a8ae1.png 如果需求有所调整,比如在Flex项目 或 Grid项目的子元素高度和容器高度相同。

 
<!-- 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%;
}

100ab45c3de516aac37cc9628355e0be_403036b6763cd1ca34396dfbaeaf6e55.png

三 Sticky Footer

首先用下图来描述什么是Sticky Footer布局效果:

e0326552cfb7da66aa107d2503fc1792_576506831e0686794a1d501abeb5905f.png Sticky Footer实现方案和等高、垂直居中一样,同样有很多种方案可以实现 比如像下面这样的结构:

 
<!-- HTML -->
<header></header>
<main></main>
<footer></footer>

先来看Flexbox布局模块中的实现方案:

 
body {
    display: flex;
    flex-direction: column;
}
 
footer {
    margin-top: auto;
}

e4a9cbfe4756b9c0db9524de4704fa90_a28c308c9a41cc6be6e5f925733f80e0.png 可以尝试着在 main 区域右下角向下拖动,改变主内容区域的高度,你会发现“当内容不足一屏时,footer 会在页面的最底部,当内容超出一屏时,footer 会自动往后延后”。

在Flexbox布局中,还可以在 main 区域上设置下面的样式,达到相等的效果:

 
body {
    display: flex;
    flex-direction: column;
}
 
main {
    flex: 1 0 auto;
}

d62b36ecca48b290f7270a3d192b85c8_4fde7c5d6efe5eb3ab46011fe83ecbb8.png 如果你想省事的话,可以在 main 上显式设置 flex-grow:1,因为 flex-shrink 和 flex-basis 的默认值为 1 和 auto。 在CSS Grid布局中我们可以借助 1fr 让 main 区域根据Grid容器剩余空间来做计算。

 
.grid__container {
    display: grid;
    grid-template-rows: auto 1fr auto;
}

95a68661583e3d09f58e94a04763f9f7_fd43f62b1b0a2f077143cbaa29f604c1.png 在Web布局中,很多时候会对列做均分布局,最为常见的就是在移动端的底部Bar,比如下图这样的一个效果:

8d5a0323065895bb3c7f5c9b026d6f13_1c2005af0fd12451f1f748bbf65fc7b9.png 在Flexbox和Grid还没出现之前,如果希望真正的做到均分效果,可以用 100%(或 100vw)除以具体的列数。比如:

 
<!-- 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);
}

5c34c3f75e090f178f84c1df961852ec_8d1d98585807d692b70272ac0c60e750.png

圣杯布局

圣杯布局(Holy Grail Layout))是Web中典型的布局模式。看上去像下图这样:

8abfdf94a0cdd1f49f5c50bedc78d45c_a6297343b5a8b0cc3c52dd5f2f5d815d.png 对于圣杯布局而言,HTML结构是有一定的要求,那就是内容为先:

 
<!-- HTML -->
<header></header>
<main>
    <article></article> <!-- 主内容 -->
    <nav></nav>
    <aside></aside>
</main>
<footer></footer>

在这里主要还是和大家一起探讨,如何使用Flexbox和Grid布局模块来实现圣杯布局。先来看Flexbox实现方案:

 
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;
}

907a220ae03f1a18cd24a01c457d3641_ca7eceabafcb5e4f6ceea9166e9c1dd0.png 通过在 nav、aside 和 article 上显式设置 order 的值,可以很好的控制这三个区域的布局顺序。比如说,希望 aside 在 article 之前排列,只需要在上面的示例基础上做一点点调整:

     
nav {
    order: 0;
}
 
aside {
    order: -1;
}

2f79deb98a0abb948af4e432b753f775_6f2aec1d0e71ecd405379973ba810a53.png

注意,order的默认值为0,值越大越排在后面!

在上例的基础上,借助CSS媒体对象的特性,可以很容易实现响应式的圣杯布局效果:

 
@media screen and (max-width: 800px) {
    main {
        flex-direction: column;
    }
 
    nav, aside {
        width: 100%;
    }
}

7826bcc302c917be35d21f9343ce7046_da60459a711b0bac55c2f4d072a656b7.png 在Grid布局模块中,实现圣杯布局要比Flexbox布局模块中更容易,而且更灵活。在CSS Grid布局模块中,HTML结构可以更简洁:

 
<!-- 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;
}

10737a718e354fc518bd3463c18255e6_68f2f519c354c3fb88a44107743548a0.png 和Flexbox布局类似,在媒体查询中可以改变每个网格区域的位置:

 
@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;
    }
}

a1d5c487a015429afb5598bc90d839d8_c79d8ab76c811a05f8bc1855b63e600f.png 除了 grid-template(即 grid-template-columns 和 grid-template-rows)之外,在Grid布局中还可以使用 grid-area 和 grid-template-areas 属性的结合,也能很方便的实现CSS圣杯布局。基于上面的示例上,只需要把你的CSS调整为:

 
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";
    }
}

fb81440786882ad4d26c01f16338d73b_a9007321062dcfaeb1b3385c6acb9e39.png 如果我们希望 main 的区域变得更大,那么可以在 grid-template-areas 上做个调整:

 
body {
    display: grid;
    grid-template-areas:
        "header header header header header"
        "nav main main main aside"
        "footer footer footer footer footer";
}

36fdb13a2a7210603c04c5869ea69548_4d5c7d14d47724d460da0535cf9bdfdd.png 虽然在效果有所调整了,但还是均分状态。更好的解决方案是,将 grid-template-areas 和 grid-template 结合起来使用:

 
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;
    }
}

b03e8f184be57d919e8f4eaf2c8057dc_876a1274db25fe156de698cbbfc8d1e8.png