差點錯過的 Tailwindcss 入門學習筆記
tags: CSS tailwindcss 2024
本篇主要只記載一些我個人覺得比較特殊需要筆記的內容~並不是整份文件喔!
Start
Install
$ npm install -D tailwindcss postcss autoprefixer
$ npx tailwindcss init [--ts|--esm]
Configure
// for TS
import type { Config } from 'tailwindcss'
export default {
content: [
'./index.html',
'./src/**/*.{vue,js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {},
},
plugins: [],
} satisfies Config
// postcss.config
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
// use with preprocessor
module.exports = {
plugins: {
'postcss-import': {},
'tailwindcss/nesting': {},
tailwindcss: {},
autoprefixer: {},
},
}
Import
/* global.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
/* entrypoint of your js file */
import './global.css'
Core Concepts
States
Pseudo-classes
hover,active,focusfirst,last,odd,evenfocus,disabled,invalid,checkedhas,group-has-*,peer-has-*group,group-hover...peer,peer-invalid...
<li class="first:pt-0 last:pb-0"></li>
<label class="has-[:checked]:bg-indigo-50 has-[:checked]:text-indigo-900 has-[:checked]:ring-indigo-200 ..">
Google Pay
<input type="radio" class="checked:border-indigo-500 ..." />
</label>
<!-- 可以藉由 group 搭配 group-has-* 做到,當同 group 內達成特定條件後套用樣式 -->
<div class="group ...">
<img src="..." />
<h4>Spencer Sharp</h4>
<div class="hidden group-has-[a]:block ...">
<img src="my-icon.svg" />
</div>
<p>Product Designer at <a href="...">planeteria.tech</a></p>
</div>
Pseudo-elements
Media queries
md,lg...darkmotion-reduce,motion-safeportrait,landscapeprint
Responsive Design
| Breakpoint prefix | Minimum width |
|---|---|
sm | 640px |
md | 768px |
lg | 1024px |
xl | 1280px |
2xl | 1536px |
Dark Mode
By default this uses the prefers-color-scheme CSS media feature, but you can also build sites that support toggling dark mode manually using the class strategy.
module.exports = {
darkMode: 'class',
// ...
}
<!-- Dark mode not enabled -->
<html>
<body>
<!-- Will be white -->
<div class="bg-white dark:bg-black">
<!-- ... -->
</div>
</body>
</html>
<!-- Dark mode enabled -->
<html class="dark">
<body>
<!-- Will be black -->
<div class="bg-white dark:bg-black">
<!-- ... -->
</div>
</body>
</html>
Reusing Styles
Extracting classes with @apply
<!-- Before extracting a custom class -->
<button class="py-2 px-4 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75">
Save changes
</button>
<!-- After extracting a custom class -->
<button class="btn-primary">
Save changes
</button>
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
.btn-primary {
@apply py-2 px-4 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75;
}
}
@layer utilities {
.content-auto {
content-visibility: auto;
}
}
CSS Variable without var()
<!-- old -->
<div class="bg-[var(--brand-color)] hover:bg-[var(--brand-hover-color)]"><div>
<!-- now -->
<div class="bg-[--brand-color] hover:bg-[--brand-hover-color]"></div>
Custom Styles
Using arbitrary values
<div class="bg-[#bada55] text-[22px] before:content-['Festivus']">
<!-- ... -->
</div>
<div class="bg-[url('/what_a_rush.png')]">
<!-- ... -->
</div>
<!-- white space -->
<div class="grid grid-cols-[1fr_500px_2fr]">
<!-- ... -->
</div>
What is Layer?
base: for things like reset rules or default styles applied to plain HTML elements.components: for class-based styles that you want to be able to override with utilities.utilities: for small, single-purpose classes that should always take precedence over any other styles.
Removing unused custom CSS
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
/* This won't be included in your compiled CSS unless you actually use it */
.card {
/* ... */
}
}
/* This will always be included in your compiled CSS */
.card {
/* ... */
}
In under-the-hood, frameworks like Vue and Svelte are processing every single
<style>block independently, and running your PostCSS plugin chain against each one in isolation. That means if you have 10 components that each have a<style>block, Tailwind is being run 10 separate times, and each run has zero knowledge about the other runs. Because of this, Tailwind can’t take the styles you define in a@layerand move them to the corresponding@tailwinddirective
Functions & Directives
Directives
@tailwind@layer@apply
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
h1 {
@apply text-2xl;
}
h2 {
@apply text-xl;
}
}
@layer components {
.btn-blue {
@apply bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded;
}
}
@layer utilities {
.filter-none {
filter: none;
}
.filter-grayscale {
filter: grayscale(100%);
}
}
Any rules inlined with @apply will have !important removed by default to avoid specificity issues:
/* Input */
.foo {
color: blue !important;
}
.bar {
@apply foo;
}
/* Output */
.foo {
color: blue !important;
}
.bar {
color: blue;
}
Functions
theme,screen
/* use dot in number */
.content-area {
height: calc(100vh - theme('spacing[2.5]'));
}
.btn-blue {
background-color: theme('colors.blue.500');
}
@media screen(sm) {
/* ... */
}
/* equal to */
@media (min-width: 640px) {
/* ... */
}
如果我們一邊在用 sass 又需要使用 screen 這種功能的話,可以像下面這樣結合 sass mixin 處理
@mixin rwd($size) {
@media (min-width: theme("screens.#{$size}")) {
@content;
}
}
// 這樣我們就可以在 nested 結構下使用 tailwind 的變數了
h1 {
@include rwd(sm) {
color: red;
}
}
