Writing CSS for a panel
A panel is drawn from computed style, so most of a page's CSS works in the scene as it is. This page is the short list of what to rely on, what to prefer, and what a panel leaves out. Every line of it is stated exactly, with the reasons, in What a panel draws and DOM panels in the reference.
What is drawn
A box is drawn from its background colour, a gradient, a border width per side and one border colour, border-radius, opacity, visibility, transform and overflow, in the page's paint order. An outline is a ring around the box, outline-offset from its border edge, drawn over everything else in the box's layer as a page draws it. A box-shadow is drawn, outer and inset, up to four layers of it. Text is rasterized once as a mask and coloured by its material, so animating color re-draws nothing. An <img> is a picture on the same box, with object-fit and object-position. A <li> has its marker. A checkbox is a box with a tick in it, in the element's color; a text field is a box with its value in it. Inline <svg> is drawn when the scene installs the svgElements() plugin from justdom-three/svg, from the shapes' computed style, so a class on a <path> and fill: currentColor work. A colour can be written in any CSS colour space, oklch(), lab() and color(display-p3 …) among them, and one outside sRGB is clipped to it.
What to prefer
Move things with
transform. Atransformis a matrix write with no re-layout and no re-rasterized text, as on the flat web.translateZis the one that moves toward the viewer; a panel laid flat has its y axis along the surface it lies on.Animate
transform,opacityand colours. They are the cheap tier: a style read and a matrix or material write per element. A layout property such asheightorfont-sizere-measures the panel every frame. It works, so save it for moments.Hover and press change colour, not size. The attributes the portal writes,
data-xr-hover,data-xr-active,data-xr-checkedanddata-xr-focus, are declared unable to move anything, which is what keeps a hover to one element's restyle. A width or a padding under one of them is not mirrored. A page's:hover,:activeand:focusrules answer them as written, since the portal rewrites each to name its attribute too (Hover, press and focus):css.button:hover { transform: translateZ(4px) scale(1.04); /* fine: a matrix write */ padding: 12px; /* ignored: this is layout */ }Start every rule from a class. A
<style>whose rules all start from a class restyles only the panels that class can reach when it changes, which is whatclassNameandstylesheetfromjustdom-corewrite. A rule from a tag, an attribute or:rootrestyles every panel on the page.Give images a size. An
<img>given no size takes the picture's when it arrives, and the panel re-measures.Prefer percentage stops in a gradient on anything that resizes: a
pxstop bakes a new gradient row at every size.Write
cursor: pointeron anything a ray should press, as a page does for anything clickable. It is the rule that makes an element a ray target.Turn off Safari's text autosizing with
html { -webkit-text-size-adjust: none; }in the page's own stylesheet, not in anythingstylesheetorclassNamewrites, on a page laid out wider than a phone's screen. Safari on an iPhone lays the text of such a block out bigger than its computedfont-size, which is the size a panel draws, so the glyphs no longer fit the lines they were measured on and a revealed run is cut in the wrong places.
Overlays
An element that is positioned and stacked above, position other than static with a positive z-index, is an overlay: a layer of its own, lifted 10 px in front of its parent's content so that stereo reads it as floating, and opaque to rays, so a ray landing between two menu rows does not press a button behind the menu. Overlays stack by nesting, not by how big the number is. Keep an overlay within the silhouette of its panel where you can, since a panel placed in front of it hides whatever hangs outside.
.menu {
position: absolute;
z-index: 1;
top: 100%;
}Clipping and scrolling
An element that hides its overflow clips what is inside it, corners included, and trims ray hits the same way, so a button scrolled out of sight cannot be pressed. Scrolling is the ordinary scrollTop write and costs no re-layout. A list is pulled by hand the moment it overflows, and scrollable(props) from justdom-three-ui adds the arrows and the thumb for a scrollbar's kind of control.
What is left out
The things a page does that a panel does not, most often met:
- All but the topmost gradient and the topmost
url()picture of stacked backgrounds. A box with a picture is drawn on its own rather than in its panel's batch. background-clip; the background fills the padding box.- Dashed, dotted and double borders and outlines, drawn solid, and sides bordered in different colours, drawn in the first side's.
- The outline and the
box-shadowof a box drawn on its own: an<img>, and a box with aurl()picture. - A shadow falling on a box at its own draw level, as a later flow sibling's does on a page.
- A
::beforeor::afterpositioned against a box other than its own element, or given az-index, and the counters and quotes in acontent. - A
text-shadowpast its first layer. The first is drawn, baked into the text's texture, and that text re-draws per colour change. :has(),:nth-last-child(), and a sibling combinator ondata-xr-hover,data-xr-activeordata-xr-focus.- A native
<select>, a<textarea>'s value, every<input>type but checkboxes and the text kinds, and the system keyboard.justdom-three-uihas the dropdown and the keyboard. - Text selection; a field has a caret only.
- In SVG: a gradient or a pattern on text, masks, filters,
<foreignObject>, and aclip-pathof any shape but a single<rect>. - A change made through the CSSOM,
insertRuleor the developer tools, unless theming mode is on.
The reference ends each section with its own "Not followed" list, which is the exact statement.