高品质的音视频能力是怎样的? | Qcon 全球软件开发大会·上海站邀请函 了解详情
写点什么

人人都用 Bootstrap 的年代过去了,如今我很难向开发者们推荐 Bootstrap 5

Thomas Dimnet

  • 2022-09-23
    北京
  • 本文字数:11205 字

    阅读完需:约 37 分钟

人人都用Bootstrap的年代过去了,如今我很难向开发者们推荐Bootstrap 5

Bootstrap 5 和 Tailwind 相比简直就是噩梦

 

我最近开始为开发人员编写小教程。我的目标是向初级开发人员展示高级开发人员在编写代码时是如何思考的。例如,高级开发人员如何开始理解他们原先不了解的文档或新框架,以及他们在出错时(也就是著名的“代码坏味道”)如何解决问题。

 

我在 Frontend Mentor 网站上找到了一些示例项目,并写了各种各样的代码。例如,第一个项目是一个产品卡片组件,我决定使用普通的 CSS 和 Tailwind 以及 Bootstrap 来编写解决方案。

 

这不仅对读者来说很有趣,对我来说也很有趣。我想看看 Tailwind 和 Bootstrap 在过去几年里发展得怎样。我知道 Tailwind 的开发者体验会很棒,但我并不知道原来使用 Bootstrap 5 会如此痛苦。它很糟糕,所以我写了这篇文章。

 

在本文中,你将看到历史(主要是关于 Bootstrap)、想法(关于开发体验)和代码片段。让我们先从历史部分讲起吧!

 

人人都用 Bootstrap 的年代

 

多年前,Bootstrap 无处不在。在 2016 年,你几乎找不到一个没有使用 Bootstrap 的网站。CSS Flexbox 已经有了,但 CSS Grid 还不为人所知,也没有得到很好的支持。我记得在 2016 年中,我曾与一位开发人员谈起 CSS Grid,我向他讲述了它的强大功能,但他的回答令人感到震惊——他还以为我说的是 HTML 表格元素,可见他对 CSS Grid 一无所知。那时,所有人都依赖 Bootstrap 3,他们都还在使用 jQuery。

 

除了 Bootstrap,还有其他 CSS 框架。第二个最著名框架的是 Foundation。除了电子邮件模板,我使用 Foundation 的机会并不多。也许它比 Bootstrap 更好或更差或不同或相同,事实上,我真的不知道。

 

他们声称(现在在他们的 GitHub 页面上仍然如此)自己是“世界上最先进的响应式前端框架”。但从他们的官方文档和 GitHub 代码库来看,我觉得它已经死了。我不想在历史方面花太多时间,只是想在继续其他话题之前补充一些东西。

 


bonnegueule.fr——2016 年使用 Bootstrap 编写的一个法国网站(来源:waybackmachine.com)

 

首先,Bootstrap 是由 Twitter 的工程师开发的,他们做得很好。Twitter 仍然在使用 Bootstrap,还有许多网站也是。大多数时候,即使你不是一个经验丰富的开发人员,也可以很容易地判断一个网站是否使用了 Bootstrap。但在我看来,这并不总是好事情,因为它会让所有网站看起来都一个样。

 

对于一些网站来说,这可能是一个优势,因为用户不需要重新熟悉网站。例如,他们知道链接或提交按钮是什么样子的。但是,在某些时候,你的网站失去了个性,依赖它就变成了一个劣势。它的第二个优点是核心开发团队决定在 Bootstrap 5 中移除 jQuery。我不知道这个决定是好是坏。今天,jQuery 没有其他前端框架那么受欢迎,开发人员也越来越少使用它,所以在某种程度上,这么做是有意义的。

 

然而,移除 jQuery 增加了核心开发团队的工作量,并且失去了对旧浏览器的一些兼容性。

 

最后要说声“感谢”。Bootstrap 核心开发团队在网页可访问性方面做得非常出色,尤其是 Bootstrap 4。他们引入了许多与 aria 属性相关的概念,并提供了人们可以使用的具体示例和代码示例。在我看来,Bootstrap 4 很棒!遗憾的是,Bootstrap 5 不是。

 

Tailwind 重塑编写 CSS 的方式

 

与许多人一样,我也是因为 Tailwind 才知道“实用优先 CSS(Utility-first CSS)”这个词。在此之前,我一直在尝试使用 BEM。我不知道你是怎么想的,但我一直对 BEM 有种迷惘的感觉。我了解修饰符的概念,但是当我需要使用块或元素时,会感到有点困惑。

 

理论上,按照这种方式构建 CSS 似乎是一个合理的想法。然而,它往往会污染 HTML 的可读性。这里有一篇文章(https://medium.com/@jescalan/bem-is-terrible-f421495d093a)介绍了这些概念。

 

让我们回到 Tailwind 上来。为什么说在开发“实用优先”CSS 框架时 Tailwind 向前迈出了一大步?如果你读过前面我分享的那个文章资源,那么你应该已经知道答案了。Tailwind 不像 Bootstrap 那样依赖组件且一次应用多种样式,相反,它添加只做一件事的类。换句话说,你编写的类可以进行任意组合——一个类用于填充,另一个类用于控制字体大小,等等。

 

我们来举个例子。

 

下面是使用 Bootstrap 编写的卡片组件。

 

<div class="card" style="width: 18rem;">  <img src="..." class="card-img-top" alt="...">  <div class="card-body">    <h5 class="card-title">Card title</h5>    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>    <a href="#" class="btn btn-primary">Go somewhere</a>  </div></div>
复制代码

 

结果看起来像这样:




下面是使用 Tailwind 编写的卡片组件。

 

<figure class="md:flex bg-slate-100 rounded-xl p-8 md:p-0 dark:bg-slate-800">  <img class="w-24 h-24 md:w-48 md:h-auto md:rounded-none rounded-full mx-auto" src="/sarah-dayan.jpg" alt="" width="384" height="512">  <div class="pt-6 md:p-8 text-center md:text-left space-y-4">    <blockquote>      <p class="text-lg font-medium">        “Tailwind CSS is the only framework that I've seen scale        on large teams. It’s easy to customize, adapts to any design,        and the build size is tiny.”      </p>    </blockquote>    <figcaption class="font-medium">      <div class="text-sky-500 dark:text-sky-400">        Sarah Dayan      </div>      <div class="text-slate-700 dark:text-slate-500">        Staff Engineer, Algolia      </div>    </figcaption>  </div></figure>
复制代码

 

结果看起来像这样。

 


这两张卡片看起来不一样,但我希望你们看看代码。在使用 Bootstrap 时,卡片组件可以在大小和颜色方面有所不同,但最终,它们或多或少看起来是一样的。还记得我在本文开头说的“即使你不是一个经验丰富的开发人员,也可以很容易地判断一个网站是否使用了 Bootstrap”吗?

 

在使用 Tailwind 时,你几乎可以把自定义样式添加到任何东西上。你可能会问,这重要吗?首先,因为它允许你按照你想要的方式设计网站,这就非常棒了,尤其是对设计师来说!其次,它可以帮助开发人员尽可能接近你想要的模型,并且不会破坏 HTML 标记和 CSS 之间的任何责任关系。

 

有了 Tailwind,你就不再需要依赖 BEM 了。对我来说,这真是个好消息!

 

开发者体验和文档

 

Tailwind——设置和使用都方便

 

那是我第一次使用 Tailwind。我的意思是,我之前就知道这个项目,并且已经阅读了文档,但还没有机会使用它。对于这个项目,我决定不使用 CLI 或 PostCSS。

 

我决定使用 CDN。通过阅读文档得知,生产环境的网站不适合这么做,但如果是出于试验的目的是可以的。不过我还是惊讶地发现,即使使用了 CDN,仍然可以很简单地添加自定义颜色和字体。

 

相比之下,Bootstrap API 则是一团糟。它的文档和示例代码都不容易看懂,尤其是如果你还不知道有版本 5。

 

我是这样在项目中设置 Tailwind 的:

 

<script src="https://cdn.tailwindcss.com"></script>  <script>    tailwind.config = {      theme: {        extend: {          colors: {            viridian: 'hsl(158, 36%, 37%)',            dawnPink: 'hsl(30, 38%, 92%)',            white: 'hsl(0, 0%, 100%)',            ebonyClay: 'hsl(212, 21%, 14%)',            stormGray: 'hsl(228, 12%, 48%)'          },          fontFamily: {            montserrat: ['Montserrat', 'sans-serif'],            fraunces: ['Fraunces', 'serif']          }        }      }    }  </script>
复制代码

 

在上面的代码示例中,我在 tailwind.config 对象中添加了新的颜色和新的字体。

 

然后,我在代码中使用它:

 

<p class="font-montserrat font-medium text-xs tracking-[.5em] uppercasetext-stormGray mb-3">  Perfume</p><h1 class="font-fraunces text-3xl font-bold text-ebonyClay mb-4">  Gabrielle Essence Eau de Parfum</h1><p class="font-montserrat font-medium text-sm text-stormGray mb-6">  A floral, solar and voluptuous interpretation composed by Olivier Polge,  Perfumer-Creator for the House of CHANEL.</p>
复制代码

 

看,这很容易!我不需要写自定义 CSS 或 Sass 代码,我只需要调用正确的类就可以了。它真的非常简单,但却很强大!

 

Tailwind——多么好的文档

 

这就引出了 Tailwind 的第二个优势——文档。我是一名开发人员(我想你也是),大多数时候,当我们忙于一个项目时,根本没有时间阅读整个文档。我们需要可以直接使用或重用的简单但具体的示例。

 

我们想看看 Tailwind 是否是一个对的工具,我们想很快得出结论。在过去的几年里,我对开发者体验(简称 DX)越来越感兴趣。以下是我在网上找到的一个有关 DX 的定义:

 

开发者体验是指与 API 或开发工具相关的每一次交互。

—— 来源:https://everydeveloper.com/developer-experience/

 

关于交互,不要只考虑代码注释、变量名或遵循约定,我们还要考虑文档,以及使用库或框架的容易程度。

 

例如,我认为 Symfony 和 Angular 的开发者体验就很棒。它们提供了教程、优秀的文档和代码示例。但还有更多的东西!当你开始使用它们时,你也会学到其他概念。例如,Symfony 文档解释了实体和存储库模式的概念。Angular 告诉我们什么是 Promise 和 Observable。

 

相反,React 的文档就算不上出色。它们都没有解释如何编写有效的测试,甚至关于 Hook 都没有提供足够的信息。大多数时候,当我与开发人员谈及 React Hook 时,他们并不了解它们的工作原理。所以说,DX 很重要,比你想象的更重要。它可以让一个项目成功,也可以让它失败。有了 Tailwind,我一个下午就能完成这个项目。文档应该易于阅读和使用,框架也是。那么,Bootstrap 5 怎么样?

 

Bootstrap——组件和 Utility 的混合

 

当我在写这篇文章时,我不确定我是想先讨论 Utility API 还是组件和 Utility 之间的模糊边界。

 

退一步来看,我认为这两个问题是相关的,从组件和 Utility 开始讨论可能会更有意义。

 

Bootstrap 从一开始都是关于组件,有表单组件、轮播组件(即使你不应该使用它)、面包屑组件、模态组件,等等。这些是(还是曾经是?)Bootstrap 最大的优势。

 

如果我想要一个标题呢?我在“Content”部分的“Typography”页面可以找到关于 heading、display 和 lead 类的信息。

 

这太棒了!但是“Utilities”部分的“Text”页面呢,尤其是“Font size”部分呢?这是另一种改变字体大小的方式。那么我应该用哪一种呢?我可以把它们结合起来使用吗?框架想让我怎么做?这些都是我在编写代码时问自己的问题。

 

Bootstrap 给我的印象是它位于两把椅子之间,不知道该坐哪一边。一方面,他们希望你坚持使用 Bootstrap 及其组件库,因为核心开发团队投入了大量时间和精力。另一方面,他们引入了 Utility 及其 API,但文档里又没有给出很多示例。

 

Bootstrap Utility API——理解它需要一些时间

 

几天前,我正在为产品组件编写 Bootstrap 解决方案,并创建了不使用 Bootstrap Utility 的类。

 

我想给一个元素添加 90%的宽度。我查看了文档,在“Utilities”部分找到了“Sizing”页面。默认宽度为 25%、50%、75%和 100%。我先创建了一个叫作 w-90 的自定义宽度,表示 90%,但我知道有些地方出错了。

 

这又是代码的坏味道!我快速查看了 Utility API 页面,并认为已经理解了。我必须在项目中安装 Sass 和 Bootstrap 才能使用这个 API。

 

我安装好了,然后跳到“Customize”部分的“Sass”页面,发现我可以做出一个选择——要么导入 Bootstrap 所有的东西,但不能修改 Utility,要么手动导入你需要的东西。

 

// Custom.scss// Option B: Include parts of Bootstrap

// 1. Include functions first (so you can manipulate colors, SVGs, calc, etc)@import "../node_modules/bootstrap/scss/functions";

// 2. Include any default variable overrides here

// 3. Include remainder of required Bootstrap stylesheets@import "../node_modules/bootstrap/scss/variables";

// 4. Include any default map overrides here

// 5. Include remainder of required parts@import "../node_modules/bootstrap/scss/maps";@import "../node_modules/bootstrap/scss/mixins";@import "../node_modules/bootstrap/scss/root";

// 6. Optionally include any other parts as needed@import "../node_modules/bootstrap/scss/utilities";@import "../node_modules/bootstrap/scss/reboot";@import "../node_modules/bootstrap/scss/type";@import "../node_modules/bootstrap/scss/images";@import "../node_modules/bootstrap/scss/containers";@import "../node_modules/bootstrap/scss/grid";@import "../node_modules/bootstrap/scss/helpers";

// 7. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss`@import "../node_modules/bootstrap/scss/utilities/api";

// 8. Add additional custom code here
复制代码

 

然后我修改了 Utility(下面将向你展示是如何修改的),并将 Sass 编译为 CSS。乍一看似乎没问题,但我很快发现按钮没有了样式。原来我忘记导入一些东西了,看看第 19 行到 26 行就知道了。

 

注释写着“根据需要导入其他部分”,但我是从 Bootstrap 5 开始的,我不知道哪些是需要的,哪些是不需要的。还记得我讲的 DX 吗?对我来说,这就是糟糕的 DX!因为即使是简单的复制和粘贴,你也找不到一个能用的例子。这很令人沮丧,也不会给人留下什么好印象。

 

下面是我修改的东西。

 

// Include any default variable overrides here (though functions won't be available)// Custom variables$viridian: hsl(158, 36%, 37%);$dawn-pink: hsl(30, 38%, 92%);$white: hsl(0, 0%, 100%);$ebony-clay: hsl(212, 21%, 14%);$storm-gray: hsl(228, 12%, 48%);

$font-montserrat: 'Montserrat', sans-serif;$font-fraunces: 'Fraunces', serif;

// Configuration@import "../node_modules/bootstrap/scss/functions";



// 2. Include any default variable overrides here$body-bg: $dawn-pink;$font-weight-normal: 500;



@import "../node_modules/bootstrap/scss/variables";

// 4. Include any default map overrides here$custom-colors: ( "viridian": $viridian, "dawn-pink": $dawn-pink, "white": $white, "ebony-clay": $ebony-clay, "storm-gray": $storm-gray);

// Merge the maps$theme-colors: map-merge($theme-colors, $custom-colors);



@import "../node_modules/bootstrap/scss/maps";@import "../node_modules/bootstrap/scss/mixins";@import "../node_modules/bootstrap/scss/utilities";

// Layout & components@import "../node_modules/bootstrap/scss/root";@import "../node_modules/bootstrap/scss/reboot";@import "../node_modules/bootstrap/scss/type";@import "../node_modules/bootstrap/scss/images";@import "../node_modules/bootstrap/scss/containers";@import "../node_modules/bootstrap/scss/grid";@import "../node_modules/bootstrap/scss/buttons";



// Import we don't need@import "../node_modules/bootstrap/scss/tables";@import "../node_modules/bootstrap/scss/forms";@import "../node_modules/bootstrap/scss/transitions";@import "../node_modules/bootstrap/scss/dropdown";@import "../node_modules/bootstrap/scss/button-group";@import "../node_modules/bootstrap/scss/nav";@import "../node_modules/bootstrap/scss/navbar";@import "../node_modules/bootstrap/scss/card";@import "../node_modules/bootstrap/scss/accordion";@import "../node_modules/bootstrap/scss/breadcrumb";@import "../node_modules/bootstrap/scss/pagination";@import "../node_modules/bootstrap/scss/badge";@import "../node_modules/bootstrap/scss/alert";@import "../node_modules/bootstrap/scss/progress";@import "../node_modules/bootstrap/scss/list-group";@import "../node_modules/bootstrap/scss/close";@import "../node_modules/bootstrap/scss/toasts";@import "../node_modules/bootstrap/scss/modal";@import "../node_modules/bootstrap/scss/tooltip";@import "../node_modules/bootstrap/scss/popover";@import "../node_modules/bootstrap/scss/carousel";@import "../node_modules/bootstrap/scss/spinners";@import "../node_modules/bootstrap/scss/offcanvas";@import "../node_modules/bootstrap/scss/placeholders";

// Helpers@import "../node_modules/bootstrap/scss/helpers";



$utilities: map-merge( $utilities, ( "width": map-merge( map-get($utilities, "width"), ( values: map-merge( map-get(map-get($utilities, "width"), "values"), (90: 90%), ), ), ), "max-width": map-merge( map-get($utilities, "max-width"), ( values: map-merge( map-get(map-get($utilities, "max-width"), "values"), (600: 680px), ), ), ), "font-family": map-merge( map-get($utilities, "font-family"), ( values: map-merge( map-get(map-get($utilities, "font-family"), "values"), ( montserrat: $font-montserrat, fraunces: $font-fraunces ), ), ), ), "letter-spacing": ( property: letter-spacing, class: lt, responsive: true, values: ( 0: 0px, 5: 5px, 10: 10px ) ) ));

// Utilities@import "../node_modules/bootstrap/scss/utilities/api";

.max-w { max-width: 300px;}
复制代码

 

我导入了所有东西,甚至是我(还)不需要的部分,然后我加了一个注释告诉自己(未来的自己)我不需要它们。

 

我多么希望能有一个具体的例子。最后,我终于能够添加新的 Utility 了。是的,这确实有点乏味。在下面的两个小节中,你将看到几个例子,关于如何在 Bootstrap 和 Tailwind 中导入和使用自定义字体以及如何添加新的宽度。我想有些人很希望能够看到具体的例子!

 

如何导入自定义字体

 

Tailwind

 

首先,导入字体。我使用的是谷歌字体。

 

<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,700&family=Montserrat:wght@500;700&display=swap"rel="stylesheet">
复制代码

 

然后,从 CDN 导入 Tailwind 并更新 tailwind.config 对象。我添加了备用字体和新的颜色。

 

  <script src="https://cdn.tailwindcss.com"></script>  <script>    tailwind.config = {      theme: {        extend: {          colors: {            viridian: 'hsl(158, 36%, 37%)',            dawnPink: 'hsl(30, 38%, 92%)',            white: 'hsl(0, 0%, 100%)',            ebonyClay: 'hsl(212, 21%, 14%)',            stormGray: 'hsl(228, 12%, 48%)'          },          fontFamily: {            montserrat: ['Montserrat', 'sans-serif'],            fraunces: ['Fraunces', 'serif']          }        }      }    }  </script>
复制代码

 

最后,使用它!

 

<span class="text-white font-montserrat font-bold text-sm">  Add to Cart</span>
复制代码

 

很简单,对吧?

 

Bootstrap

 

通过 npm 安装 Saas。

 

{  "dependencies": {    "bootstrap": "^5.2.0",    "sass": "^1.53.0"  },  "scripts": {    "sass": "node_modules/.bin/sass scss/main.scss css/main.css --watch"  }}
复制代码

 

通过 Sass 添加 Bootstrap 并导入 Bootstrap 所有的东西。

 

然后,你就可以去掉你不想要的部分。

 

在第 9 行和第 10 行之间,我定义了 Sass 变量。我在第 102 行和第 113 行之间修改了 font-family Utility。

 

// Include any default variable overrides here (though functions won't be available)// Custom variables$viridian: hsl(158, 36%, 37%);$dawn-pink: hsl(30, 38%, 92%);$white: hsl(0, 0%, 100%);$ebony-clay: hsl(212, 21%, 14%);$storm-gray: hsl(228, 12%, 48%);

$font-montserrat: 'Montserrat', sans-serif;$font-fraunces: 'Fraunces', serif;

// Configuration@import "../node_modules/bootstrap/scss/functions";



// 2. Include any default variable overrides here$body-bg: $dawn-pink;$font-weight-normal: 500;



@import "../node_modules/bootstrap/scss/variables";

// 4. Include any default map overrides here$custom-colors: ( "viridian": $viridian, "dawn-pink": $dawn-pink, "white": $white, "ebony-clay": $ebony-clay, "storm-gray": $storm-gray);

// Merge the maps$theme-colors: map-merge($theme-colors, $custom-colors);



@import "../node_modules/bootstrap/scss/maps";@import "../node_modules/bootstrap/scss/mixins";@import "../node_modules/bootstrap/scss/utilities";

// Layout & components@import "../node_modules/bootstrap/scss/root";@import "../node_modules/bootstrap/scss/reboot";@import "../node_modules/bootstrap/scss/type";@import "../node_modules/bootstrap/scss/images";@import "../node_modules/bootstrap/scss/containers";@import "../node_modules/bootstrap/scss/grid";@import "../node_modules/bootstrap/scss/buttons";



// Import we don't needimport "../node_modules/bootstrap/scss/tables";@import "../node_modules/bootstrap/scss/forms";@import "../node_modules/bootstrap/scss/transitions";@import "../node_modules/bootstrap/scss/dropdown";@import "../node_modules/bootstrap/scss/button-group";@import "../node_modules/bootstrap/scss/nav";@import "../node_modules/bootstrap/scss/navbar";@import "../node_modules/bootstrap/scss/card";@import "../node_modules/bootstrap/scss/accordion";@import "../node_modules/bootstrap/scss/breadcrumb";@import "../node_modules/bootstrap/scss/pagination";@import "../node_modules/bootstrap/scss/badge";@import "../node_modules/bootstrap/scss/alert";@import "../node_modules/bootstrap/scss/progress";@import "../node_modules/bootstrap/scss/list-group";@import "../node_modules/bootstrap/scss/close";@import "../node_modules/bootstrap/scss/toasts";@import "../node_modules/bootstrap/scss/modal";@import "../node_modules/bootstrap/scss/tooltip";@import "../node_modules/bootstrap/scss/popover";@import "../node_modules/bootstrap/scss/carousel";@import "../node_modules/bootstrap/scss/spinners";@import "../node_modules/bootstrap/scss/offcanvas";@import "../node_modules/bootstrap/scss/placeholders";

// Helpers@import "../node_modules/bootstrap/scss/helpers";



$utilities: map-merge( $utilities, ( "width": map-merge( map-get($utilities, "width"), ( values: map-merge( map-get(map-get($utilities, "width"), "values"), (90: 90%), ), ), ), "max-width": map-merge( map-get($utilities, "max-width"), ( values: map-merge( map-get(map-get($utilities, "max-width"), "values"), (600: 680px), ), ), ), "font-family": map-merge( map-get($utilities, "font-family"), ( values: map-merge( map-get(map-get($utilities, "font-family"), "values"), ( montserrat: $font-montserrat, fraunces: $font-fraunces ), ), ), ), "letter-spacing": ( property: letter-spacing, class: lt, responsive: true, values: ( 0: 0px, 5: 5px, 10: 10px ) ) ));

// Utilities@import "../node_modules/bootstrap/scss/utilities/api";

.max-w { max-width: 300px;}
复制代码

 

然后,我在 HTML 文件中使用它,如下所示:

 

<p class="text-uppercase text-storm-gray font-montserrat fw-normal lt-5">Perfume</p>
复制代码

 

如何添加 letter-spacing 属性

 

Tailwind

 

用下面的代码导入 Tailwind:

 

<script src="https://cdn.tailwindcss.com"></script>
复制代码

 

使用自定义的 Tailwind 类,如 tracking-[.5em]。

 

<p class="font-montserrat font-medium text-xs tracking-[.5em] uppercase text-stormGray mb-3">Perfume</p>
复制代码

 

就是这么简单!

 

Bootstrap

 

与上面一样,我通过 Npm 安装 Bootstrap 和 Sass。

 

然后,我修改了 Utility。请看第 34 行。我创建了一个新的 Utility,它使用了 lt 类,有三个值。

 

$utilities: map-merge(  $utilities,  (    "width": map-merge(      map-get($utilities, "width"),      (        values: map-merge(          map-get(map-get($utilities, "width"), "values"),          (90: 90%),        ),      ),    ),    "max-width": map-merge(      map-get($utilities, "max-width"),      (        values: map-merge(          map-get(map-get($utilities, "max-width"), "values"),          (600: 680px),        ),      ),    ),    "font-family": map-merge(      map-get($utilities, "font-family"),      (        values: map-merge(          map-get(map-get($utilities, "font-family"), "values"),          (            montserrat: $font-montserrat,            fraunces: $font-fraunces          ),        ),      ),    ),    "letter-spacing": (      property: letter-spacing,      class: lt,      responsive: true,      values: (        0: 0px,        5: 5px,        10: 10px      )    )  ));
复制代码

 

最后是使用它:

 

<p class="text-uppercase text-storm-gray font-montserrat fw-normal lt-5">Perfume</p>
复制代码

 

这是一篇很长的文章,比我刚开始写的时候预期的要长。在文章结束之前,我想告诉你们一些关于 Bootstrap 的事情。Bootstrap 3 和 Bootstrap 4 会好一些,但 Bootstrap 5 不是很好,特别是在文档和开发者体验方面。

 

我感觉 Bootstrap 正在衰落。它还没有消亡,但核心开发团队似乎迷失了愿景,不知道要去到哪里。也许我是错的,但毕竟 Bootstrap 在 React 和全域 SPA 之前就已经出现了。

 

它在过去、现在都可以与全栈式框架结合使用,但不包括 React,至少在我看来是这样。也许在几年后,我们会重新回归,但在今天,我似乎很难向初级或高级开发人员推荐 Bootstrap。

 

原文链接:

 

https://betterprogramming.pub/the-rise-and-fall-of-bootstrap-68d4cd703666

2022-09-23 14:213639

评论

发布
暂无评论
发现更多内容

面试突击47:死锁产生的原因有哪些?

王磊

Java 面试 java面试

互联网用户画像,精准营销,数仓有妙招

华为云开发者联盟

位图 GaussDB(DWS) 用户画像 精准营销 Roaringbitmap

区间合并算法

秋名山码民

算法 5月月更

共同推动基础软件根技术发展,华为与中国软件行业协会签署战略合作协议

科技热闻

数据湖揭秘—Delta Lake

阿里云大数据AI技术

sql spark 分布式计算 关系型数据库 存储

极狐GitLab入驻阿里云计算巢,共同提升云上开发体验

阿里云弹性计算

DevOps 计算巢

得物技术消息中间件应用的常见问题与方案

得物技术

kafka 分布式 MQ 中间件 消息队列

持续学习 和 灾难性遗忘

infoQ-LolitaAnn

人工智能 深度学习 5月月更

【架构学习09】——电商秒杀系统

tiger

架构实战营

网站开发进阶(五十四)jQuery获取父级元素、子级元素、兄弟元素方法汇总

No Silver Bullet

JQuery框架 5月月更

存储卷指标消失之谜 | K8S Internals 系列第二期

BoCloud博云

Kubernetes kubelet

万亿储能的极限拉力赛

钛禾产业观察

kubernetes下的Nginx加Tomcat三部曲之三

程序员欣宸

Java Kubernetes 5月月更

【架构学习10】——毕业总结

tiger

架构实战营

GaussDB(for Influx)与开源企业版性能对比

华为云开发者联盟

数据库 开源 查询 写入 GaussDB(for Influx)

位运算小妙招-求二进制序列中1的个数

芒果酱

c++ C语言 5月月更

趣学设计模式-代理模式

ZuccRoger

5月月更

5 月 20 日,API 网关 Apache APISIX Summit ASIA 2022 重磅来袭

Apache APISIX 中文社区

开源 API网关 Apache APISIX APISIX 网关 APISIX Summit

YUV数据分析

Loken

音视频 5月月更

SAP 订单模型的编排方式概述

Jerry Wang

订单管理 订单 5月月更 b2b 编排系统

为了让女朋友运动起来,小伙儿不仅买单车还设计了智能防盗单车锁

华为云开发者联盟

stm32 华为云IoT 智能防盗单车锁 蓝牙

明道云入选爱分析2022年两份低代码研究报告

明道云

沙利文发布《2021年中国数据库市场报告》:中国分布式数据库2021专利占全球76%

科技热闻

来自2022年的Python 网络爬虫补充知识,HTML+JSON+爬虫场景

梦想橡皮擦

5月月更

赵海鹏:如何进行OpenHarmony音频特性架构设计和开发工作

OpenHarmony开发者社区

OpenHarmony 开发者故事 开发者说

C语言_标准时间与秒单位的转换

DS小龙哥

5月月更

【LeetCode】乘积小于 K 的子数组Java题解

Albert

LeetCode 5月月更

ptrace注入分析

小道安全

flask上传作品之dbm操作

上进小菜猪

flask 5月月更

姐姐驾到 | 零基础小白如何学前端!

锋享前端

『Python』题集⒋

謓泽

Python 5月月更

人人都用Bootstrap的年代过去了,如今我很难向开发者们推荐Bootstrap 5_前端_InfoQ精选文章