Loading...
With CSS Typed OM we can easily define property values such as CSS.px(5)
, but properties don't only have values.
The CSS Properties & Values API in the browser allows users to customize CSS properties and configure their types for checks, default values, whether inheritance is supported, and other metadata, which is also part of CSS Houdini.
For example, the following shows how to customize a color property.
window.CSS.registerProperty({name: '--my-color',syntax: '<color>',inherits: false,initialValue: '#c0ffee',});
We have also implemented this API in G, defining a set of built-in property value types.
CSS property values contain various types: https://drafts.csswg.org/css-values-4/
In G we support the following types.
unset
center
red
transparent
linear-gradient
%
px
em
rem
deg
rad
turn
In some scenarios, these types can be combined, e.g. <length-percentage> is a combination of <length> and <percentage>.
Corresponds to CSSKeywordValue in CSS Typed OM.
For example, 'normal'
will be parsed as
text.style.fontWeight = 'normal';const styleMap = text.computedStyleMap();styleMap.get('fontWeight'); // CSSKeywordValue { value: 'normal' }
As with CSS, the global keywords are as follows.
It can be used to reset inherited properties.
For example, in the following example, <em>
should have inherited the color
attribute defined by <p>
, but it overrides the inherited value by applying the default value (black) via initial
.
p {color: red;}em {color: initial;}<p><span>This text is red.</span><em>This text is in the initial color (typically black).</em><span>This is red again.</span></p>
https://developer.mozilla.org/en-US/docs/Web/CSS/initial
https://developer.mozilla.org/en-US/docs/Web/CSS/inherit
https://developer.mozilla.org/en-US/docs/Web/CSS/unset
Corresponds to CSSUnitValue in CSS Typed OM.
Property values that currently use this type include.
circle.style.opacity = '0.5';const styleMap = circle.computedStyleMap();styleMap.get('opacity'); // CSSUnitValue { unit:'', value: 0.5 }
The length type is used to define distances, which in turn include absolute and relative types.
https://drafts.csswg.org/css-values-4/#length-value
Pixels are obviously an absolute unit, and if a length value uses number
the default unit is px
. It is then resolved to CSS.px()
.
circle.style.r = 10;// orcircle.style.r = '10px';const styleMap = circle.computedStyleMap();styleMap.get('r'); // CSSUnitValue { unit: 'px', value: 10 }
Represents the font-size of the root element. When used within the root element font-size, it represents its initial value (a common browser default is 16px, but user-defined preferences may modify this).
Represents the calculated font-size of the element. If used on the font-size property itself, it represents the inherited font-size of the element.
https://drafts.csswg.org/css-values-4/#percentage-value
https://drafts.csswg.org/css-values-4/#angle-value
Represents an angle in degrees. One full circle is 360deg. Examples: 0deg, 90deg, 14.23deg.
Represents an angle in gradians. One full circle is 400grad. Examples: 0grad, 100grad, 38.8grad.
Represents an angle in radians. One full circle is 2π radians which approximates to 6.2832rad. 1rad is 180/π degrees. Examples: 0rad, 1.0708rad, 6.2832rad.
Represents an angle in a number of turns. One full circle is 1turn. Examples: 0turn, 0.25turn, 1.2turn.
Referring to the CSS specification definition of the type <color>, we support the following color value types, which exist as string
types in JS.
It is a type included in <paint>.
Properties that would currently use this type are.
CSS defines a series of basic color keywords that are case sensitive. The image below left shows the basic color keywords, and the image below right shows some of the extended keywords.
In the internal implementation, we will pass the keyword string to d3-color to parse it and get CSSRGB.
Example usage is as follows.
circle.style.fill = 'red';circle.style.fill = 'darkcyan';
Defined in the sRGB color space and supports hexadecimal writing.
Usage examples are as follows.
circle.style.fill = '#f00';circle.style.fill = '#ff0000';circle.style.fill = 'rgb(255,0,0)';circle.style.fill = 'rgb(100%, 0%, 0%)';
Adds a transparency channel to rgb
. According to specification, alpha
takes values in the range [0, 1]
.
Usage examples are as follows.
circle.style.fill = 'rgb(255,0,0)';circle.style.fill = 'rgba(255,0,0,1)';circle.style.fill = 'rgba(100%,0%,0%,1)';
Equivalent to rgba(0,0,0,0)
i.e. completely transparent black.
Note that it has a different meaning than none
supported by <paint>.
https://www.w3.org/TR/css-color-3/#currentcolor
Equivalent to black in the Canvas / WebGL rendering environment, and the same name property effect in SVG.
Referring to <paint> in SVG, it is a concatenation of the following types.
<paint> = none | <color> | <gradient> | <pattern>
The following properties are currently in use.
Not using any color is not equal to <color> of [transparent](/en/api/css/css-properties-values-api #transparent) keyword. In the case of the fill
property, for example, both are visually identical, but setting it to 'transparent'
will still pick it up, while setting it to 'none'
will not.
For example, when a drawing is initialized without the fill
attribute set, it is equivalent to manually changing it to none
after creation.
const circle = new Circle({r: 150,});circle.style.fill = 'none';
All CSS property metadata in Blink is defined in a JSON list, which describes how the style system should parse and calculate style values.
The attribute metadata contains the following key information.
The defaults have a different definition of "whether the property supports inheritance".
https://developer.mozilla.org/en-US/docs/Web/CSS/initial_value
- For inherited properties, the initial value is used on the root element only, as long as no specified value is supplied.
- For non-inherited properties, the initial value is used on all elements, as long as no specified value is supplied.
Therefore, for the root node of G, all inherited
attributes need to be set to their default values at creation time, e.g. visibility
is defined in the attribute metadata as follows, and it supports inheritance.
{name: 'visibility',keywords: ['visible', 'hidden'],inherited: true,interpolable: true,defaultValue: 'visible',handler: CSSPropertyVisibility,}
Since inheritance is supported, the child element will be visible
by default, even if visibility
has not been set.
The parsing of property values goes through the following stages.
https://developer.mozilla.org/en-US/docs/Web/CSS/computed_value
In this step it is necessary to.
The computed value map can be obtained via the computedStyleMap method, which is a Map type.
/*** computed values*/const styleMap = circle.computedStyleMap();expect((styleMap.get('r') as CSSUnitValue).equals(CSS.px(100))).to.be.true;const fill = styleMap.get('fill') as CSSRGB;expect(fill.r).toBe(255);expect(fill.g).toBe(0);expect(fill.b).toBe(0);expect(fill.alpha).toBe(1);
However, the computed value cannot be used directly for rendering, e.g., percentages, relative lengths need to be further calculated.
https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
The computed value is further processed to get the value that will eventually be fed into the rendering pipeline.
For example CSS.percent(50)
needs to be computed to get CSS.px(?)
.
Define the new property in CSS as follows.
https://developer.mozilla.org/en-US/docs/Web/API/CSS/RegisterProperty
CSS.registerProperty({name: '--my-color',syntax: '<color>',inherits: false,initialValue: '#c0ffee',});
This property can then be used in CSS. One of the more critical ones is syntax
, the limitation being that you can only use the browser's built-in implementation and can't really do custom parsing in the true sense.
In this example, we register several different types of custom properties, allowing them to support interpolation.
import { CSS, PropertySyntax } from '@antv/g';// Register custom propertiesCSS.registerProperty({name: 'myNumber',syntax: PropertySyntax.NUMBER, // Using the built-in "number" parserinitialValue: '0',interpolable: true, // Support interpolation during animation});// Apply animations to custom propertiesconst animation = myCustomElement.animate([{myNumber: 0,},{myNumber: 1,},],{ duration: 2000, fill: 'both' },);
The name of the attribute in string form. It needs to be globally unique and cannot conflict with built-in properties, and can be prefixed with a namespace.
Whether to support inheritance.
Default value.
If or not interpolation is supported. Only supported to apply animation.
For example, in the following custom element, we define the custom attribute angle
, which uses the <angle>
parser and supports interpolation.
CSS.registerProperty({name: 'angle',syntax: PropertySyntax.ANGLE,initialValue: '0',interpolable: true,});
We currently support the following parsers.
/*** @see https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type*/export enum PropertySyntax {/*** @see https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#coordinate*/COORDINATE = '<coordinate>',/*** @see https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#color*/COLOR = '<color>',/*** @see https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#paint*/PAINT = '<paint>',/*** @see https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#number*/NUMBER = '<number>',/*** @see https://developer.mozilla.org/zh-CN/docs/Web/CSS/angle*/ANGLE = '<angle>',/*** <number> with range 0..1* @see https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#opacity_value*/OPACITY_VALUE = '<opacity-value>',/*** <number> with range 0..Infinity*/SHADOW_BLUR = '<shadow-blur>',/*** @see https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#length*/LENGTH = '<length>',/*** @see https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#percentage*/PERCENTAGE = '<percentage>',LENGTH_PERCENTAGE = '<length> | <percentage>',LENGTH_PERCENTAGE_12 = '[<length> | <percentage>]{1,2}',/*** @see https://developer.mozilla.org/en-US/docs/Web/CSS/margin#formal_syntax*/LENGTH_PERCENTAGE_14 = '[<length> | <percentage>]{1,4}',/*** @see https://developer.mozilla.org/en-US/docs/Web/SVG/Content_type#list-of-ts*/LIST_OF_POINTS = '<list-of-points>',PATH = '<path>',/*** @see https://developer.mozilla.org/en-US/docs/Web/CSS/filter#formal_syntax*/FILTER = '<filter>',Z_INDEX = '<z-index>',OFFSET_PATH = '<offset-path>',OFFSET_DISTANCE = '<offset-distance>',CLIP_PATH = '<clip-path>',TRANSFORM = '<transform>',TRANSFORM_ORIGIN = '<transform-origin>',TEXT = '<text>',TEXT_TRANSFORM = '<text-transform>',}