一起走进Tailwind CSS的世界

发表时间: 2023-07-18 09:53

1.介绍

tailwind 是一个流行的原子化 css 框架。本质上是一个工具集,包含了大量类似 flex、 pt-4、 text-center 以及 rotate-90 等工具类,可以组合使用并直接在 HTML 代码上实现任何 UI 设计。

2、安装

下方法是Vite + Vue模式下的安装方法,其他脚手架与框架的使用同理。

// 创建项目npm create vite app --template vue// 安装必要依赖npm i -D tailwindcss postcss autoprefixer// 使用tailwindcss的初始化命令创建TailwindCSS配置文件npx tailwindcss init -p

为了打包时TailwindCSS能生成对应的样式文件,需要在tailwind.config.js中正确配置content字段,如以下配置将扫描 src 目录下所有以 vue/js/ts/jsx/tsx 结尾的文件。

// tailwind.config.jsmodule.exports = {  content: [    './src/**/*.{vue,js,ts,jsx,tsx}'  ],    theme: {    extend: {},  },  plugins: [],}

注意:TailwindCSS并不会生成一个全量的样式包,而是根据具体使用到的语法生成对应的样式代码,这样可以确保打包产生的样式包是最小的。

引入Tailwind的基本指令

/* tailwind.css *//* tailwind base 相当于一份重置样式表,包含了最基础的样式。 */@tailwind base;/* tailwind components 包含了一些组件类, 组件相当于复合样式 */@tailwind components;/* tailwind utilities 包含了工具类,也就是 flex mx-auto 这些内置样式 */@tailwind utilities;/* 这么划分的原因是因为 css 的优先级规则,tailwindcss 全部都是一级样式,在类名权重相等的情况,下面的样式可以覆盖上面的样式,所以工具类优先,组件类次之,基础样式兜底,生成的样式顺序尤为重要,所以 上面三句指令的顺序非必须建议不要修改。*/

3、应用

传统上,当我们需要在网络上设计某些内容时,都会编写 CSS。

// 传统方案<script setup></script><template>    <div class="chat-notification">        <div class="chat-notification-logo-wrapper">            <svg class="h-12 w-12" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="a"><stop stop-color="#2397B3" offset="0%"></stop><stop stop-color="#13577E" offset="100%"></stop></linearGradient><linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="b"><stop stop-color="#73DFF2" offset="0%"></stop><stop stop-color="#47B1EB" offset="100%"></stop></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M28.872 22.096c.084.622.128 1.258.128 1.904 0 7.732-6.268 14-14 14-2.176 0-4.236-.496-6.073-1.382l-6.022 2.007c-1.564.521-3.051-.966-2.53-2.53l2.007-6.022A13.944 13.944 0 0 1 1 24c0-7.331 5.635-13.346 12.81-13.95A9.967 9.967 0 0 0 13 14c0 5.523 4.477 10 10 10a9.955 9.955 0 0 0 5.872-1.904z" fill="url(#a)" transform="translate(1 1)"></path><path d="M35.618 20.073l2.007 6.022c.521 1.564-.966 3.051-2.53 2.53l-6.022-2.007A13.944 13.944 0 0 1 23 28c-7.732 0-14-6.268-14-14S15.268 0 23 0s14 6.268 14 14c0 2.176-.496 4.236-1.382 6.073z" fill="url(#b)" transform="translate(1 1)"></path><path d="M18 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4zM24 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4zM30 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4z" fill="#FFF"></path></g></svg>        </div>        <div class="chat-notification-content">            <h4 class="chat-notification-title">ChitChat</h4>            <p class="chat-notification-message">You have a new message!</p>        </div>    </div></template><style>    .chat-notification {        display: flex;        max-width: 24rem;        margin: 0 auto;        padding: 1.5rem;        border-radius: 0.5rem;        background-color: #fff;        box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);    }    .chat-notification-logo-wrapper {        flex-shrink: 0;    }    .chat-notification-logo {        height: 3rem;        width: 3rem;    }    .chat-notification-content {        margin-left: 1.5rem;        padding-top: 0.25rem;    }    .chat-notification-title {        color: #1a202c;        font-size: 1.25rem;        line-height: 1.25;    }    .chat-notification-message {        color: #718096;        font-size: 1rem;        line-height: 1.5;    }</style>

使用 Tailwind,您可以通过直接在 HTML 中应用预先存在的类来设置元素样式。

// Tailwind方案<script setup></script><template>    <div class="p-6 max-w-sm mx-auto bg-white rounded-xl shadow-lg flex items-center space-x-4">      <div class="shrink-0">          <svg class="h-12 w-12" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="a"><stop stop-color="#2397B3" offset="0%"></stop><stop stop-color="#13577E" offset="100%"></stop></linearGradient><linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="b"><stop stop-color="#73DFF2" offset="0%"></stop><stop stop-color="#47B1EB" offset="100%"></stop></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M28.872 22.096c.084.622.128 1.258.128 1.904 0 7.732-6.268 14-14 14-2.176 0-4.236-.496-6.073-1.382l-6.022 2.007c-1.564.521-3.051-.966-2.53-2.53l2.007-6.022A13.944 13.944 0 0 1 1 24c0-7.331 5.635-13.346 12.81-13.95A9.967 9.967 0 0 0 13 14c0 5.523 4.477 10 10 10a9.955 9.955 0 0 0 5.872-1.904z" fill="url(#a)" transform="translate(1 1)"></path><path d="M35.618 20.073l2.007 6.022c.521 1.564-.966 3.051-2.53 2.53l-6.022-2.007A13.944 13.944 0 0 1 23 28c-7.732 0-14-6.268-14-14S15.268 0 23 0s14 6.268 14 14c0 2.176-.496 4.236-1.382 6.073z" fill="url(#b)" transform="translate(1 1)"></path><path d="M18 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4zM24 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4zM30 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4z" fill="#FFF"></path></g></svg>      </div>      <div>          <div class="text-xl font-medium text-black">ChitChat</div>          <p class="text-slate-500">You have a new message!</p>      </div>    </div></template><style></style>

在上面的例子中,使用了

  • Tailwind 的Flexbox和填充实用程序(flex、shrink-0和p-6)控制整体卡片布局
  • 最大宽度和边距实用程序 (max-w-sm和mx-auto) 限制卡片宽度并将其水平居中
  • 设置卡片外观样式的背景颜色、边框半径和框阴影实用程序用(bg-white、rounded-xl和shadow-lg)
  • 图像宽度和高度实用程序用 (w-12和h-12)
  • space-Between实用程序 (space-x-4) 处理图像和文本之间的间距
  • 设置卡片文本样式的字体大小、文本颜色和字体粗细实用程序(text-xl、text-black、font-medium)

能够实现完全自定义的组件设计,而无需编写一行自定义 CSS。

TailwindCSS语法检索技巧 TailwindCSS的基本原则是将每一个style语法转换为一个class,因此,在官网检索想要的样式class时,按照样式的语法来检索是效率最高的。如想要获取圆角的语法,只需要搜索Border Radius即可

<template>    <div class="text-base p-1 border border-black border-solid"></div></template><style>	.text-base {    font-size: 16px;}.p-1 {    padding: 4px;}.border {    border-width: 1px;}.border-black {    border-color: black;}.border-solid {    border-style: solid;}</style>

image.png

悬停、焦点还有其他状态

<script setup>    import { reactive } from 'vue';    const data = reactive({        list: [            {                name: '克里斯汀·拉莫斯',                email: 'kristen.ramos@example.com',                imageUrl: 'https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80'            },            {                name: '弗洛伊德·迈尔斯',                email: 'kristen.ramos@example.com',                imageUrl: 'https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80'            },            {                name: '考特尼·亨利',                email: 'kristen.ramos@example.com',                imageUrl: 'https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80'            },            {                name: '特德·福克斯',                email: 'kristen.ramos@example.com',                imageUrl: 'https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80'            },        ],    });</script><template>    <!--        hover:        active:        focus:ring(带有盒子阴影的轮廓环)     -->    <button class="bg-violet-500 hover:bg-violet-600 active:bg-violet-700 focus:outline-none focus:ring focus:ring-violet-300">保存</button>    <!-- 第一个、最后一个、奇数和偶数 -->        <div class="max-w-md mx-auto bg-white shadow my-8">            <ul role="list" class="p-6 divide-y divide-slate-200">                <li class="flex py-4 first:pt-0 last:pb-0 odd:bg-white even:bg-slate-50" v-for="(item, index) in data.list" :key="index">                    <img  referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"  class="h-10 w-10 rounded-full" :src="item.imageUrl" alt="" />                    <div class="ml-3 overflow-hidden">                        <p class="text-sm font-medium text-slate-900">{{item.name}}</p>                        <p class="text-sm text-slate-500 truncate">{{item.email}}</p>                    </div>                </li>            </ul>        </div>    </template>    ```    ### 响应式设计    Tailwind 中的每个实用程序类都可以在不同的断点处有条件地应用,这使得构建复杂的响应式界面变得轻而易举,而无需离开 HTML。受常见设备分辨率的启发,默认有五个断点:![image.png](https://wos.58cdn.com.cn/IjGfEdCbIlr/ishare/712be3f2-ba8e-4030-88b4-8d2d6ec4496cimage.png)```html<div class="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl">  <div class="md:flex">    <div class="md:shrink-0">      <img  referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"  class="h-48 w-full object-cover md:h-full md:w-48" src="/img/building.jpg" alt="Modern building architecture">    </div>    <div class="p-8">      <div class="uppercase tracking-wide text-sm text-indigo-500 font-semibold">Company retreats</div>      <a href="#" class="block mt-1 text-lg leading-tight font-medium text-black hover:underline">Incredible accommodation for your team</a>      <p class="mt-2 text-slate-500">Looking to take your team away on a retreat to enjoy awesome food and take in some sunshine? We have a list of places to do just that.</p>    </div>  </div></div>

比如要实现一个媒体查询,根据不同的屏幕宽度实现不同的图片宽度。

按照之前的写法,可能得这么干@mediaonly screen and (max-width:1280px) {   .img {         width:196px;   } }@mediaonly screen and (max-width:760px) {   .img {         width:128px;   } }
// tailwind方案<img  referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"  class="w-16 md:w-32 lg:w-48" src="...">

深色模式

Tailwind 提供了一个dark变体,可在启用暗模式时以不同的方式设计网站

<div class="bg-white dark:bg-slate-800 rounded-lg px-6 py-8 ring-1 ring-slate-900/5 shadow-xl">  <div>    <span class="inline-flex items-center justify-center p-2 bg-indigo-500 rounded-md shadow-lg">      <svg class="h-6 w-6 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true"><!-- ... --></svg>    </span>  </div>  <h3 class="text-slate-900 dark:text-white mt-5 text-base font-medium tracking-tight">Writes Upside-Down</h3>  <p class="text-slate-500 dark:text-slate-400 mt-2 text-sm">    The Zero Gravity Pen can be used to write in any orientation, including upside-down. It even works in outer space.  </p></div>

重用样式

<div>  <div class="mt-3 flex -space-x-2 overflow-hidden">    <img  referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"  class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>    <img  referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>    <img  referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"  class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2.25&w=256&h=256&q=80" alt=""/>    <img  referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"  class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>    <img  referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1517365830460-955ce3ccd263?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>  </div></div>

每个头像的程序类重复了5次

<script setup></script><template>	<div>        <div class="mt-3 flex -space-x-2 overflow-hidden">            <img  referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"  class="avator" src="https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>            <img  referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"  class="avator" src="https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>            <img  referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"  class="avator" src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2.25&w=256&h=256&q=80" alt=""/>            <img  referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   class="avator" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>            <img  referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"   referrerPolicy="no-referrer"  class="avator" src="https://images.unsplash.com/photo-1517365830460-955ce3ccd263?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>        </div>    </div></template><style scoped>	@tailwind base;@tailwind components;@tailwind utilities;@layer components {  .avator-primary {    @apply inline-block h-12 w-12 rounded-full ring-2 ring-white;  }}</style>

功能和指令

@tailwind

使用@tailwind指令可以向css添加tailwind的base、component、utilities样式

/** * This injects Tailwind's base styles and any base styles registered by * plugins. */ @tailwind base;/** * This injects Tailwind's component classes and any component classes * registered by plugins. */ @tailwind components;/** * This injects Tailwind's utility classes and any utility classes registered * by plugins. */ @tailwind utilities;

@apply

使用 @apply 将任何现存的功能类内联到自定义 CSS 中。如上面重复样式的例子所用的方式。

@layer

使用 @layer 指令告诉 Tailwind 一组自定义样式应该属于哪个 “bucket”。可用的层有 base, components 和 utilities。

@tailwind base;@tailwind components;@tailwind utilities;/* 如果想为特定 HTML 元素添加自己的默认基本样式,使用指令@layer将这些样式添加到 Tailwind 的base图层中*/@layer base {  h1 {    @apply text-2xl;  }  h2 {    @apply text-xl;  }}/* component更适合用于复杂的、需要在多个地方重复使用的样式*/@layer components {  .btn-blue {    @apply bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded;  }}/*utilities更适合用于快速创建简单的、仅在特定场景使用的样式。*/@layer utilities {  @variants hover, focus {    .filter-none {      filter: none;    }    .filter-grayscale {      filter: grayscale(100%);    }  }}

@screen

@screen 指令允许创建通过名称引用断点的媒体查询,而不是在 CSS 中复制他们的值。

/* 假设有一个名为 sm 的 640px 的断点,只需要写一些自定义的指向这个断点的 CSS。 *//* 而不是编写一个复制那些值的原始的媒体查询,如下所示: */@media (min-width:640px) {  /* ... */}@screen sm {  /* ... */}

screen()

screen 函数接受像 md 这样的屏幕名称并生成相应的媒体特征表达式:

/* Input */@media screen(sm) {  /* ... */}/* Output */@media (min-width:640px) {  /* ... */}

theme()

使用 theme() 函数可以通过点符号来获取 Tailwind 配置的值。 当想要引用一个主题配置中的一部分声明的值时

@tailwind utilities;@layer utilities {    .div {        border: 1px solid theme('colors.cyan');    }}

定制

tailwind.config.js配置任何自定义项:内容、主题、屏幕、颜色、间距、插件、预设

// tailwind.config.jsmodule.exports = {  // 内容  content: ['./src/**/*.{html,js}'],  // 主题  theme: {    // 屏幕    screens: {      sm: '480px',      md: '768px',      lg: '976px',      xl: '1440px',    },    // 颜色    colors: {      'blue': '#1fb6ff',      'purple': '#7e5bef',      'pink': '#ff49db',      'orange': '#ff7849',      'green': '#13ce66',      'yellow': '#ffc82c',      'gray-dark': '#273444',      'gray': '#8492a6',      'gray-light': '#d3dce6',    },    // 间距    spacing: {      '1': '8px',      '2': '12px',      '3': '16px',      '4': '24px',      '5': '32px',      '6': '48px',    },    fontFamily: {      sans: ['Graphik', 'sans-serif'],      serif: ['Merriweather', 'serif'],    },    extend: {      // 扩展默认间距比例      spacing: {        '13': '3.25rem',        '15': '3.75rem',        '128': '32rem',        '144': '36rem',      },      borderRadius: {        '4xl': '2rem',      }    }  },    /*      使用可重用的第三方插件扩展 Tailwind。插件允许为 Tailwind 注册新样式    */    plugins: [        require('@tailwindcss/line-clamp'),    ],}

4、原理

从TaiWindCss实践的使用场景上来看,我们以 PostCSS 插件的形式安装TaiWindCss,本质上讲TaiWindCss是一个postCss的插件。 对于PostCSS的插件使用,我们在使用的过程中一般都需要如下步骤:

  • PostCSS 配置文件 postcss.config.js,新增 tailwindcss 插件。
  • TaiWindCss插件需要一份配置文件,比如:tailwind.config.js。
  • 项目 引入的 less,sass,css 文件中注入 @tailwind 标识,并引入 base,components,utilities,是否全部引入取决你自己。

使用postcss做处理器

// `postcss-import`:用于处理 PostCSS 的规范插件npm install postcss-import// postcss.config.js// 然后把它作为 PostCSS 配置中的第一个插件:exportdefault {  plugins: {      tailwindcss: {},      autoprefixer: {},  },}

了解什么是postcss

通俗的讲法:postCss 就是一个开发工具,是一个用 JavaScript 工具和插件转换 CSS 代码的工具。支持变量,混入,未来 CSS 语法,内联图像等等。

特性与常见的功能:

  • 增强代码的可读性:
  • 将未来的 CSS 特性带到今天
  • 避免 CSS 代码中的错误
  • 可以作为预处理器使用

postCss的核心原理/工作流

PostCSS 包括 CSS 解析器,CSS 节点树 API,一个源映射生成器和一个节点树 stringifier。

PostCSS 主要的原理核心工作流:

  • 通过 fs 读取CSS文件
  • 通过 parser 将CSS解析成抽象语法树(AST树)
  • 将AST树”传递”给任意数量的插件处理
  • 诸多插件进行数据处理。插件间传递的数据就是AST树
  • 通过 stringifier 将处理完毕的AST树重新转换成字符串

image.png

  • 将CSS解析成抽象语法树(AST树)
  • 将AST树”传递”给任意数量的插件处理
  • 将处理完毕的AST树重新转换成字符串

在PostCSS中有几个关键的处理机制:(详细看postcss文档)

Source string → Tokenizer(分词器) → Parser(解析器) → AST → Processor (处理器)→ Stringifier(弦化器)->new css

tailwindcss工作流

image.png

基本的步骤:

  • 将CSS解析成抽象语法树(AST树)
  • 读取插件配置,根据配置文件,生成新的抽象语法树
  • 将AST树”传递”给一系列数据转换操作处理(变量数据循环生成,切套类名循环等)
  • 清除一系列操作留下的数据痕迹
  • 将处理完毕的AST树重新转换成字符串

tailwindcss 大多作为 postcss plugin 来使用的,它源码里自己实现了一个文件读取机制(也就是 tailwind.config.js 中的 content 配置项 ),来对我们编写的代码进行提取。

// 转换前@layer components{  @variants responsive{    .container{      width: 100%    }  }}
// 转换后{  "raws": {    "semicolon": false,    "after": "\n\n"  },  "type": "root",  "nodes": [    {      "raws": {        "before": "",        "between": "",        "afterName": " ",        "semicolon": false,        "after": "\n"      },      "type": "atrule",      "name": "layer",      "source": {        "start": {          "line": 1,          "column": 1        },        "input": {          "css": "@layer components{\n  @variants responsive{\n    .container{\n      width: 100%\n    }\n  }\n}\n\n",          "hasBOM": false,          "id": "<input css 17>"        },        "end": {          "line": 7,          "column": 1        }      },      "params": "components",      "nodes": [        {          "raws": {            "before": "\n  ",            "between": "",            "afterName": " ",            "semicolon": false,            "after": "\n  "          },          "type": "atrule",          "name": "variants",          "source": {            "start": {              "line": 2,              "column": 3            },            "input": {              "css": "@layer components{\n  @variants responsive{\n    .container{\n      width: 100%\n    }\n  }\n}\n\n",              "hasBOM": false,              "id": "<input css 17>"            },            "end": {              "line": 6,              "column": 3            }          },          "params": "responsive",          "nodes": [            {              "raws": {                "before": "\n    ",                "between": "",                "semicolon": false,                "after": "\n    "              },              "type": "rule",              "nodes": [                {                  "raws": {                    "before": "\n      ",                    "between": ": "                  },                  "type": "decl",                  "source": {                    "start": {                      "line": 4,                      "column": 7                    },                    "input": {                      "css": "@layer components{\n  @variants responsive{\n    .container{\n      width: 100%\n    }\n  }\n}\n\n",                      "hasBOM": false,                      "id": "<input css 17>"                    },                    "end": {                      "line": 4,                      "column": 17                    }                  },                  "prop": "width",                  "value": "100%"                }              ],              "source": {                "start": {                  "line": 3,                  "column": 5                },                "input": {                  "css": "@layer components{\n  @variants responsive{\n    .container{\n      width: 100%\n    }\n  }\n}\n\n",                  "hasBOM": false,                  "id": "<input css 17>"                },                "end": {                  "line": 5,                  "column": 5                }              },              "selector": ".container"            }          ]        }      ]    }  ],  "source": {    "input": {      "css": "@layer components{\n  @variants responsive{\n    .container{\n      width: 100%\n    }\n  }\n}\n\n",      "hasBOM": false,      "id": "<input css 17>"    },    "start": {      "line": 1,      "column": 1    }  }}

image.png

5、问题

问题1、为什么不直接使用内联样式呢?

  • 有约束的设计。使用内联样式,每个值都是一个神奇的数字。使用实用程序,可以从预定义的设计系统中选择样式,这使得构建视觉上一致的 UI 变得更加容易。
  • 响应式设计。不能在内联样式中使用媒体查询,但可以使用 Tailwind 的响应式实用程序轻松构建完全响应式界面。
  • 悬停、焦点等状态。内联样式无法针对悬停或焦点等状态,但 Tailwind 的状态变体可以轻松地使用实用程序类来设置这些状态的样式

问题2、与bootstrap的区别

许多人会想到 CSS 框架,有很多,例如 Bootstrap、Bulma 和 Material UI。Bootstrap 和 Bulma 等框架利用预先准备好的组件(例如按钮、菜单和面包屑)进行设计。在 Tailwind CSS 中,没有准备任何组件,而是使用Utilize Class来创建设计自己的组件。 原来Bootstrap等框架可以通过提前准备组件集合来高效地设计网站,但是有一个缺点,就是因为使用了相同的设计,所以没有原创性。相比之下,Tailwind CSS 没有组件集合,所以即使你创建一个名为相同按钮的组件,每个人都会应用不同的Utilize Class创建它,可以创建出一个高度原创的网站。

两者都有优点和缺点,所以使用哪一个取决于个人,但使用 Tailwind CSS 的人数正在稳步增加

什么是Utilize Class?

例如,如果要使用 Bootstrap 创建按钮,请将class设置为btn 。但是,在 Tailwind 中,并没有 btn 等用于创建按钮的class,你可以通过编写如下所示的Utilize Class来创建按钮。你可能会觉得要设置的类太多了,但是学习成本很低,因为你一用就习惯了。如果不知道类名,可以通过搜索 Tailwind CSS 文档轻松找到它

<button class="bg-indigo-700 font-semibold text-white py-2 px-4 rounded">Utilize Class</button><!-- bg-indigo-700 设置颜色,font-semibold 设置字体粗细,text-white 设置文本颜色,py-2 设置左右填充,px 设置上下填充,rounded 设置圆角。-->

问题3、这跟在项目中直接写好全局的类名然后直接使用,有什么区别呢?

demo说明:tailwindcss/test

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>Document</title>    <link rel="stylesheet" href="/dist/output.css"></head><body>    <div>        <h1 class="flex text-3xl font-bold underline text-blue-600">            Hello world!        </h1>    </div></body></html>

在demo中,我只是用了flex text-3xl font-bold underline text-blue-600,这几个类名,打包之后发现,css文件当中除了基础样式,就只有这几个类对应样式:

其实我们在搭建tailwind的项目过程中就可以发现,tailwind存在于JIT引擎(Just-In-Time),就是在编译过程才去扫描我们的html文件,在这个过程中去识别使用了哪些类名,然后才生成对应的样式。 相比于预先直接全局写好大量的类名,JIT机制的优点在于精简紧凑,样式所占用的空间较小,因为用到了才会生成。

// 启用JIT模式/** @type {import('tailwindcss').Config} */module.exports = {  mode: 'JIT',  /**  * 由于 JIT 模式通过扫描模板文件按需生成 CSS,因此在 tailwind.config.js   * 文件中使用所有模板路径配置 purge 选项至关重要  * 启动开发服务器或构建运行器时,Tailwind 将按需生成您的样式,而不是预先生成所有内容。  */  purge: [    "public/**/*.html",    "src/pages/**/*.{js,jsx,ts,tsx,vue}"  ],  theme: {    extend: {},  },  plugins: [],}

问题4、与其他UI组件同时引用时,可能会出现样式冲突

// 注释掉 @tailwind base 样式// tailwind.css/* @tailwind base;@tailwind components;@tailwind utilities; */// 关闭默认样式// tailwind.config.js...exportconstcorePlugins = {	  preflight: false}...

下载preflight.css,手动导入,解决冲突。

6、总结

优点

  • 默认样式好看
  • 响应式系统更灵活
  • 主题可配置
  • 工具链完善
  • 开发效率高(配合VSCode插件)

应用场景

  • 偏展示型的网站(企业官网,产品官网,币圈各种官网等等)

适用人群

最后

为啥这个 css 框架叫 tailwind 呢? 因为作者 Adam Wathan喜欢叫做 kiteboarding 风筝冲浪的运动。 就是这样的,一个风筝,一个冲浪板:

这种运动在顺风 tailwind 和逆风 headwind 下有不同的技巧。而 tailwind 的时候明显更加省力。 所以就给这个 css 框架起名叫 tailwind 了,借用其省力的意思。

作者介绍

贺燕珍:

  • 一个有两个孩子的妈妈。
  • 喜欢跑步、爬山和听音乐,这些活动可以帮助我释放压力。
  • 对自由的渴望驱使着我不断追求个人发展和成长。
  • 享受探索新技术和构建用户友好的界面的过程。
  • 希望我能努力保持积极的心态,以充满热情和创造力的方式工作。


来源:微信公众号:58本地服务终端技术

出处
:https://mp.weixin.qq.com/s/y9ZIJX_FxgeTRUi695-eDw