”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 在Web工程中使用CSS级联层

在Web工程中使用CSS级联层

发布于2024-08-16
浏览:461

在Web工程中使用CSS级联层

CSS的全称是层叠样式表(Cascading Style Sheets),它的一个重要概念既是“层叠”,靠后声明的样式会覆盖前面的样式。这个特性使我们在开发新内容时,非常方便地在继承旧样式的同时做出一些微调。

随着前端开发的工程化,特别是Vue.js等框架的广泛使用,我们需要在项目中管理越来越多的碎片样式文件。当这些样式文件互相关联时,为了使它们在HTML文档中出现的顺序符合我们的预期,往往需要我们付出更多的精力。

好在,我们现在有了CSS级联层

通过级联层,我们可以非常方便地归类CSS代码,使得层中的样式永远在逻辑上按我们想要的方式排序,而不用关心它们在HTML文档中出现的顺序。

CSS级联层已被确认为 Baseline 2022,您可以放心地使用这个特性。

理想的工程实践

原子设计(Atomic Design)是现代Web开发中常用的设计模式,我们可以按照这个设计,将样式层同样分为以下五层:

  1. Atoms(原子)
  2. Molecules(分子)
  3. Organisms(生物体)
  4. Templates(模板)
  5. Pages(页面)

在实际工程中您可能需要增减它们,如添加一个基础层用于在不同浏览器中规范初始样式(Reboot/Normalize),所以最终工程中的样式层可能是这样的:

/* 规范基础样式、定义CSS自定义属性等 */
@layer base { /* ... */ }

/* 我们可以借助子层来排序这些可重用组件的样式 */
@layer components.atoms { /* ... */ }
@layer components.molecules { /* ... */ }
@layer components.organisms { /* ... */ }

/* 模板可以被归类到布局中 */
@layer layouts { /* ... */ }
@layer pages { /* ... */ }

只要我们保证HTML文档的最开始按照这个顺序定义层,我们就可以在之后的开发中直接将样式代码防止在层中而无需关系它们的被导入的先后顺序。



  Document

与TailwindCSS结合使用

目前绝大多数与TailwindCSS结合的组件库,均是通过JS控制工具类的方式调整组件的样式,本文不讨论这个方式。借助级联层可以将TailwindCSS与任意的组件库结合使用,从而允许我们使用tailwind微调组件库的样式。

TailWindCSS中已经有了层的概念,在4之前的版本中,依旧使用的模拟的层,并非真正的级联层,为了让TailwindCSS的样式在我们的工程中出现在合适的位置,我们需要改写导入文件:

/*
 * "base"这个层名会被TailwindCSS当作它的逻辑层处理,
 * 此处我们使用"tailwind-base"代替
 */
@layer tailwind-base {
  @tailwind base;
}

/*
 * "utilities"和"variants"同理,
 * 但我们无需定义两个层来包裹它们,因为它们始终应该定义在我们的样式之后
 */
@layer tailwind-utilities {
  @tailwind utilities;
  @tailwind variants;
}

然后,我们调整一下级联层的定义:

/*
 * 注意!我在此处删除了前文中的base层,
 * tailwind的base已经包含了样式的规范化内容,
 * 我们的工程通常不需要再次格式化
 */
@layer
  tailwind-base,
  components.atoms,
  components.molecules,
  components.organisms,
  layouts,
  pages,
  tailwind-utilities;

与组件库结合使用

组件库是前端工程必不可少的部分,以上文为基础,我们可以很容易地想到,组件的样式应当在“base”层(或“tailwind-base”层)与“layout”层之间,也即“components”层中。至于它应该在components中的何处,这需要您结合实际情况来决定,我们可以利用子层的特性进行排序

然而,绝大多数组件库均没有使用级联层,直接导入组件库的样式会使它们出现在所有层之外,在级联层规则下,它们的样式将是最高优先级,我们无法使用tailwind或者其他方式覆盖它们的样式。

为了解决这个问题,我开发了一个postcss插件,它能够通过配置为导入的样式添加级联层。

接下来,以Vite项目为例,简单说明一下如何在工程中结合使用 element-plus 组件库。

初始化项目以及安装TailwindCSS和Element Plus的内容在此省略,无论您是否使用自动导入的方式引入Element Plus均可以按本文的方式操作。

首先,安装@web-baseline/postcss-wrap-up-layer,您可以选择您喜欢的包管理器:

yarn add -D @web-baseline/postcss-wrap-up-layer

然后,在vite.config.ts文件中使用这个插件:

/* 这里省略了其他无关的配置内容 */

import WrapUpLayer from '@web-baseline/postcss-wrap-up-layer';

export default defineConfig({
  css: {
    postcss: {
      plugins: [
        WrapUpLayer({
          rules: [
            {
              /* 此处使用了正则进行匹配 */
              includes: /^node_modules\/element-plus\//,
              layerName: 'components.element-plus',
            },
          ],
        }),
      ],
    },
  },
})

就是这样,这个插件将会为所有匹配到的文件添加设置的级联层,如果您使用其他的组件库,可以进行类似的设置。

在Vue SFC(单文件组件)中更方便地处理CSS级联层

在Vue的单文件组件中,我们可以使用定义样式,我们可以直接在其中将样式包裹在级联层中,就像这样:

这不方便,也不美观。通常情况下,我们并不会关注样式在哪个层中,也不希望看到这个始终存在的缩进。因此,我也开发了一个vite插件,允许您以属性的形式(如:

安装@web-baseline/vite-plugin-vue-style-layer:

yarn add -D @web-baseline/vite-plugin-vue-style-layer

在vite.config.ts文件中使用这个插件:

/* 这里省略了其他无关的配置内容 */

import Vue from '@vitejs/plugin-vue';
import VueStyleLayer from '@web-baseline/vite-plugin-vue-style-layer';

export default defineConfig({
  plugins: [
    Vue(),
    VueStyleLayer(),
  ],
})

这样,就可以将上文的组件改写成下面的样子:

我认为,这或许可以成为Vue SFC官方支持的功能,甚至是新的Web特性,将layer作为

这个Vite插件目前已经满足了使用的需要,但我知道它还有些许不足之处,我正在考虑将其使用 unplugin 重构,以支持更多的框架,而不仅仅是Vite Vue。

在Nuxt中使用级联层

我通常使用Nuxt进行Web开发,而以上的功能在Nuxt中配置需要分散在各处,因此我将它们合并为一个模块以集中配置。由于Nuxt并不公开HTML文档的编辑,我在模块中添加了级联层排序字段。

安装@web-baseline/nuxt-css-layer:

yarn add -D @web-baseline/nuxt-css-layer

在nuxt.config.ts文件中使用这个模块:

/* 这里省略了其他无关的配置内容 */
export default defineNuxtConfig({
  modules: [
    '@web-baseline/nuxt-css-layer',
    '@nuxtjs/tailwindcss',
    '@element-plus/nuxt',
  ],
  cssLayer: {
    rules: [
      {
        includes: /^node_modules\/element-plus\//,
        layerName: 'components.element-plus',
      },
    ],
    cssLayerOrder: [
      'tailwind-base',
      'components.element-plus',
      'components.atoms',
      'components.molecules',
      'components.organisms',
      'layouts',
      'pages',
      'tailwind-utilities',
    ],
  },
});

结语

在CSS级联层的帮助下,我们可以方便的在大型项目中管理样式文件,同时也允许我们将TailwindCSS与那些传统的组件库结合使用。

感谢您的阅读,如果您觉得我的工作对您有所帮助,欢迎为我的仓库添加Star!

  • @web-baseline/postcss-wrap-up-layer
  • @web-baseline/vite-plugin-vue-style-layer
  • @web-baseline/nuxt-css-layer

如果您在使用的过程中发现任何问题,欢迎提出issue以及提出pr!

版本声明 本文转载于:https://dev.to/tm-sunnyday/zai-webgong-cheng-zhong-shi-yong-cssji-lian-ceng-322b?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 如何在 Django 中记录所有 SQL 查询?
    如何在 Django 中记录所有 SQL 查询?
    如何在 Django 中记录 SQL 查询记录 Django 应用程序执行的所有 SQL 查询有利于调试和性能分析。本文提供了有关如何有效实现此目标的分步指南。配置要记录所有 SQL 查询,包括管理站点生成的查询,请将以下代码段集成到settings.py 文件中的 LOGGING 字段:LOGGI...
    编程 发布于2024-11-06
  • JavaScript 是同步还是异步,是单线程还是多线程? JavaScript代码是如何执行的?
    JavaScript 是同步还是异步,是单线程还是多线程? JavaScript代码是如何执行的?
    JavaScript 是一种同步、单线程语言,一次只能执行一个命令。仅当当前行执行完毕后,才会移至下一行。但是,JavaScript 可以使用事件循环、Promises、Async/Await 和回调队列执行异步操作(JavaScript 默认情况下是同步的)。 JavaScript代码是如何执行的...
    编程 发布于2024-11-06
  • 如何从 PHP 中的对象数组中提取一列属性?
    如何从 PHP 中的对象数组中提取一列属性?
    PHP:从对象数组中高效提取一列属性许多编程场景都涉及使用对象数组,其中每个对象可能有多个属性。有时,需要从每个对象中提取特定属性以形成单独的数组。在 PHP 中,在不借助循环或外部函数的情况下用一行代码实现此目标可能很棘手。一种可能的方法是利用 array_walk() 函数和 create_fu...
    编程 发布于2024-11-06
  • 构建 PHP Web 项目的最佳实践
    构建 PHP Web 项目的最佳实践
    规划新的 PHP Web 项目时,考虑技术和战略方面以确保成功非常重要。以下是一些规则来指导您完成整个过程: 1. 定义明确的目标和要求 为什么重要:清楚地了解项目目标有助于避免范围蔓延并与利益相关者设定期望。 行动: 创建具有特定功能的项目大纲。 确定核心特征和潜在的发展阶段。 ...
    编程 发布于2024-11-06
  • 如何在不使用嵌套查询的情况下从 MySQL 中的查询结果分配用户变量?
    如何在不使用嵌套查询的情况下从 MySQL 中的查询结果分配用户变量?
    MySQL 中根据查询结果分配用户变量背景和目标根据查询结果分配用户定义的变量可以增强数据库操作能力。本文探讨了一种在 MySQL 中实现此目的的方法,而无需借助嵌套查询。用户变量赋值语法与流行的看法相反,用户变量赋值可以直接集成到查询中。 SET 语句的赋值运算符是= 或:=。但是,:= 必须在其...
    编程 发布于2024-11-06
  • 如何使用 array_column() 函数从 PHP 中的对象数组中提取 Cat ID?
    如何使用 array_column() 函数从 PHP 中的对象数组中提取 Cat ID?
    从 PHP 中的对象数组中提取猫 ID处理对象数组(例如猫对象数组)时,提取特定属性通常可以成为一项必要的任务。在这种特殊情况下,我们的目标是将每个 cat 对象的 id 属性提取到一个新数组中。正如您的问题中所建议的,一种方法涉及使用 array_walk() 和 create_function ...
    编程 发布于2024-11-06
  • 实用指南 - 迁移到 Next.js App Router
    实用指南 - 迁移到 Next.js App Router
    随着 Next.js App Router 的发布,许多开发者都渴望迁移他们现有的项目。在这篇文章中,我将分享我将项目迁移到 Next.js App Router 的经验,包括主要挑战、变化以及如何使该过程更加顺利。 这是一种增量方法,您可以同时使用页面路由器和应用程序路由器。 为...
    编程 发布于2024-11-06
  • 何时以及为何应调整 @Transactional 中的默认隔离和传播参数?
    何时以及为何应调整 @Transactional 中的默认隔离和传播参数?
    @Transactional中的隔离和传播参数在Spring的@Transactional注解中,两个关键参数定义了数据库事务的行为:隔离和传播。本文探讨了何时以及为何应考虑调整其默认值。传播传播定义了事务如何相互关联。常见选项包括:REQUIRED: 在现有事务中运行代码,如果不存在则创建一个新事...
    编程 发布于2024-11-06
  • OpenAPI 修剪器 Python 工具
    OpenAPI 修剪器 Python 工具
    使用 OpenAPI Trimmer 简化您的 OpenAPI 文件 管理大型 OpenAPI 文件可能会很麻烦,尤其是当您只需要一小部分 API 来执行特定任务时。这就是 OpenAPI Trimmer 派上用场的地方。它是一个轻量级工具,旨在精简您的 OpenAPI 文件,使其...
    编程 发布于2024-11-06
  • PHP:揭示动态网站背后的秘密
    PHP:揭示动态网站背后的秘密
    PHP(超文本预处理器)是一种服务器端编程语言,广泛用于创建动态和交互式网站。它以其简单语法、动态内容生成能力、服务器端处理和快速开发能力而著称,并受到大多数网络托管服务商的支持。PHP:揭秘动态网站背后的秘方PHP(超文本预处理器)是一种服务器端编程语言,以其用于创建动态和交互式网站而闻名。它广泛...
    编程 发布于2024-11-06
  • JavaScript 中的变量命名最佳实践,实现简洁、可维护的代码
    JavaScript 中的变量命名最佳实践,实现简洁、可维护的代码
    简介:增强代码清晰度和维护 编写干净、易理解和可维护的代码对于任何 JavaScript 开发人员来说都是至关重要的。实现这一目标的一个关键方面是通过有效的变量命名。命名良好的变量不仅使您的代码更易于阅读,而且更易于理解和维护。在本指南中,我们将探讨如何选择具有描述性且有意义的变量名称,以显着改进您...
    编程 发布于2024-11-06
  • 揭示 Spring AOP 的内部工作原理
    揭示 Spring AOP 的内部工作原理
    在这篇文章中,我们将揭开 Spring 中面向方面编程(AOP)的内部机制的神秘面纱。重点将放在理解 AOP 如何实现日志记录等功能,这些功能通常被认为是一种“魔法”。通过浏览核心 Java 实现,我们将看到它是如何与 Java 的反射、代理模式和注释相关的,而不是任何真正神奇的东西。 ...
    编程 发布于2024-11-06
  • JavaScript ESelease 笔记:释放现代 JavaScript 的力量
    JavaScript ESelease 笔记:释放现代 JavaScript 的力量
    JavaScript ES6,正式名称为 ECMAScript 2015,引入了重大增强功能和新功能,改变了开发人员编写 JavaScript 的方式。以下是定义 ES6 的前 20 个功能,它们使 JavaScript 编程变得更加高效和愉快。 JavaScript ES6 的 2...
    编程 发布于2024-11-06
  • 了解 Javascript 中的 POST 请求
    了解 Javascript 中的 POST 请求
    function newPlayer(newForm) { fetch("http://localhost:3000/Players", { method: "POST", headers: { 'Content-Type': 'application...
    编程 发布于2024-11-06
  • 如何使用 Savitzky-Golay 滤波平滑噪声曲线?
    如何使用 Savitzky-Golay 滤波平滑噪声曲线?
    噪声数据的平滑曲线:探索 Savitzky-Golay 过滤在分析数据集的过程中,平滑噪声曲线的挑战出现在提高清晰度并揭示潜在模式。对于此任务,一种特别有效的方法是 Savitzky-Golay 滤波器。Savitzky-Golay 滤波器在数据可以通过多项式函数进行局部近似的假设下运行。它利用最小...
    编程 发布于2024-11-06

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3