CSS i TypeScript med vaniljeekstrakt

Kilde node: 1121024

vaniljeekstrakt er et nytt rammeverk-agnostisk CSS-in-TypeScript-bibliotek. Det er en lett, robust og intuitiv måte å skrive stilene dine på. vaniljeekstrakt er ikke et preskriptivt CSS-rammeverk, men et fleksibelt verktøy for utvikler. CSS-verktøy har vært en relativt stabil plass de siste årene med PostCSS, sass, CSS-modulerog stylede komponenter alle kommer ut før 2017 (noen lenge før det) og de forbli populær i dag. Tailwind er et av få verktøy som har rystet opp ting i CSS-verktøy de siste årene.

vaniljeekstrakt har som mål å riste opp igjen. Den ble utgitt i år og har fordelen av å kunne utnytte noen nyere trender, inkludert:

  • JavaScript-utviklere bytter til TypeScript
  • Nettleserstøtte for egendefinerte CSS-egenskaper
  • Utility-first styling

Det er en hel haug med smarte innovasjoner innen vaniljeekstrakt som jeg tror gjør det til en stor sak.

Null kjøretid

CSS-i-JS-biblioteker injiserer vanligvis stiler i dokumentet under kjøring. Dette har fordeler, bl.a kritisk CSS uttrekk og dynamisk styling.

Men som en generell tommelfingerregel, en egen CSS-fil kommer til å gi mer ytelse. Det er fordi JavaScript-kode må gå gjennom dyrere parsing/kompilering, mens en separat CSS-fil kan bufres mens HTTP2-protokollen reduserer kostnadene for den ekstra forespørselen. Også, egendefinerte egenskaper kan nå tilby mye dynamisk styling gratis.

Så i stedet for å injisere stiler under kjøring, tar vaniljeekstrakt etter Linaria og astroturf. Disse bibliotekene lar deg forfatte stiler ved å bruke JavaScript-funksjoner som blir revet ut ved byggetid og brukt til å konstruere en CSS-fil. Selv om du skriver vaniljeekstrakt i TypeScript, påvirker det ikke den totale størrelsen på JavaScript-produksjonspakken.

Loggfila

Et stort verdiforslag med vaniljeekstrakt er at du får skriving. Hvis det er viktig nok til å holde resten av kodebasen din typesikker, hvorfor ikke gjøre det samme med stilene dine?

TypeScript gir en rekke fordeler. For det første er det autofullføring. Hvis du skriver "fo", får du i en TypeScript-vennlig editor en liste over skriftalternativer i en rullegardin - fontFamily, fontKerning, fontWeight, eller hva annet som passer - å velge mellom. Dette gjør CSS-egenskaper synlige fra redaktøren din. Hvis du ikke husker navnet på fontVariant men vet at det kommer til å starte med ordet "font" du skriver det og bla gjennom alternativene. I VS Code trenger du ikke å laste ned noe ekstra verktøy for å få dette til.

Dette setter virkelig fart på utformingen av stiler:

Det betyr også at redaktøren din følger deg over skulderen for å forsikre deg om at du ikke gjør noen stavefeil som kan forårsake frustrerende feil.

vaniljeekstrakttyper gir også en forklaring på syntaksen i typedefinisjonen og en lenke til MDN -dokumentasjon for CSS-egenskapen du redigerer. Dette fjerner et trinn med febrilsk Googling når stiler oppfører seg uventet.

Bilde av VSCode med markøren over fontKerning-egenskapen og et popup-vindu som beskriver hva egenskapen gjør med en lenke til Mozilla-dokumentasjonen for eiendommen

Å skrive i TypeScript betyr at du bruker camel-case-navn for CSS-egenskaper, som backgroundColor. Dette kan være litt av en endring for utviklere som bruker vanlig CSS-syntaks, som background-color.

integrasjoner

vaniljeekstrakt gir førsteklasses integrasjoner for alle de nyeste bunterne. Her er en fullstendig liste over integrasjoner den støtter for øyeblikket:

  • Webpack
  • esbuild
  • Bor
  • Snødekket
  • NesteJS
  • Gatsby

Det er også fullstendig ramme-agnostisk. Alt du trenger å gjøre er å importere klassenavn fra vanilje-ekstrakt, som blir konvertert til en streng ved byggetid.

bruk

For å bruke vaniljeekstrakt skriver du opp en .css.ts fil som komponentene dine kan importere. Anrop til disse funksjonene blir konvertert til hashet og omfangsbestemt klassenavnstrenger i byggetrinnet. Dette kan høres ut som CSS-moduler, og dette er ikke tilfeldig: skaperen av vaniljeekstrakt, Mark Dalgleish, er også medskaper av CSS-moduler.

style()

Du kan opprette en CSS-klasse med automatisk omfang ved å bruke style() funksjon. Du sender inn elementets stiler, og eksporterer deretter den returnerte verdien. Importer denne verdien et sted i brukerkoden din, og den konverteres til et klassenavn med omfang.

// 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>`;

Mediespørringer og pseudovelgere kan også inkluderes i stilerklæringer:

// 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%)"
}

Disse style funksjonskall er en tynn abstraksjon over CSS - alle egenskapsnavnene og -verdiene tilordnes CSS-egenskapene og -verdiene du er kjent med. En endring å venne seg til er at verdier noen ganger kan deklareres som et tall (f.eks padding: 30) som er standard til en pikselenhetsverdi, mens noen verdier må deklareres som en streng (f.eks. padding: "10px 20px 15px 15px").

Egenskapene som går inn i stilfunksjonen kan bare påvirke en enkelt HTML-node. Dette betyr at du ikke kan bruke nesting til å deklarere stiler for barna til et element – ​​noe du kanskje er vant til i sass or PostCSS. I stedet må du style barn separat. Hvis et barneelement trenger forskjellige stiler basert på forelderen kan du bruke selectors egenskap for å legge til stiler som er avhengige av overordnet:

// 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>`;

Eller du kan også bruke Theming API (som vi kommer til neste gang) for å lage egendefinerte egenskaper i det overordnede elementet som forbrukes av undernodene. Dette kan høres restriktivt ut, men det er med vilje blitt overlatt på denne måten for å øke vedlikeholdsevnen i større kodebaser. Det betyr at du vet nøyaktig hvor stilene er deklarert for hvert element i prosjektet ditt.

Tema

Du kan også bruke det createTheme funksjon for å bygge ut variabler i et TypeScript-objekt:

// 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,
});

Da lar vaniljeekstrakt deg lage en variant av temaet ditt. TypeScript hjelper det å sikre at varianten din bruker alle de samme egenskapsnavnene, slik at du får en advarsel hvis du glemmer å legge til background eiendom til temaet.

Bilde av VS-kode der viser et tema som blir erklært, men mangler bakgrunnsegenskapen, noe som forårsaker en stor mengde røde snirklete linjer som advarer om at eiendommen er glemt

Slik kan du lage et vanlig tema og en mørk modus:

// 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,
});

Deretter, ved å bruke JavaScript, kan du dynamisk bruke klassenavnene som returneres av vaniljeekstrakt for å bytte tema:

// 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>`

Hvordan fungerer dette under panseret? Gjenstandene du deklarerer i createTheme funksjonen gjøres om til egendefinerte CSS-egenskaper knyttet til elementets klasse. Disse egendefinerte egenskapene hashes for å forhindre konflikter. Utdata-CSS for vår mainTheme eksempel ser slik ut:

.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;
}

Og CSS-utgangen til vår darkMode tema ser slik ut:

.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;
}

Så alt vi trenger å endre i brukerkoden vår er klassenavnet. Bruk darkmode klassenavnet til det overordnede elementet, og mainTheme tilpassede egenskaper blir byttet ut med darkMode seg.

Oppskrifter API

De style og createTheme funksjoner gir nok kraft til å style et nettsted på egen hånd, men vaniljeekstrakt gir noen ekstra APIer for å fremme gjenbrukbarhet. Recipes API lar deg lage en haug med varianter for et element, som du kan velge mellom i markeringen eller brukerkoden.

Først må den installeres separat:

npm install @vanilla-extract/recipes

Slik fungerer det. Du importerer recipe funksjon og pass inn et objekt med egenskapene base og variants:

// 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 }
});

Innsiden base, kan du deklarere stilene som skal brukes på alle varianter. Innsiden variants, kan du tilby forskjellige måter å tilpasse elementet på:

// 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, }, }, },
});

Deretter kan du deklarere hvilken variant du vil bruke i markeringen:

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

Og vaniljeekstrakt utnytter TypeScript som gir autofullføring for ditt eget variantnavn!

Du kan navngi variantene dine hva du vil, og legge de egenskapene du vil ha i dem, slik:

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

Du kan se hvordan dette ville være utrolig nyttig for å bygge et designsystem, siden du kan lage gjenbrukbare komponenter og kontrollere måten de varierer. Disse variantene blir lett synlige med TypeScript - alt du trenger å skrive er CMD/CTRL + Space (på de fleste redaktører), og du får en rullegardinliste over de forskjellige måtene å tilpasse komponenten din på.

Nytte først med sprinkles

Sprinkles er et nytte-første rammeverk bygget på toppen av vaniljeekstrakt. Dette er hvordan vaniljeekstrakten dokumenterer Beskriv det:

I bunn og grunn er det som å bygge din egen null-runtime, typesikker versjon av Tailwind, Stylet systemOsv

Så hvis du ikke er en fan av å navngi ting (vi har alle mareritt om å lage en outer-wrapper div innser så at vi må pakke den inn med en . . . outer-outer-wrapper ) Sprinkles kan være din foretrukne måte å bruke vaniljeekstrakt på.

Sprinkles API må også installeres separat:

npm install @vanilla-extract/sprinkles

Nå kan vi lage noen byggeklosser som våre hjelpefunksjoner kan bruke. La oss lage en liste over farger og lengder ved å deklarere et par objekter. JavaScript-nøkkelnavnene kan være hva vi vil. Verdiene må være gyldige CSS-verdier for CSS-egenskapene vi planlegger å bruke dem til:

// 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"
};

Vi kan erklære hvilke CSS-egenskaper disse verdiene skal gjelde for ved å bruke defineProperties funksjon:

  • Gi den en gjenstand med en properties eiendom.
  • In properties, erklærer vi et objekt der nøkler er CSS-egenskapene brukeren kan angi (disse må være gyldige CSS-egenskaper) og verdier er objektene vi opprettet tidligere (våre lister over colors og lengths).
// 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, },
});

Deretter er det siste trinnet å passere returverdien på defineProperties til createSprinkles funksjon, og eksporter den returnerte verdien:

// 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);

Deretter kan vi begynne å style inne i komponentene våre inline ved å ringe til sprinkles funksjon i klasseattributtet og velge hvilke alternativer vi ønsker for hvert element.

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

JavaScript-utdata inneholder en klassenavnstreng for hver stilegenskap. Disse klassenavnene samsvarer med en enkelt regel i utdata-CSS-filen.

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

Som du kan se, lar denne API-en deg style elementer i markeringen din ved å bruke et sett med forhåndsdefinerte begrensninger. Du slipper også den vanskelige oppgaven med å komme opp med navn på klasser for hvert element. Resultatet er noe som føles mye som Tailwind, men som også drar nytte av all infrastrukturen som er bygget rundt TypeScript.

Sprinkles API lar deg også skrive forhold og stenografi å lage responsive stiler ved hjelp av verktøyklasser.

Innpakning opp

vaniljeekstrakt føles som et stort nytt skritt i CSS-verktøy. Det er lagt mye vekt på å bygge den inn i en intuitiv, robust løsning for styling som utnytter all kraften statisk skriving gir.

Videre lesing

Kilde: https://css-tricks.com/css-in-typescript-with-vanilla-extract/

Tidstempel:

Mer fra CSS triks