慣性聚合 高效追讀感興趣之博客、新聞、科技資訊
閱原文 以慣性聚合開啟

推薦訂閱源

博客园 - 司徒正美
V
V2EX
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
aimingoo的专栏
aimingoo的专栏
Apple Machine Learning Research
Apple Machine Learning Research
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
月光博客
月光博客
T
The Blog of Author Tim Ferriss
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python)
构 mini Tailwind-to-CSS 转换器——效用类名如何映射至真 CSS
SEN LLC · 2026-05-24 · via DEV Community

Tailwind乃"仅CSS耳。"然则何哉?确然岂非bg-blue-500 text-white px-6 py-3 rounded-lg font-bold shadow-md决意乎?吾撰五百行之纯范JavaScript转换器,取Tailwind类字符串,印其等价CSS,兼有实时预览。此程实为Tailwind设计之明训,胜于阅其文牍。

寰宇示范https://sen.ltd/portfolio/tw-to-css/
包裹GitHubJHSNS_URL_0

Screenshot

为何筑此?

二因:

  1. 多"Tailwind教程"未显其成之CSS。读者习类名,乃依纹摹,非悟其各一之用。。左右并列之视,使地图可见。
  2. 。自为之,乃学Tailwind之设计最速之道。。既书bg-{color}-{shade}为应之器,乃知Tailwind之感何其一贯——同形者,遍于诸用之族。

此器非Tailwind之重施也。乃百用之小宗,盖取教程与速启所常用者。志在明其对应,非欲运生产之地也.

架构

tailwind-data.js  ← Lookup tables: colour palette, spacing scale, font sizes, …
parser.js         ← Tokenizer + handler array (no DOM, Node-testable)
app.js            ← UI glue: input → parser → live preview + CSS output

入全屏模式 出全屏模式

parser.js导出parse(input),其返{ rules, unrecognised }。全流为纯——node --test不启浏览器,行四十三案而未尝辍。

處理器之列 — 加一工具 = 加一功能

每個 Tailwind 之用是其一條。HANDLERS数组也。解析器依序试之;首非空者胜。

const HANDLERS = [
  // exact-match utilities
  layoutHandler("flex",     [["display", "flex"]]),
  layoutHandler("flex-col", [["flex-direction", "column"]]),
  layoutHandler("hidden",   [["display", "none"]]),

  // prefix utilities driven by a callback
  prefixHandler("bg-", (v) => {
    const hex = resolveColor(v);
    return hex ? [["background-color", hex]] : null;
  }),
  prefixHandler("text-", (v) => {
    if (v in FONT_SIZE)   { const [s, l] = FONT_SIZE[v]; return [["font-size", s], ["line-height", l]]; }
    if (["left","center","right","justify"].includes(v)) return [["text-align", v]];
    const hex = resolveColor(v);
    return hex ? [["color", hex]] : null;
  }),

  // spacing utilities share one helper because they all key into SPACING_MAP
  spacingHandler("p",  "padding"),
  spacingHandler("px", ["padding-left", "padding-right"]),
  spacingHandler("py", ["padding-top",  "padding-bottom"]),
  spacingHandler("w",  "width"),
  spacingHandler("h",  "height"),
  // ...
];

入全景模式 出全屏模式

此形乃Tailwind之所以通贯一气之由也。器名者,前缀加之,尺度之钥也。,其制一也0, 0.5, 1, 2, 4, 8, …数字遍于四方。施行之,则迫尔内化焉。

类名重载(其)text-问题)

text-此乃 Tailwind 中最繁冗之前缀也:

何所立也
text-sm 字體大小加行高
text-center 左对齐
text-blue-500

一愚解器择其一而破其余。其真应之则次第遣之。

prefixHandler("text-", (v) => {
  // 1. font-size scale first (sm, md, lg, xl, 2xl, 3xl, ...)
  if (v in FONT_SIZE) {
    const [size, lh] = FONT_SIZE[v];
    return [["font-size", size], ["line-height", lh]];
  }
  // 2. text alignment keywords
  if (["left","center","right","justify"].includes(v)) {
    return [["text-align", v]];
  }
  // 3. fall through to colour resolution
  const hex = resolveColor(v);
  return hex ? [["color", hex]] : null;
});

入全景模式 出全屏模式

次第为要,非率尔而为之也——Tailwind其自身亦能解析之text-{x}依此序,故text-sm恒胜于一假设之色名smtext-blue-500屬於同色之範疇,蓋因blue-500之形制不協FONT_SIZE之鍵。

此理亦適用於border-(色與寬之別),以及其他若干。

间距之標度,僅僅是n * 0.25rem

const SPACING_BASE = [
  0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 11, 12,
  14, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 96,
];
for (const n of SPACING_BASE) {
  SPACING_MAP[String(n)] = n === 0 ? "0px" : `${n * 0.25}rem`;
}
SPACING_MAP["px"] = "1px";
SPACING_MAP["auto"] = "auto";
SPACING_MAP["full"] = "100%";

退出全屏模式

此即整個間距之體系。p-4是也padding: 1rem.mt-8是。margin-top: 2remgap-2是。gap: 0.5rem君所内化于 Tailwind 之 8px 网格直觉者0.25rem * 2 = 0.5rem ≈ 8px at default 16px root font— 于此矣。

方向快捷键(pxpymxmy此乃一言以蔽之也。

function spacingHandler(prefix, cssProp) {
  return (cls) => {
    if (!cls.startsWith(`${prefix}-`)) return null;
    const v = cls.slice(prefix.length + 1);
    if (!(v in SPACING_MAP)) return null;
    const props = Array.isArray(cssProp) ? cssProp : [cssProp];
    return props.map((p) => [p, SPACING_MAP[v]]);
  };
}

// usage:
spacingHandler("px", ["padding-left", "padding-right"]);

入全景模式 出全屏模式

胜者为王

parse("bg-red-500 bg-blue-500")
// → { rules: [
//     { class: "bg-red-500",  declarations: [["background-color", "#ef4444"]] },
//     { class: "bg-blue-500", declarations: [["background-color", "#3b82f6"]] },
//   ] }

入全景模式 出全屏模式

二则皆得存,然toCSS()坍然聚为一块,待其后胜者。

export function toCSS(rules, selector = ".preview") {
  const seen = new Map();
  for (const r of rules) {
    for (const [prop, value] of r.declarations) {
      seen.set(prop, value);  // overwrites earlier value for same prop
    }
  }
  // ...
}

入全景模式 出全屏模式

此合乎 Tailwind 之直觉,谓"于某属性,所书之末班胜"。于 Tailwind 之实,此以 CSS 源序及 JIT 编译为之——然于静态班列,Map.set越规有序,等也。

(真Tailwind则更为精妙)@layer系统之组件与实用优先,然于单类列表内,其规一也。)

测不可见者

故也parser.js纯粹无杂,每项效用皆可单元测试。

test("text-blue-500", () => {
  assert.deepEqual(classToDeclarations("text-blue-500"),
    [["color", "#3b82f6"]]);
});

test("h-screen → 100vh", () => {
  assert.deepEqual(classToDeclarations("h-screen"),
    [["height", "100vh"]]);
});

test("w-screen → 100vw, NOT 100vh", () => {
  assert.deepEqual(classToDeclarations("w-screen"),
    [["width", "100vw"]]);
});

test("invalid class returns null", () => {
  assert.equal(classToDeclarations("not-a-real-class"), null);
});

入全景模式 出全屏模式

四十三试,覆词化,每用器族,其text-命发之序,不配之径,及CSS之呈。所谓"横屏与纵屏之试"者,实为真之守卫——早于实施之际,吾曾书之100vh二者皆非,宽之谬也。

未施之事(及其故)

  • 变体(hover:md:dark:此需生成媒体查询/伪类包装器。非"名→值"演示范围。
  • 任意之值(p-[17px]bg-[#abcdef] — 易增,然所求者标准之主题,非Tailwind之重施也。
  • 插件 / 专属之主题 — 理由同前。

若欲此等,则处理器数组之构架为当之选:每一者皆仅增处理器(或为变体而绕现有者)。

试之

将汝项目之真实Tailwind类粘贴于此,观其CSS。若某物解析为空预览,则属"未识"之列,汝将知其故.

启示

  • Tailwind大抵为一五十行之查表也者,默认主题之色彩谱系、明暗层次、间距标度、字体大小、字重也。其余乃命名之范式。
  • bg-{color}-{shade}者,前缀加键,入二维之表。者,施之则设计之域昭然。
  • text-者,意有所指而重载之。者,大小、对齐、色彩三者互竞。序次派遣(先大小,次对齐,终色彩)则歧义自消。
  • 胜者为王独列一单,则表折矣Map.set依序通览解析之规——无需玩弄具体之巧。
  • 使解析器无DOM之累,则node --test遍覆诸用支。

此乃SEN LLC(东京)之开源组合第241号。吾辈持续递送精微利器:https://sen.ltd/portfolio/