2024,该放弃框架来实现 Web 布局了

在这里,我并不想评论 CSS 框架和库的好坏,但一个不争的现实就是,很多 Web 开发者很容易在众多的 CSS 框架库中迷失方向。甚至,每个框架和库都向 Web 开发者承诺,将提供更简单的样式和更流畅的 Web 布局 。然而,在当下,现代 CSS 特性 提供了更简单和更灵活的方法,你完全可以不依赖任何 CSS 框架库就能构建出你想要的 Web 布局效果!

当下的现实就是,大部分 Web 开发者过度依赖各种框架,包括 CSS 方面的框架或库,来处理样式上的事情,其中就包括为 Web 网站或应用构建布局。尽管通过配置框架可以实现我们所需的功能,但试问你有多少次仅仅为了实现 Web 布局而整合整个 CSS 框架或库呢?我相信我们当中有许多人在某个时刻都这样做过,甚至现在依旧还在这样做。

今天,我想通过这篇文章告诉大家的是,现代 CSS 提供了很多优秀的特性 ,它们可以为 现代 Web 布局 提供更好、更灵活的布局方案,你完全无需仅为布局而使用框架。而且这些特性,将为你对 Web 布局获得更大的控制权。

Web 布局一直以来对于众多 Web 开发者来说是具有一定的挑战性,但随着 现代 CSS 特性 的出现,这些挑战逐渐变得越来越没有难度。甚至包括很多 创意性布局和异形布局

接下来,我们将会探讨如何使用现代 CSS 特性FlexboxGrid 布局提供更强大的便利性,例如流体布局和重复布局。在这个过程中,我将整合 CSS 容器查询 ,使这些布局根据自身的大小而不是视窗大小进行响应,与此同时,还将应用 CSS 级联层特性,进一步允许你控制样式,防止样式发生冲突。

这意味着,你需要对现代 CSS 的一些特性有一定的认识,易于帮助你更好的阅读和理解下面的内容。如果你对现代 CSS 特性不怎么熟悉,那么个人强烈建议你购买我的小册------《现代 CSS》,它将将使你深度掌握 CSS 各种最新特性。

猛戳这里 ,或者扫描上面海报二维码(GZp5dTBe),输入优惠码,你可享受七折优惠,数量有限,先到先得!!!

有效利用 CSS 级联层和变量特性

使用过 CSS 框架或相关方法论的开发者,对于 CSS 级联层和变量这两个概念不会感到陌生。因为大多 CSS 框架都会使用它们来管理和维护 CSS 。例如,ITCSS ,它就以下图这样的方式来管理 CSS:

如今,不需要这么麻烦了,我们可以使用 CSS 的 @layer 规则 来管理 CSS。这个特性不仅可以使样式整洁有序,还允许我们通过按特定的顺序组织这些层来影响每个层的权重。这些使我们创建的 CSS 更易于维护,并可以轻松地集成到你的项目中,而且还不会遇到样式权重的冲突。

在我们今天要聊的内容中,我认为以下三个层足够了:

CSS 复制代码
@layer reset, theme, layout;

注意这个顺序,因为它真的非常重要。

排列在前面的层,其权重越低。因此,我把 reset 层排在第一,使其成为所有层中权重最低的一层;layout 层排在最后,使其权重最高,优先级高于其他两个层中的样式。

注意,如果我们添加一个没有层级的样式,它将被统一放置在一个名叫匿名层中,其权重是最高的。

说实话,我现在恋上了这个级联层规则,不管是在平时的项目中,还是在 Codepen 写案例,我都习惯性的使用它来组织我的 CSS 代码。

非常遗憾的是,今天的主题并不是聊 CSS 的级联层,因此我无法使用更多的篇幅来向大家阐述它。如果你想深入的了解她,请移步阅读《CSS 分层:@layer》一文。

既便如此,还是要花点时间来聊聊这三个层在工作中应该如何使用。

reset 层比较好理解,这个层将包含我们希望"重置"浏览器样式的样式,比如你项目中的 reset.cssnormalize.css 文件中的代码就可以放在这个层中。当然,你也可以使用之前的方式,通过单独的样式文件来"重置"浏览器默认样式。但需要记住,在引入样式文件时,要是没有使用级联规则 @layer 定义它的层级顺序,它将会被认为是匿名层级,具有最高的权重。这种情况之下,很有可能会给你造成一定的困惑。

不过,我个人习惯性喜欢在 reset 层中,使用简单"重置"样式,例如:

CSS 复制代码
@layer reset {
    *,
    *::before,
    *::after {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
}

这种方式简单且粗暴,有时候也会使你为其他元素添加不少样式。比如,为 ph1 ~ h6 等元素设置 margin 等。因此,你需要根据自己的习惯和项目环境,配置比较合适的"重置"样式。

接下来是 theme 层。从其名应该大致知道这个层的作用。是的,它就是用来设置与主题相关的样式,例如、颜色、间距等属性。在这里,我们在 :root 中定义一些与布局相关的 CSS 变量。例如:

CSS 复制代码
@layer theme {
    :root {
        --layout-fluid-min: 35ch;
        --layout-default-repeat: 3;
        --layout-default-gap: 3vmax;
        --layout-default-ram-size: min(100% - 2rem, 300px);
    }
}

我习惯性在 :root 上定义这些与布局相关的变量,因为布局容器通常是许多其他元素的包装器,全局作用域可以确保变量在我们想要用的地方都可以被引用。不过,如果需要,也可以将这些变量作为局部变量,用于指定的元素上。

注意,上面的演示代码,其中 layout- 前缀只是用于标识,这些变量是用于布局上的,你可根据自己的喜好来调整,比如使用一个简写的 l- 来表示。我更想说的是,虽然只是几行简短的示例代码,但它包含多个现代 CSS 特性:

  • CSS 自定义属性,也俗称 CSS 变量,它是以 -- 为前缀定义变量名称,然后通过 var() 函数来引用。有关于这方面更详细的介绍,可以移步阅读《CSS 自定义属性你知道多少》和《CSS 自定义属性可以用来做些什么

  • chvmax 都是现代 CSS 中相对单位,其中 ch 是字体相对单位,vmax 是视窗相对单位。除此之外,还新增很多相对单位,比如 cqwlh 等。有关于这方面更详细的介绍,可以移步阅读《现代 CSS 中的相对单位

  • min() 函数是 CSS 的比较函数,与其同时出现的还有 max()clamp() 函数。这三个函数在现代 Web 布局中非常有用。例如,min() 函数,将会根据提供的参数列表中返回最小的值。有关于这方面的介绍,可以移步阅读《CSS 的比较函数:min() 、max() 和 clamp()

  • ram,它更专业的写法是大写的,即 RAM 。它表示的是现代 Web 布局中的一个经典布局技术。利用 CSS Grid 布局中的 repeat() 和 minmax() 函数以及 auto-fit 或 auto-fill 属性实现自动换行布局(注意,不是文本换行)

是不是信息量有点爆棚!

layout 层主要是用来设置布局相关的样式的,我们接下来的代码大部分都是在这个层中完成。刚才提到过,我们将会使用一些现代 CSS 特性来完成一些特定的布局,比如流式布局、重复布局和 RAM 布局。最为关键的是,这些布局你只需要在容器中引用相对应的类名就可以快速完成。因此,我们在 layout 层定义几个类名。

CSS 复制代码
@layer layout {
    .repeating-grid{
        
    }
    
    .repeating-flex {
    
    }
    
    .fluid-grid {
    
    }
    
    .fluid-flex {
    
    }
    
    .grid-ram {
    
    }
}

现在我们已经组织好了所有层,设置了变量,并定义了规则集,我们可以开始实际的布局工作了。我们将从基于 CSS GridFlexbox 的"重复"布局开始。

重复布局

我们先从简单的重复布局开始。

简单地介绍一下重复布局。这里所说的"重复布局"类似上图中的窗格,在布局容器中会包含多个元素,每个元素会按照指定的列数均等排列。这种布局,对于 CSS 的 Flexbox 和 Grid 是再简单不过了。因为它们具有弹性特性,使得我们无需去做过多的计算,即可吶应布局容器尺寸。

重复网格布局

前面我们在 layout 层中定义了两个类名: .repeating-grid.grid-ram 。它们其实都是用来定义重复网格布局的样式规则。

在 CSS 中,要通过网格布局技术来实现重复网格布局,首先得有相应的网格容器。因此,我们需要将 .repeating-grid.grid-ram 都定义为网格容器:

CSS 复制代码
@layer layout {
    .repeating-grid {
        display: grid;
    }
    
    .grid-ram {
        display: grid;
    }
}

你还可以使用 :is() 选择器对上面代码进行优化:

less 复制代码
@layer layout {
    :is(.repeating-grid, .grid-ram) {
        display: grid;
    }
}

有了网格容器之后,我们就可以在相应的类中应用我们创建的变量来建立布局。先以 .repeating-grid 为例:

CSS 复制代码
@layer layout {
    .repeating-grid {
        grid-template-columns: repeat(var(--layout-default-repeat), minmax(0, 1fr));
        gap: var(--layout-default-gap);
    }
}

现在,你就创建了一个三列多行的重复网格布局,其中行数由 .repeating-grid 中的子元素数量决定。假设你将 .repeating-grid 类名应用于像下面这样的一段 HTML 结构中:

HTML 复制代码
<div class="repeating-grid cards">
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
</div>

Demo 地址:codepen.io/airen/full/...

现在,每行始终会包含三个大小相等的列,这些列占据可用空间的一个分数 1fr ,并且它们之间有一个 3vmax 的间距。

注意,fr 单位是网格中独有的一个单位,会根据容器可以空间自动进行分配,具体的计算方式可以参阅《Grid 布局中的计算》。如果使用 1fr 将会告诉浏览器,将容器可用空间根据 repeat() 函数指定的列数进行均分。我在这里使用的是 minmax(0,1fr) ,主要用于避免 Grid 项目的最小尺寸不会小于其最小内容尺寸( min-content 。有关于这方面的详细阐述,请移步阅读《防御式 CSS 精讲》中的《Flexbox 和 Grid 布局中的最小内容尺寸》或者《可用于 Grid 布局中的函数》!

一个简单实用的重复网格布局就好了。如果你将 .repeating-grid 类名作为一个实用类名,融入到你自己的开发体系中,那么今后你只需要在容器上显式设置 class 类名,就可以实现重复布局。

当然,在此基础上我们可以进一步扩展。例如,将其列数和间距变得更具高可配置性。实现这个功能,并不复杂,也无需编写太多额外的代码。我们只需要在前面的基础上引入两个新的 CSS 变量,这些变量是局部的,仅用于 repeating-grid 的范围内:

  • --_grid-repeat :网格列数

  • --_repeating-grid-gap :网格间距

注意,这里我们使用 --_ 来区分全局变量,表示这个变量是"私有的"或局部作用域的。

添加私有变量的 .repeating-grid 样式规则变成下面这样:

CSS 复制代码
@layer layout {
    --_grid-repeat:var(--grid-repeat, var(--layout-default-repeat));
    --_repeating-grid-gap: var(--grid-gap, var(--layout-default-gap));
    
    grid-template-columns: repeat(var(--_grid-repeat), minmax(0, 1fr));
    gap: var(--_repeating-grid-gap);
}

注意,上面代码中,我们将全局变量作为局部变量的备用值。这样做的好处是,当 --grid-repeat--grid-gap 未定义值时,将采用全局变量定义的值作为备用值。如果你要使用的时候,又可以很容易覆盖全局变量,而且不会干扰其他地方使用全局变量。这是 CSS 自定义属性的一个主要特性,如果你对这个用法不是很了解,请移步阅读《CSS 自定义属性你知道多少》。

假设,你在另一个页面,希望将重复列从 3 更改为 5,同时将间隙从 3vmax 更新为 3vmin,使用相同的HTML,只需使用一个新的类来覆盖这些值。

HTML 复制代码
<div class="repeating-grid cards cards--products">
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <!-- 省略其他 card -->
</div>

然后在 .cards--products 重新分配列数和间距,即:

CSS 复制代码
.cards--products {
    --grid-repeat: 5;
    --grid-gap: 3vmin;
}

正如你所看到的,--grid-repeat: 5--grid-gap: 3vmin 重新分配布局列数和间距,从而实现了你想要的重复布局效果。但还不够完美,你还可以进一步使其变得更完美。例如:

  • 手机端只显示一列;

  • iPad 端显示两列;

  • 笔记本电脑显示三列

  • 桌面端显示四列

借助 CSS 媒体查询,使得进一步达到你所期望的重复布局效果:

CSS 复制代码
.cards--products {
    --grid-repeat: 1;
    --grid-gap: 1rem;
    
    @media only screen and (width >= 760px) {
        --grid-repeat: 2;
    }
    
    @media only screen and (width >= 1024px) {
        --grid-repeat: 3;
        --grid-gap: 2vmin;
    }
    
    @media only screen and (width >= 1280px) {
        --grid-repeat: 4;
        --grid-gap: 3vmin;
    }
}

Demo 地址:codepen.io/airen/full/...

这效果可能对你来说,很完美了,对吧!其实,我们还有更完美的方案,那就是 .grid-ram 类要做的事情了。

虽然 .repeating-grid 在 CSS 媒体查询的加持之下,可以根据视窗尺寸的变化调整列数和间距,但总是需要编写多个查询条件。针对于这样的布局场景,我们使用 CSS Grid RAM 布局会更灵活得多。它不需要你指定任何的列数,你只需要指定列的最小宽度和间距即可,至少显示多少列,让浏览器去计算吧。

.repeating-grid 类似,我们在 layout 层中完善 .grid-ram 的样式规则:

CSS 复制代码
@layer layout {
    .grid-ram {
        grid-template-columns: repeat(auto-fit, minmax(var(--layout-default-ram-size), 1fr));
        gap: var(--layout-default-gap);
   }
}

现在,你只需要将上面示例中的 .repeating-grid 类名替换为 .grid-ram ,具备 RAM 布局技术的重复网格布局就实现了:

HTML 复制代码
<div class="grid-ram cards">
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <div class="card"></div>
    <!-- 省略其他 card -->
</div>

Demo 地址:codepen.io/airen/full/...

同样的,我们可以给 .grid-ram 提供两个局部作用域的变量,用于设置网格项目的尺寸和间距:

  • --_ram-size :网格项目宽度(期望的小尺寸)

  • --_repeating-grid-gap :网格间距

CSS 复制代码
@layer layout {
    .grid-ram {
        --_ram-size: var(--ram-size, var(--layout-default-ram-size));
        --_repeating-grid-gap: var(--grid-gap,var(--layout-default-gap));
        grid-template-columns: repeat(auto-fit, minmax(var(--_ram-size), 1fr));
        gap: var(--_repeating-grid-gap);
    }
}

假设你在另一个页面中希望网格列的宽度是 400px1fr 之间变化,并且网格间距是 2vw 。那么你只需要在 page 层重新设置 --ram-size--grid-gap 的值即可:

CSS 复制代码
@layer page {
    .cards--products {
        --ram-size: 400px;
        --grid-gap: 2vw;
    }
}

这个时候,你看到的重复网格布局效果如下:

Demo 地址:codepen.io/airen/full/...

重复弹性布局

重复弹性布局与重复网格布局类似,但我们将使用 CSS Flexbox 来实现。首先,我们为 layout 层定义 .repeating-flex 样式:

CSS 复制代码
.repeating-flex {
    display: flex;
    flex-wrap: wrap; /* 这个非常重要 */
    gap: var(--layout-default-gap);
}

接下来,我们定义局部变量,以便可以根据需要覆盖全局变量:

CSS 复制代码
.repeating-flex {
    --_repeating-flex-gap: var(--flex-gap, var(--layout-default-gap));

    display: flex;
    flex-wrap: wrap;
    gap: var(--_repeating-flex-gap);
}

例如:

css 复制代码
@layer page {
    .cards--products {
        --flex-gap: 2vw;
    
        @media only screen and (width > 1000px) {
            --flex-gap: 3vw;
        }
    }
}

正如你所看到的,至少目前这个重复弹性布局是有问题的,Flex 项目并没有弹性,当 Flexbox 容器没有足够空间容纳第四列的时候,它右侧会有额外的空白区域。

在 Flexbox 布局中,我们可以使用 flex 属性来避免这种现象出现:

CSS 复制代码
@layer layout {
    .repeating-flex {
        --_repeating-flex-gap: var(--flex-gap, var(--layout-default-gap));
    
        display: flex;
        flex-wrap: wrap;
        gap: var(--_repeating-flex-gap);
    
        > * {
            flex: 1 1 25%;
        }
    }
}

这里使用 > * 选择器,主要是因为我们并不知道 Flex 项目使用的是什么元素。它可能是 div ,也可以是 section ,或其他 HTML 元素。使用 > * 选择器,我们至少可以确保只选择 Flex 项目,以防止影响其他元素样式。

你可能发现了,flex-basis 应用了一个 25% 的值,其实这是一个假定值。因为我们现在还没有引入重复列数。换句话说,这个 25% 应该是根据重复列数来自动匹配。这个时候,我们需要引入另外两个自定义属性:

CSS 复制代码
@layer layout {
    .repeating-flex {
        --_flex-repeat: var(--flex-repeat, var(--layout-default-repeat));
        --_repeating-flex-gap: var(--flex-gap, var(--layout-default-gap));
        
        --_gap-count: calc(var(--_flex-repeat) - 1);
        --_gap-repeater-calc: calc(
            var(--_repeating-flex-gap) / var(--_flex-repeat) * var(--_gap-count)
        );

        display: flex;
        flex-wrap: wrap;
        gap: var(--_repeating-flex-gap);
    
        > * {
            flex: 1 1 calc((100% / var(--_flex-repeat)) - var(--_gap-repeater-calc));
        }
    }
}

引入这两个变量的主要目的是用来正确计算 flex-basis 属性的值(即 flex 属性的第三个值),替代上面代码中的 25% 。这表示我们希望 Flex 项目的"理想"尺寸。为了让大家易于理解,我把变量先抽去,那么上面的代码对应的就是:

CSS 复制代码
@layer layout {
    display: flex;
    flex-wrap: wrap;
    gap: 3vmax;

    > * {
        flex: 1 1 calc((100% / 3) - calc(3vmax / 3 * 2));
    }
}

简单的解释一下 calc((100% / 3) - calc(3vmax / 3 * 2))calc() 计算出来的值就是 flex-basis 的值,也就是我们上面的假设值 25% ,只不过现在是浏览器自动根据 Flexbox 容器,列数,列间距计算的值。其中:

  • 100% 指的是 Flexbox 容器的尺寸

  • 3vmax 是列间距的尺寸

  • 3 是我们期望一行排列的列数

  • 2 是列与列之间的间隔数,由于我们一行排三列,第一列之前和第三列之后都没有间距,所以间隔数是 3 - 1 = 2

如果把具体的数值换作 CSS 变量,它就是:

CSS 复制代码
calc(var(--_repeating-flex-gap) / var(--_flex-repeat) * var(--_gap-count))
  • --_gap-count:通过从 --_flex-repeat (重复的列数) 中减去 1 来存储 Flex 项目之间的间隙数量(即,列与列之间的间隙数量)。因为在第一个项目之前或最后一个项目之后没有间隙,所以项目数量比间隙数量多一个。

  • --_gap-repeater-calc:根据每个项目的间隙大小和项目之间的总间隙数量来计算总间隙大小。

特别声明,CSS Flexbox 中的 flex 属性是一个非常复杂的特性。如果你想全面的了解 flex 以及其子属性 flex-shrinkflex-growflex-basis 是如何影响 Flex 项目的计算,又是如何影响整个 Flexbox 布局,那么我个人强烈建议好好阅读下面几篇课程的内容:

默认之下,你看到的效果如下:

Demo 地址:codepen.io/airen/full/...

同样的,你也可以根据具体的场景来调整局部作用域的变量:

CSS 复制代码
@layer page {
    .cards--products {
        --flex-gap: 2vh;
        --flex-repeat: 1;
        
        @media only screen and (width > 760px) {
            --flex-gap: 2vw;
            --flex-repeat: 2;
        }
    
        @media only screen and (width > 1024px) {
            --flex-gap: 3vw;
            --flex-repeat: 3;
        }
        
        @media only screen and (width > 1280px) {
            --flex-gap: 4vw;
            --flex-repeat: 4;
        }
    }
}

Demo 地址:codepen.io/airen/full/...

重复弹性布局与重复网格布局最大的差别是:

  • 在重复网格布局中,如果最后一行没有足够多的网格项目来填充所有列,那么之后的列将会以空格呈现

  • 在重复弹性布局中,如果最后一行没有足够的的 Flex 项目来填充所有列,那么 Flex 项目会自动扩展填充整个 Flexbox 容器(如下图所示)

流式布局

到目前为止,除了 RAM 布局,我们所做的重复布局都需要通过容器查询或媒体查询来调整重复的列数。但与其手动调整重复列数,不如将这个事情交给浏览器来处理,即浏览器通过流式布局自动填充布局容器中所有可用空间。因此,我们新增了两个实用类 .fluid-grid.fluid-flex ,利用少量的 CSS 来实现它,同时也不会影响到其他实用类的布局能力。

流式网格布局

这里所说的流式网格布局,其实与前面的 .grid-ram 实用类构建的重复网格布局是相似的。只不过,提供了一些额外的变量,使其更为灵活一些。具体来说,我们定义了一个名为 --_fluid-grid-min 的变量,用于管理网格列的最小宽度。

例如,假设你希望的网格列宽度至少是 400px ,并有 20px 的列间距。在这种情况下,当网格容器宽度大于 820px 时,我们基本上是在使用两列网格;反之,如果网格容器小于 820px ,那么列会拉伸到容器的全宽(此时列的宽度等于网格容器的宽度)。

如果我们想要一个三列网格,那么网格容器的宽度大约为 1240px (即 400 x 3 + 20 x 2)。这一切都在于控制列间距的最小尺寸值。

CSS 复制代码
@layer layout {
    .fluid-grid {
        --_fluid-grid-min: var(--fluid-grid-min, var(--layout-fluid-min));
        --_fluid-grid-gap: var(--grid-gap, var(--layout-default-gap));
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(min(var(--_fluid-grid-min), 100%), 1fr));
        gap: var(--_fluid-grid-gap);
    }
}

注意,它与 .grid-ram 之间的差异:

CSS 复制代码
@layer layout {
    .grid-ram {
        --_ram-size: var(--ram-size, var(--layout-default-ram-size));
        --_repeating-grid-gap: var(--grid-gap,var(--layout-default-gap));
        grid-template-columns: repeat(auto-fit, minmax(var(--_ram-size), 1fr));
        gap: var(--_repeating-grid-gap);
    }
}

可以说,它们除了自定义属性与类名之间的差异之外,几乎没有任何差异。这意味着,这两个实用类,你可以二选一。就我个人而言,我更喜欢将其命名为 .grid-ram ,因为看到类名就大概知道其布局采用的技术方案。

具体案例在这里就展示,你可以回过头看前面关于 .grid-ram 实用类相关的案例!

流式弹性布局

我们基本上可以重复 .repeating-flex 的 CSS 规则,但我们设置每列的 flex-basis 为其最小尺寸,而不是列数。

CSS 复制代码
@layer layout {
    .fluid-flex {
        --_fluid-flex-min: var(--fluid-flex-min, var(--layout-fluid-min));
        --_fluid-flex-gap: var(--flex-gap, var(--layout-default-gap));
    
        display: flex;
        flex-wrap: wrap;
        gap: var(--_fluid-flex-gap);
    
        > * {
            flex: 1 1 var(--_fluid-flex-min);
        }
    }
}

Demo 地址:codepen.io/airen/full/...

小结

稍微整理一下这几个实用类的 CSS 规则:

CSS 复制代码
@layer layout {
    :is(.repeating-grid, .grid-ram) {
        display: grid;
    }
  
    :is(.repeating-flex, .fluid-flex) {
        display: flex;
        flex-wrap: wrap; /* 这个很重要 */
    }
    
    .repeating-grid {
        --_grid-repeat: var(--grid-repeat, var(--layout-default-repeat));
        --_repeating-grid-gap: var(--grid-gap, var(--layout-default-gap));
    
        grid-template-columns: repeat(var(--_grid-repeat), minmax(0, 1fr));
        gap: var(--_repeating-grid-gap);
    }

    .repeating-flex {
        --_flex-repeat: var(--flex-repeat, var(--layout-default-repeat));
        --_repeating-flex-gap: var(--flex-gap, var(--layout-default-gap));
    
        --_gap-count: calc(var(--_flex-repeat) - 1);
        --_gap-repeater-calc: calc(
          var(--_repeating-flex-gap) / var(--_flex-repeat) * var(--_gap-count)
        );
    
        
        gap: var(--_repeating-flex-gap);
    
        > * {
            flex: 1 1 calc((100% / var(--_flex-repeat)) - var(--_gap-repeater-calc));
        }
    }


    .fluid-flex {
        --_fluid-flex-min: var(--fluid-flex-min, var(--layout-fluid-min));
        --_fluid-flex-gap: var(--flex-gap, var(--layout-default-gap));
    
        gap: var(--_fluid-flex-gap);
    
        > * {
            flex: 1 1 var(--_fluid-flex-min);
        }
    }

    .grid-ram {
        --_ram-size: var(--ram-size, var(--layout-default-ram-size));
        --_repeating-grid-gap: var(--grid-gap, var(--layout-default-gap));
        grid-template-columns: repeat(auto-fit, minmax(var(--_ram-size), 1fr));
        gap: var(--_repeating-grid-gap);
    }
}

请将这几个实用类对应的 CSS 规则存入你的 CSS 中,那么接下来,你在实际工作中,只需要在布局容器上设置所需的类名,并根据实际需求,调整相对应的局部变量,你的布局就能自动完成。

当然,如果你感兴趣,你可以按照类似的方式,将你经常使用的布局,通过实用类和 CSS 自定义属性结合起来,并将相应的规则集存放在 layout 层。这将让你减少重复性的工作。

虽然整篇文章只是介绍了几个关于 Web 布局的实用类,但它的信息量还是蛮大的。但整个思路就是一条,借助现代 CSS 特性与现代 Web 布局技术,做了一些只需编写一次并可以在任何需要特定布局的地方使用的类。我坚信,前面所述的内容能帮你打开一些编写 CSS 的思路,以及提供的实用类能减少你做一些重复性的工作。

最后,我想说的是,不管是现代 CSS 还是现代 Web 布局,所涵盖的东西绝不仅限于此,如果你感兴趣的话,请关注我的小册。


如果你觉得该教程对你有所帮助,请给我点个赞。要是你喜欢 CSS ,或者想进一步了解和掌握 CSS 相关的知识,请关注我的专栏,或者移步阅读下面这些系列教程:

相关推荐
魏大帅。3 分钟前
Axios 的 responseType 属性详解及 Blob 与 ArrayBuffer 解析
前端·javascript·ajax
花花鱼9 分钟前
vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法
前端·javascript·elementui
k093313 分钟前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
EricWang135834 分钟前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
September_ning34 分钟前
React.lazy() 懒加载
前端·react.js·前端框架
web行路人44 分钟前
React中类组件和函数组件的理解和区别
前端·javascript·react.js·前端框架
超雄代码狂1 小时前
ajax关于axios库的运用小案例
前端·javascript·ajax
长弓三石1 小时前
鸿蒙网络编程系列44-仓颉版HttpRequest上传文件示例
前端·网络·华为·harmonyos·鸿蒙
小马哥编程1 小时前
【前端基础】CSS基础
前端·css
嚣张农民2 小时前
推荐3个实用的760°全景框架
前端·vue.js·程序员