The box every effect of Axiom draws on: it owns the shape, the tilt and the frame scheduler.
A surface is the box that every visual effect of Axiom Design System draws on. Wrap your element with ax-surface, pick the layers you need in the layers attribute, and shape it with custom properties: corners, edge features, border and tilt. Your content is always on top of the layers.
The Playground (/playground) has every property and many ready-made shapes. Underneath, Shape computes the outline and Typed OM reads the custom properties. This page shows the properties one idea at a time.
Shape properties are not inherited, so set them on the ax-surface element itself. Surfaces only work while they are visible and read their styles only after something changed.
Installation
npm install @ax-design/surfaceand import it:
import { register } from '@ax-design/surface';
register();If you don't use a bundler, load the script instead:
<script src="https://unpkg.com/@ax-design/surface/build/main.js"></script>
<script>AxSurface.register();</script>Corners
The radius sets every corner. Percentages are relative to the shorter side, and like border-radius, radii that do not fit are scaled down.
The corner shape has the same keywords as the CSS corner-shape property: round, bevel, scoop and notch. Bevel, scoop and notch corners meet the sides in sharp points; the shoulder radius rounds those points.
Try it
<ax-surface class="shape" layers="fill">...</ax-surface>.shape {
--ax-radius: 30%;
--ax-corner-shape: scoop;
--ax-corner-shoulder-radius: 0px;
}Moved corners
Every corner can have its own radius, shape and shoulder radius, for example --ax-top-left-radius and --ax-corner-top-left-shape. A corner that sets nothing uses the general value.
A corner can also move into the shape. Positive shifts move the corner toward the middle of the shape: shift the top left and the bottom right corners on x and you get a trapezoid or a parallelogram, depending on the two values. Percentages are relative to the width for x and to the height for y. Negative values move the corner out of the box.
Try it
.shape {
--ax-corner-top-left-shift-x: 20%;
--ax-corner-bottom-right-shift-x: 20%;
--ax-top-right-radius: 0px;
}Edge features
Each side can carry a feature: a bump or a notch. The kind is arc (circular), rect, triangle, trapezoid or cusp. Cusp is two arcs that meet in a point: pointing in it pinches the side, pointing out it makes a pointed arch.
Depth is how far the feature goes: positive values go out of the shape, negative values go into it. Span is its width along the side. At is where its middle sits; sides run clockwise, so the top goes from left to right. This example uses the top side.
Try it
.shape {
--ax-edge-top-kind: arc;
--ax-edge-top-depth: -20px;
--ax-edge-top-span: 40%;
--ax-edge-top-at: 50%;
}All sides at once
The --ax-edge-* properties without a side set the feature of all four sides. A side that sets its own value, like --ax-edge-top-depth, wins over them.
Sides run clockwise, so the same --ax-edge-at on every side turns each feature the same way around the shape. The result has rotational symmetry, not mirror symmetry. The tip radius rounds the point of a cusp.
Try it
.shape {
--ax-radius: 30%;
--ax-edge-kind: cusp;
--ax-edge-depth: -8px;
--ax-edge-span: 100%;
--ax-edge-tip-radius: 20px;
/* A side can still go its own way. */
--ax-edge-top-depth: -12px;
}Border, fill and tilt
The fill layer paints the inside of the shape with --ax-fill-color and the border with --ax-border-color. The border is as wide on every side as --ax-border-width says, or per side with --ax-border-top-width and its siblings.
Set --ax-tilt-mode and the surface tilts toward the point you press. Absolute sinks the pressed side by the tilt depth, relative tilts it by a number of degrees. The border keeps the same width on screen while the surface tilts. Press the shape to try it.
Try it
.shape {
--ax-fill-color: rgba(255, 255, 255, 0.14);
--ax-border-color: white;
--ax-border-width: 2px;
--ax-tilt-mode: absolute;
--ax-tilt-depth: 3px; /* absolute */
--ax-tilt-factor: 8; /* relative, in degrees */
}Layers together
The layers attribute lists what the surface draws, in order. Your content is on top of all of them. Fill comes with Surface, the others come from their packages: elevation (a shadow that follows the shape), reveal and acrylic.
Put elevation first, so the other layers paint on top of it. Pick a list below. The background of this preview is an image, so the acrylic has something to blur.
Try it
import { register } from '@ax-design/surface';
import { registerAcrylicLayer } from '@ax-design/acrylic';
import { registerElevationLayer } from '@ax-design/elevation';
import { registerRevealLayer } from '@ax-design/reveal-highlight';
registerAcrylicLayer();
registerElevationLayer();
registerRevealLayer();
register();<ax-surface class="shape" layers="acrylic reveal">...</ax-surface>.shape {
--elevation-depth: 16;
}
Clip
Add the clip attribute and the content of the surface is cut to its shape, so an image or a video fills a tile of any shape. The cut follows the shape when it changes, and tilts with the content when the surface is pressed.
Without clip the content keeps its own box, and the shape only draws around it.
Try it
<ax-surface class="tile" clip layers="reveal">
<img src="cover.jpg" alt="" style="display: block; width: 100%; height: 100%; object-fit: cover">
</ax-surface>.tile {
width: 220px;
height: 220px;
--ax-radius: 24%;
--ax-corner-shape: scoop;
}Reference
layers attribute
space separated names
The layers the surface draws, in order: fill, reveal, acrylic, elevation or one you registered.
clip attribute
boolean, default off
Cuts the content to the shape. The cut follows the shape and the tilt.
observe attribute
precise
Use it when a style of yours depends on something a surface cannot see, such as an element inside another component's shadow root.
--ax-radius property
<length-percentage>, default 0px
The radius of every corner. Percentages are relative to the shorter side.
--ax-{corner}-radius property
<length-percentage>, default -1px
The radius of one corner (top-left, top-right, bottom-right, bottom-left). A negative value means use --ax-radius.
--ax-corner-shape property
round | bevel | scoop | notch, default round
The shape of every corner.
--ax-corner-{corner}-shape property
round | bevel | scoop | notch | auto, default auto
The shape of one corner. auto means use --ax-corner-shape.
--ax-corner-shoulder-radius property
<length>, default 0px
Rounds the two points where a bevel, scoop or notch corner meets the sides. Round corners ignore it.
--ax-corner-{corner}-shoulder-radius property
<length>, default 0px
The shoulder radius of one corner. Wins over the general property.
--ax-corner-{corner}-shift-x property
<length-percentage>, default 0px
Moves one corner point along x. Percentages are relative to the width. Negative values move it out of the box.
--ax-corner-{corner}-shift-y property
<length-percentage>, default 0px
Moves one corner point along y. Percentages are relative to the height.
--ax-edge-{side}-kind property
flat | arc | rect | triangle | trapezoid | cusp, default flat
The feature on one side (top, right, bottom, left). Arc is a circular bump or notch, cusp is two arcs that meet in a point.
--ax-edge-{side}-depth property
<length>, default 0px
How far the feature goes. Positive values go out of the shape, negative values go into it.
--ax-edge-{side}-span property
<length-percentage>, default 33%
The width of the feature along the side. Percentages are relative to the length of the side.
--ax-edge-{side}-at property
<length-percentage>, default 50%
Where the middle of the feature sits. Sides run clockwise: top left to right, right top to bottom, bottom right to left, left bottom to top.
--ax-edge-{side}-ratio property
<number>, default 0.5
For trapezoid only: the width of the far end compared to the base. 1 gives a rectangle, 0 a triangle.
--ax-edge-{side}-tip-radius property
<length>, default 0px
Rounds the far corners of the feature, or the point of a cusp.
--ax-edge-{side}-shoulder-radius property
<length>, default 0px
Rounds the corners where the feature meets the side.
--ax-edge-kind, --ax-edge-depth, --ax-edge-span, --ax-edge-at, --ax-edge-ratio, --ax-edge-tip-radius, --ax-edge-shoulder-radius property
as the side properties
The feature of all four sides at once. Each is the default of the side property with the same name; a side that sets its own value wins.
--ax-border-width property
<length>, default 1px
The width of the border on every side. It stays equally thick on screen while the surface tilts.
--ax-border-{side}-width property
<length>, default -1px
The width of the border on one side. A negative value means use --ax-border-width.
--ax-tilt-mode property
off | absolute | relative, default off
Tilts the surface toward the point you press. Inherited.
--ax-tilt-depth property
<length>, default 1px
For absolute mode: how far the pressed side sinks.
--ax-tilt-factor property
<number>, default 2
For relative mode: the angle in degrees.
--ax-tilt-zoom property
<length>, default 0.8px
How far the whole surface falls when you press its center.
--ax-tilt-perspective property
<length>, default 25px
The perspective of the tilt.
--ax-tilt-direction property
normal | inverted, default normal
Inverted lifts the pressed side instead of sinking it.
--ax-fill-color property
<color>, default transparent
For the fill layer: the color inside the shape.
--ax-border-color property
<color>, default transparent
For the fill layer: the color of the border.
refresh() method
() => void
Reads the styles of this surface again. Use it after a change the surface cannot notice.
refreshAll() method
() => void
Reads the styles of every surface again. Exported by the package.
release() method
() => void
Ends a press before the pointer is up, for containers that take the gesture over (a tile drag). Since 0.2.1.
registerLayer(name, create) method
(name: string, create: () => Layer) => void
Registers a layer you wrote, to use in the layers attribute.