Styling
Styles are plain CSS in a css template.
import { define, html, css } from '@alacris/core';
define('x-card', { styles: css` :host { display: block; border: 1px solid #ddd; border-radius: 8px } h3 { margin: 0 } `, setup: () => html`<h3><slot name="title"></slot></h3><slot></slot>`,});Parsed once for the whole page
Section titled “Parsed once for the whole page”css interns by text: identical CSS always returns the same constructed
stylesheet. Two components sharing a reset share the parse, and adopting a sheet
into a shadow root is a pointer copy, not a parse.
const reset = css`*, ::before, ::after { box-sizing: border-box }`;
define('x-a', { styles: [reset, css`:host { display: block }`], setup });define('x-b', { styles: [reset, css`:host { display: flex }`], setup });// `reset` is parsed once, and both components adopt the same objectA thousand elements of the same component cost one parse and a thousand pointer copies.
Composition
Section titled “Composition”Interpolating one sheet into another inlines its text, so stylesheets compose without anything being parsed twice:
const tokens = css`:host { --gap: .75rem }`;const base = css`${tokens} :host { display: grid; gap: var(--gap) }`;styles accepts a sheet, a raw CSS string, a CSSStyleSheet, or an array of
any of those, applied in order:
styles: [reset, tokens, css`:host { color: red }`]Dynamic values belong in custom properties
Section titled “Dynamic values belong in custom properties”Do not rebuild a stylesheet to change a colour. Bind a custom property instead — one property write, no CSS re-parse, and the browser does the rest:
html`<div style=${() => ({ '--bar-fill': pct() + '%', opacity: fade() })}>`.bar { width: var(--bar-fill) }style accepts an object with custom properties included, and clears any key
you stop passing. class accepts objects and arrays:
html`<button class=${() => ({ btn: true, 'btn--on': active() })}>`Reskinning without re-adopting
Section titled “Reskinning without re-adopting”A sheet can be rewritten in place. Every element that adopted it updates on a single write — no re-adoption, no new rules, no re-render:
const skin = css`:host { --tone: #111 }`;
skin.replace(':host { --tone: #eee }'); // every instance, immediatelyThat is the cheapest possible theme switch.
Style the element itself:
:host { display: block }:host([disabled]) { opacity: .5 }:host(.compact) { padding: .25rem }:host only matches from inside the component. Note that a bare tag selector
in the page beats it, which is usually what you want — see
theming.
Slotted content
Section titled “Slotted content”Content passed in from the page stays in the light DOM. Reach it with
::slotted(), which matches only top-level slotted elements:
::slotted(p) { margin: 0 }::slotted(.tag) { font-size: .85rem }Light DOM
Section titled “Light DOM”With shadow: false there is nothing to encapsulate — your page’s CSS applies
normally, and styles are added to the containing document once rather than per
element.
The one rule
Section titled “The one rule”- Theming for consumers — the harder half: letting other people restyle what you built
- Alacris UI — a token system and
applyThemebuilt onvars()