CSS trong TypeScript với vanilla-extract

Nút nguồn: 1121024

tinh dầu vanilla là một thư viện CSS-in-TypeScript mới của khuôn khổ-bất khả tri. Đó là một cách nhẹ, mạnh mẽ và trực quan để viết các kiểu của bạn. vanilla-extract không phải là một khuôn khổ CSS bắt buộc, mà là một phần linh hoạt của công cụ dành cho nhà phát triển. Công cụ CSS đã là một không gian tương đối ổn định trong vài năm qua với đăngCSS, Sass, Mô-đun CSSthành phần theo kiểu tất cả đều ra mắt trước năm 2017 (một số lâu trước đó) và họ vẫn phổ biến hôm nay. Gió cùng chiều là một trong số ít công cụ đã làm chấn động mọi thứ trong lĩnh vực công cụ CSS trong vài năm qua.

vanilla-extract nhằm mục đích làm rung chuyển mọi thứ trở lại. Nó được phát hành trong năm nay và có lợi ích là có thể tận dụng một số xu hướng gần đây, bao gồm:

  • Các nhà phát triển JavaScript chuyển sang TypeScript
  • Hỗ trợ trình duyệt cho các thuộc tính tùy chỉnh CSS
  • Kiểu dáng ưu tiên tiện ích

Có rất nhiều cải tiến thông minh trong chiết xuất vani mà tôi nghĩ nó sẽ trở thành một vấn đề lớn.

Thời gian chạy bằng không

Các thư viện CSS-in-JS thường đưa các kiểu vào tài liệu trong thời gian chạy. Điều này có những lợi ích, bao gồm CSS quan trọng chiết xuất và tạo kiểu động.

Nhưng theo nguyên tắc chung, một tệp CSS riêng biệt sẽ hoạt động hiệu quả hơn. Đó là bởi vì mã JavaScript cần trải qua quá trình phân tích / biên dịch tốn kém hơn, trong khi một tệp CSS riêng biệt có thể được lưu vào bộ nhớ cache trong khi giao thức HTTP2 giảm chi phí của yêu cầu bổ sung. Cũng, Thuộc tính tùy chỉnh hiện có thể cung cấp nhiều kiểu dáng động miễn phí.

Vì vậy, thay vì tiêm các kiểu trong thời gian chạy, chiết xuất vani sẽ sau Linarialướt sóng. Các thư viện này cho phép bạn tạo kiểu bằng cách sử dụng các hàm JavaScript được tách ra tại thời điểm xây dựng và được sử dụng để tạo tệp CSS. Mặc dù bạn viết vanilla-extract trong TypeScript, nó không ảnh hưởng đến kích thước tổng thể của gói JavaScript sản xuất của bạn.

TypeScript

Một đề xuất giá trị chiết xuất vani lớn là bạn phải nhập. Nếu điều đó đủ quan trọng để giữ an toàn cho phần còn lại của kiểu cơ sở mã của bạn, thì tại sao không làm như vậy với các kiểu của bạn?

TypeScript cung cấp một số lợi ích. Đầu tiên, có tính năng tự động hoàn thành. Nếu bạn nhập “fo” thì trong trình chỉnh sửa thân thiện với TypeScript, bạn sẽ nhận được danh sách các tùy chọn phông chữ trong trình đơn thả xuống - fontFamily, fontKerning, fontWeight, hoặc bất kỳ thứ gì khác phù hợp - để lựa chọn. Điều này làm cho các thuộc tính CSS có thể được khám phá thoải mái từ trình chỉnh sửa của bạn. Nếu bạn không thể nhớ tên của fontVariant nhưng hãy biết rằng nó sẽ bắt đầu với từ “phông chữ” bạn nhập nó và cuộn qua các tùy chọn. Trong VS Code, bạn không cần tải xuống bất kỳ công cụ bổ sung nào để thực hiện điều này.

Điều này thực sự tăng tốc độ tạo các style:

Điều đó cũng có nghĩa là biên tập viên của bạn đang trông chừng bạn để đảm bảo rằng bạn không mắc bất kỳ lỗi chính tả nào có thể gây ra lỗi khó chịu.

Các loại chiết xuất vani cũng cung cấp giải thích về cú pháp trong định nghĩa loại của chúng một liên kết đến Tài liệu MDN cho thuộc tính CSS mà bạn đang chỉnh sửa. Điều này loại bỏ một bước điên cuồng trên Google khi các kiểu hoạt động không mong muốn.

Hình ảnh của VSCode với con trỏ di chuột qua thuộc tính fontKerning và cửa sổ bật lên mô tả những gì thuộc tính này thực hiện với liên kết đến tài liệu Mozilla cho thuộc tính

Viết bằng TypeScript có nghĩa là bạn đang sử dụng tên lạc đà cho các thuộc tính CSS, như backgroundColor. Đây có thể là một chút thay đổi đối với các nhà phát triển được sử dụng cú pháp CSS thông thường, như background-color.

Tích hợp

vani-extract cung cấp các tích hợp hạng nhất cho tất cả các gói mới nhất. Đây là danh sách đầy đủ tích hợp nó hiện hỗ trợ:

  • gói web
  • xây dựng
  • Sống
  • Lớp băng tuyết
  • Tiếp theoJS
  • Gatsby

Nó cũng hoàn toàn bất khả tri theo khuôn khổ. Tất cả những gì bạn cần làm là nhập tên lớp từ vanilla-Extract, được chuyển đổi thành một chuỗi tại thời điểm xây dựng.

Sử dụng

Để sử dụng vanilla-Extract, bạn viết một .css.ts tệp mà các thành phần của bạn có thể nhập. Các lệnh gọi đến các hàm này được chuyển đổi thành các chuỗi tên lớp được băm và có phạm vi trong bước xây dựng. Điều này nghe có vẻ tương tự như Mô-đun CSS, và đây không phải là ngẫu nhiên: người tạo ra vani-Extract, Mark Dalgleish, cũng là đồng sáng tạo của Mô-đun CSS.

style()

Bạn có thể tạo một lớp CSS có phạm vi tự động bằng cách sử dụng style() hàm số. Bạn chuyển kiểu của phần tử, sau đó xuất giá trị trả về. Nhập giá trị này vào đâu đó trong mã người dùng của bạn và nó được chuyển đổi thành tên lớp trong phạm vi.

// title.css.ts
import {style} from "@vanilla-extract/css"; export const titleStyle = style({ backgroundColor: "hsl(210deg,30%,90%)", fontFamily: "helvetica, Sans-Serif", color: "hsl(210deg,60%,25%)", padding: 30, borderRadius: 20,
});
// title.ts
import {titleStyle} from "./title.css"; document.getElementById("root").innerHTML = `<h1 class="${titleStyle}">Vanilla Extract</h1>`;

Truy vấn phương tiện và bộ chọn giả cũng có thể được bao gồm bên trong khai báo kiểu:

// title.css.ts
backgroundColor: "hsl(210deg,30%,90%)",
fontFamily: "helvetica, Sans-Serif",
color: "hsl(210deg,60%,25%)",
padding: 30,
borderRadius: 20, "@media": { "screen and (max-width: 700px)": { padding: 10 }
}, ":hover":{ backgroundColor: "hsl(210deg,70%,80%)"
}

Kia là style các lệnh gọi hàm là một sự trừu tượng nhỏ so với CSS - tất cả các tên và giá trị thuộc tính đều ánh xạ đến các thuộc tính và giá trị CSS mà bạn quen thuộc. Một thay đổi để làm quen là các giá trị đôi khi có thể được khai báo dưới dạng số (ví dụ: padding: 30) được mặc định là giá trị đơn vị pixel, trong khi một số giá trị cần được khai báo dưới dạng chuỗi (ví dụ: padding: "10px 20px 15px 15px").

Các thuộc tính bên trong hàm kiểu chỉ có thể ảnh hưởng đến một nút HTML duy nhất. Điều này có nghĩa là bạn không thể sử dụng lồng để khai báo các kiểu cho phần tử con - điều mà bạn có thể quen với Sass or đăngCSS. Thay vào đó, bạn cần tạo kiểu riêng cho trẻ. Nếu một phần tử con cần các kiểu khác nhau dựa trên cha mẹ, bạn có thể sử dụng selectors thuộc tính để thêm các kiểu phụ thuộc vào cấp độ gốc:

// title.css.ts
export const innerSpan = style({ selectors:{[`${titleStyle} &`]:{ color: "hsl(190deg,90%,25%)", fontStyle: "italic", textDecoration: "underline" }}
});
// title.ts
import {titleStyle,innerSpan} from "./title.css";
document.getElementById("root").innerHTML = `<h1 class="${titleStyle}">Vanilla <span class="${innerSpan}">Extract</span></h1>
<span class="${innerSpan}">Unstyled</span>`;

Hoặc bạn cũng có thể sử dụng API Theming (mà chúng ta sẽ nói đến phần tiếp theo) để tạo các thuộc tính tùy chỉnh trong phần tử mẹ được sử dụng bởi các nút con. Điều này nghe có vẻ hạn chế, nhưng nó được cố ý làm theo cách này để tăng khả năng bảo trì trong các cơ sở mã lớn hơn. Nó có nghĩa là bạn sẽ biết chính xác nơi các kiểu đã được khai báo cho mỗi phần tử trong dự án của bạn.

Chủ đề

Bạn có thể sử dụng createTheme hàm để xây dựng các biến trong một đối tượng TypeScript:

// title.css.ts
import {style,createTheme } from "@vanilla-extract/css"; // Creating the theme
export const [mainTheme,vars] = createTheme({ color:{ text: "hsl(210deg,60%,25%)", background: "hsl(210deg,30%,90%)" }, lengths:{ mediumGap: "30px" }
}) // Using the theme
export const titleStyle = style({ backgroundColor:vars.color.background, color: vars.color.text, fontFamily: "helvetica, Sans-Serif", padding: vars.lengths.mediumGap, borderRadius: 20,
});

Sau đó, chiết xuất vani cho phép bạn tạo một biến thể của chủ đề của mình. TypeScript giúp nó đảm bảo rằng biến thể của bạn sử dụng tất cả các tên thuộc tính giống nhau, vì vậy bạn sẽ nhận được cảnh báo nếu bạn quên thêm background thuộc tính của chủ đề.

Hình ảnh của VS Code trong đó hiển thị một chủ đề đang được khai báo nhưng thiếu thuộc tính nền gây ra một lượng lớn các đường nguệch ngoạc màu đỏ để cảnh báo rằng thuộc tính đã bị lãng quên

Đây là cách bạn có thể tạo chủ đề thông thường và chế độ tối:

// title.css.ts
import {style,createTheme } from "@vanilla-extract/css"; export const [mainTheme,vars] = createTheme({ color:{ text: "hsl(210deg,60%,25%)", background: "hsl(210deg,30%,90%)" }, lengths:{ mediumGap: "30px" }
})
// Theme variant - note this part does not use the array syntax
export const darkMode = createTheme(vars,{ color:{ text:"hsl(210deg,60%,80%)", background: "hsl(210deg,30%,7%)", }, lengths:{ mediumGap: "30px" }
})
// Consuming the theme export const titleStyle = style({ backgroundColor: vars.color.background, color: vars.color.text, fontFamily: "helvetica, Sans-Serif", padding: vars.lengths.mediumGap, borderRadius: 20,
});

Sau đó, bằng cách sử dụng JavaScript, bạn có thể áp dụng động các tên lớp được trả về bởi vanilla-extract để chuyển đổi các chủ đề:

// title.ts
import {titleStyle,mainTheme,darkMode} from "./title.css"; document.getElementById("root").innerHTML = `<div class="${mainTheme}" id="wrapper"> <h1 class="${titleStyle}">Vanilla Extract</h1> <button onClick="document.getElementById('wrapper').className='${darkMode}'">Dark mode</button>
</div>`

Làm thế nào để điều này hoạt động dưới mui xe? Các đối tượng bạn khai báo trong createTheme hàm được chuyển thành các thuộc tính tùy chỉnh CSS được gắn vào lớp của phần tử. Các thuộc tính tùy chỉnh này được băm để tránh xung đột. CSS đầu ra cho mainTheme ví dụ trông như thế này:

.src__ohrzop0 { --color-brand__ohrzop1: hsl(210deg,80%,25%); --color-text__ohrzop2: hsl(210deg,60%,25%); --color-background__ohrzop3: hsl(210deg,30%,90%); --lengths-mediumGap__ohrzop4: 30px;
}

Và đầu ra CSS của darkMode chủ đề trông như thế này:

.src__ohrzop5 { --color-brand__ohrzop1: hsl(210deg,80%,60%); --color-text__ohrzop2: hsl(210deg,60%,80%); --color-background__ohrzop3: hsl(210deg,30%,10%); --lengths-mediumGap__ohrzop4: 30px;
}

Vì vậy, tất cả những gì chúng ta cần thay đổi trong mã người dùng của mình là tên lớp. Áp dụng darkmode tên lớp cho phần tử mẹ và mainTheme thuộc tính tùy chỉnh được hoán đổi cho darkMode những cái.

API công thức nấu ăn

Sản phẩm stylecreateTheme các chức năng cung cấp đủ sức mạnh để tự tạo kiểu cho một trang web, nhưng vanilla-extract cung cấp thêm một số API để thúc đẩy khả năng tái sử dụng. API Recipes cho phép bạn tạo một loạt các biến thể cho một phần tử mà bạn có thể chọn trong mã đánh dấu hoặc mã người dùng của mình.

Đầu tiên, nó cần được cài đặt riêng:

npm install @vanilla-extract/recipes

Đây là cách nó hoạt động. Bạn nhập recipe hàm và truyền vào một đối tượng với các thuộc tính basevariants:

// button.css.ts
import { recipe } from '@vanilla-extract/recipes'; export const buttonStyles = recipe({ base:{ // Styles that get applied to ALL buttons go in here }, variants:{ // Styles that we choose from go in here }
});

Inside base, bạn có thể khai báo các kiểu sẽ được áp dụng cho tất cả các các biến thể. Bên trong variants, bạn có thể cung cấp các cách khác nhau để tùy chỉnh phần tử:

// button.css.ts
import { recipe } from '@vanilla-extract/recipes';
export const buttonStyles = recipe({ base: { fontWeight: "bold", }, variants: { color: { normal: { backgroundColor: "hsl(210deg,30%,90%)", }, callToAction: { backgroundColor: "hsl(210deg,80%,65%)", }, }, size: { large: { padding: 30, }, medium: { padding: 15, }, }, },
});

Sau đó, bạn có thể khai báo biến thể bạn muốn sử dụng trong đánh dấu:

// button.ts
import { buttonStyles } from "./button.css"; <button class=`${buttonStyles({color: "normal",size: "medium",})}`>Click me</button>

Và chiết xuất vani thúc đẩy TypeScript cung cấp tính năng tự động hoàn thành cho của riêng bạn tên biến thể!

Bạn có thể đặt tên cho các biến thể của mình bất kỳ thứ gì bạn thích và đặt bất kỳ thuộc tính nào bạn muốn vào chúng, như sau:

// button.css.ts
export const buttonStyles = recipe({ variants: { animal: { dog: { backgroundImage: 'url("./dog.png")', }, cat: { backgroundImage: 'url("./cat.png")', }, rabbit: { backgroundImage: 'url("./rabbit.png")', }, }, },
});

Bạn có thể thấy điều này sẽ cực kỳ hữu ích như thế nào để xây dựng một hệ thống thiết kế, vì bạn có thể tạo các thành phần có thể tái sử dụng và kiểm soát chúng theo cách khác nhau. Các biến thể này trở nên dễ dàng phát hiện với TypeScript - tất cả những gì bạn cần nhập là CMD/CTRL + Space (trên hầu hết các trình chỉnh sửa) và bạn sẽ nhận được danh sách thả xuống các cách khác nhau để tùy chỉnh thành phần của mình.

Tiện ích ưu tiên với Sprinkles

Sprinkles là một khuôn khổ tiện ích đầu tiên được xây dựng dựa trên chiết xuất vani. Đây là cách tài liệu về chiết xuất vani miêu tả nó:

Về cơ bản, nó giống như xây dựng phiên bản không thời gian chạy, an toàn kiểu của riêng bạn Gió cùng chiều, Hệ thống kiểu dáng, Vv

Vì vậy, nếu bạn không phải là người thích đặt tên cho mọi thứ (tất cả chúng ta đều gặp ác mộng khi tạo ra một outer-wrapper div sau đó nhận ra rằng chúng ta cần phải bọc nó bằng một. . . outer-outer-wrapper ) Rắc có thể là cách ưa thích của bạn để sử dụng chiết xuất vani.

API Sprinkles cũng cần được cài đặt riêng:

npm install @vanilla-extract/sprinkles

Bây giờ chúng ta có thể tạo một số khối xây dựng cho các chức năng tiện ích của chúng ta để sử dụng. Hãy tạo một danh sách màu sắc và độ dài bằng cách khai báo một vài đối tượng. Các tên khóa JavaScript có thể là bất cứ thứ gì chúng ta muốn. Các giá trị sẽ cần phải là giá trị CSS hợp lệ cho các thuộc tính CSS mà chúng tôi định sử dụng chúng cho:

// sprinkles.css.ts
const colors = { blue100: "hsl(210deg,70%,15%)", blue200: "hsl(210deg,60%,25%)", blue300: "hsl(210deg,55%,35%)", blue400: "hsl(210deg,50%,45%)", blue500: "hsl(210deg,45%,55%)", blue600: "hsl(210deg,50%,65%)", blue700: "hsl(207deg,55%,75%)", blue800: "hsl(205deg,60%,80%)", blue900: "hsl(203deg,70%,85%)",
}; const lengths = { small: "4px", medium: "8px", large: "16px", humungous: "64px"
};

Chúng ta có thể khai báo các thuộc tính CSS nào mà các giá trị này sẽ áp dụng bằng cách sử dụng defineProperties chức năng:

  • Chuyển nó một đối tượng với một properties bất động sản.
  • In properties, chúng tôi khai báo một đối tượng trong đó phím là các thuộc tính CSS mà người dùng có thể đặt (những thuộc tính này cần phải là các thuộc tính CSS hợp lệ) và giá trị là những đối tượng chúng tôi đã tạo trước đó (danh sách của chúng tôi về colorslengths).
// sprinkles.css.ts
import { defineProperties } from "@vanilla-extract/sprinkles"; const colors = { blue100: "hsl(210deg,70%,15%)" // etc.
} const lengths = { small: "4px", // etc.
} const properties = defineProperties({ properties: { // The keys of this object need to be valid CSS properties // The values are the options we provide the user color: colors, backgroundColor: colors, padding: lengths, },
});

Sau đó, bước cuối cùng là chuyển giá trị trả về của defineProperties đến createSprinkles và xuất giá trị trả về:

// sprinkles.css.ts
import { defineProperties, createSprinkles } from "@vanilla-extract/sprinkles"; const colors = { blue100: "hsl(210deg,70%,15%)" // etc.
} const lengths = { small: "4px", // etc. } const properties = defineProperties({ properties: { color: colors, // etc. },
});
export const sprinkles = createSprinkles(properties);

Sau đó, chúng ta có thể bắt đầu tạo kiểu bên trong nội tuyến các thành phần của mình bằng cách gọi sprinkles trong thuộc tính lớp và chọn các tùy chọn mà chúng ta muốn cho mỗi phần tử.

// index.ts
import { sprinkles } from "./sprinkles.css";
document.getElementById("root").innerHTML = `<button class="${sprinkles({ color: "blue200", backgroundColor: "blue800", padding: "large",
})}">Click me</button>
</div>`;

Đầu ra JavaScript chứa một chuỗi tên lớp cho mỗi thuộc tính kiểu. Các tên lớp này khớp với một quy tắc duy nhất trong tệp CSS đầu ra.

<button class="src_color_blue200__ohrzop1 src_backgroundColor_blue800__ohrzopg src_padding_large__ohrzopk">Click me</button>

Như bạn có thể thấy, API này cho phép bạn tạo kiểu cho các phần tử bên trong đánh dấu của mình bằng cách sử dụng một tập hợp các ràng buộc được xác định trước. Bạn cũng tránh được nhiệm vụ khó khăn khi tìm ra tên của các lớp cho mọi phần tử. Kết quả là một cái gì đó giống như Tailwind, nhưng cũng được hưởng lợi từ tất cả cơ sở hạ tầng đã được xây dựng xung quanh TypeScript.

API Sprinkles cũng cho phép bạn viết điều kiệnsở đoản để tạo kiểu đáp ứng bằng cách sử dụng các lớp tiện ích.

Kết thúc

vanilla-extract giống như một bước tiến lớn mới trong công cụ CSS. Rất nhiều suy nghĩ đã được đưa ra để xây dựng nó thành một giải pháp trực quan, mạnh mẽ để tạo kiểu sử dụng tất cả sức mạnh mà tính năng nhập tĩnh mang lại.

Đọc thêm

Nguồn: https://css-tricks.com/css-in-typescript-with-vanilla-extract/

Dấu thời gian:

Thêm từ Thủ thuật CSS