Let's use this cool button to go over some of the basic features of Typed OM.
28 |
For any element you can use the computedStyleMap() method, to retrieve all the styles affecting the element.
29 |
30 |
31 |
Some super cool Term
32 |
Some other super cool Definition
33 |
34 |
35 |
registerPaint('headerHighlight', class {
36 | // Whether Alpha is allowed - This is set to true by default, if it is set to false all colours used on the canvas will have full opacity, or alpha of 1.0
37 | static get contextOptions() { return {alpha: true}; }
38 |
39 | paint(ctx, size) {
40 | // ctx - drawing context
41 | // size - size of the box being painted
42 | ctx.fillStyle = 'hsla(55, 90%, 60%, 1.0)';
43 | ctx.fillRect(0, size.height/4, size.width*0.66, size.height*0.7);
44 | }
45 | });
46 |
47 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/cssPaint/intro/03partThree/header-highlight.js:
--------------------------------------------------------------------------------
1 | console.clear();
2 |
3 | registerPaint('headerHighlight', class {
4 | // use this function to retrieve any custom props defined for the element, return them in the specified array
5 | static get inputProperties() { return ['--highColour']; }
6 | // Input arguments that can be passed to the `paint` function
7 | // static get inputArguments() { return ['']; }
8 | // Whether Alpha is allowed? - This is set to true by default, if it is set to false all colours used on the canvas will have full opacity, or alpha of 1.0
9 | static get contextOptions() { return {alpha: true}; }
10 |
11 | paint(ctx, size, props) {
12 | // ctx -> drawing context
13 | // size -> size of the box being painted
14 | // props -> list of custom properties available to the element
15 |
16 | // set where to start the highlight & dimensions
17 | const x = 0;
18 | const y = size.height*0.3;
19 | const blockWidth = size.width*0.33;
20 | const highlightHeight = size.height*0.85;
21 |
22 | // Paint uses Typed OM to retireve the custom property value, so we have to use the get method on it
23 | ctx.fillStyle = props.get('--highColour');
24 | // block
25 | ctx.beginPath();
26 | ctx.moveTo(x, y);
27 | ctx.lineTo(blockWidth, y);
28 | ctx.lineTo(blockWidth+highlightHeight, highlightHeight);
29 | ctx.lineTo(x, highlightHeight);
30 | ctx.lineTo(x, y);
31 | ctx.closePath();
32 | ctx.fill();
33 | // dashes
34 | for (let i=0; i<4; i++) {
35 | let start = i*2;
36 | ctx.beginPath();
37 | ctx.moveTo((blockWidth)+(start*10)+10, y);
38 | ctx.lineTo((blockWidth)+(start*10)+20, y);
39 | ctx.lineTo((blockWidth)+(start*10)+20+(highlightHeight), highlightHeight);
40 | ctx.lineTo((blockWidth)+(start*10)+10+(highlightHeight), highlightHeight);
41 | ctx.lineTo((blockWidth)+(start*10)+10, y);
42 | ctx.closePath();
43 | ctx.fill();
44 | }
45 | } // paint
46 | });
--------------------------------------------------------------------------------
/cssPaint/intro/04partFour/header-highlight.js:
--------------------------------------------------------------------------------
1 |
2 | registerPaint('headerHighlight', class {
3 | static get inputProperties() { return ['--highColour']; }
4 | // Input arguments that can be passed to the `paint` function
5 | static get inputArguments() { return ['*','']; }
6 |
7 | static get contextOptions() { return {alpha: true}; }
8 |
9 | paint(ctx, size, props, args) {
10 | // ctx -> drawing context
11 | // size -> size of the box being painted
12 | // props -> list of custom properties available to the element
13 | // args -> list of arguments we can set when calling the paint() function in our css
14 |
15 | // set where to start the highlight & dimensions
16 | const x = 0;
17 | const y = size.height*0.3;
18 | const blockWidth = size.width*0.33;
19 | const highlightHeight = size.height*0.85;
20 | const colour = props.get('--highColour');
21 |
22 | // use our custom arguments
23 | ctx.fillStyle = colour;
24 | ctx.strokeStyle = 'transparent';
25 |
26 | const strokeWidth = args[1];
27 | if (strokeWidth.unit === 'px') {
28 | ctx.lineWidth = strokeWidth.value;
29 | } else {
30 | ctx.lineWidth = 1.0;
31 | }
32 | // set a stroke
33 | const hasStroke = args[0].toString();
34 | if (hasStroke === 'stroke') {
35 | ctx.fillStyle = 'transparent';
36 | ctx.strokeStyle = colour;
37 | }
38 |
39 | // block
40 | ctx.beginPath();
41 | ctx.moveTo(x, y);
42 | ctx.lineTo(blockWidth, y);
43 | ctx.lineTo(blockWidth+highlightHeight, highlightHeight);
44 | ctx.lineTo(x, highlightHeight);
45 | ctx.lineTo(x, y);
46 | ctx.closePath();
47 | ctx.fill();
48 | ctx.stroke();
49 | // dashes
50 | for (let i=0; i<4; i++) {
51 | let start = i*2;
52 | ctx.beginPath();
53 | ctx.moveTo((blockWidth)+(start*10)+10, y);
54 | ctx.lineTo((blockWidth)+(start*10)+20, y);
55 | ctx.lineTo((blockWidth)+(start*10)+20+(highlightHeight), highlightHeight);
56 | ctx.lineTo((blockWidth)+(start*10)+10+(highlightHeight), highlightHeight);
57 | ctx.lineTo((blockWidth)+(start*10)+10, y);
58 | ctx.closePath();
59 | ctx.fill();
60 | ctx.stroke();
61 | }
62 |
63 | } // paint
64 | });
65 |
66 |
--------------------------------------------------------------------------------
/sharedAssets/shared-styles.css:
--------------------------------------------------------------------------------
1 | @import 'normalize.css';
2 | @import 'prism.css';
3 | /* Real Simple MDN Styles */
4 |
5 | @font-face {
6 | font-family: 'zillaslab';
7 | src: url('ZillaSlab.woff2') format('woff2');
8 | }
9 |
10 | :root {
11 | --black: hsl(0, 0%, 16%);
12 | --white: hsl(0,0%,97%);
13 | --blue: hsl(198, 100%, 66%);
14 | --teal: hsl(198, 43%, 42%);
15 | --lightYellow: hsl(43, 100%, 92%);
16 | --grey: hsl(0, 0%, 80%);
17 | --unit: 1.2rem;
18 | }
19 |
20 | body {
21 | padding: var(--unit);
22 | background-color: var(--white);
23 | font-family: 'Arial', sans-serif; font-size: 100%;
24 | color: var(--black); line-height: 1.3;
25 | max-width: 900px;
26 | }
27 |
28 | /* page partials */
29 | footer {
30 | padding: var(--unit);
31 | margin-top: calc(var(--unit)*2);
32 | border-top: 1px solid var(--grey);
33 | }
34 | footer p {
35 | margin: 0px; text-align: center;
36 | }
37 |
38 | /* base styles */
39 | h1, h2 {
40 | font-family: "zillaslab", serif;
41 | }
42 |
43 | h2 {
44 | padding: calc(var(--unit)/2);
45 | background-color: var(--black);
46 | color: var(--white); font-weight: normal;
47 | }
48 |
49 | p {}
50 |
51 | a {
52 | border: 1px solid var(--teal);
53 | border-width: 0px 0px 1px 0px;
54 | color: var(--teal);
55 | text-decoration: none;
56 | }
57 | a:hover {
58 | border-width: 1px 0px 0px 0px;
59 | }
60 |
61 | nav ul {
62 | display: flex; justify-content: space-between;
63 | margin: 0px; padding: 0px;
64 | list-style: none;
65 | }
66 | nav li {margin: 0px; padding: 0px;}
67 |
68 | dl {display: flex; flex-wrap: wrap;}
69 | dt, dd {padding: 2%; box-sizing: border-box;}
70 | dt {width: 30%; font-weight: bold; text-align: right;}
71 | dd {width: 66%; margin: 0px;}
72 |
73 | code {
74 | background-color: var(--lightYellow);
75 | font-family:monospace; font-size:110%;
76 | letter-spacing:0.5px;
77 | }
78 |
79 | pre {
80 | padding: var(--unit);
81 | background-color: var(--grey);
82 | border-left: 4px solid var(--teal);
83 | white-space: pre-wrap;
84 | overflow-wrap: break-word;
85 | tab-size: 4; font-size: 86%;
86 | }
87 |
88 | pre code {
89 | background: none;
90 | }
91 |
92 | figure {
93 | margin: 0px; padding: 0px;
94 | }
--------------------------------------------------------------------------------
/typedOM/transformValue/02example/app.js:
--------------------------------------------------------------------------------
1 | console.clear();
2 |
3 | class Sparkle {
4 |
5 | constructor(originX, originY) {
6 | this.x = CSS.px(originX);
7 | this.y = CSS.px(originY);
8 | this.img = this.createImage();
9 | }
10 |
11 | get _translate() {
12 | const shift = Math.floor(Math.random() * 40) - 20;
13 | return new CSSTranslate(
14 | CSS.px(shift),
15 | CSS.px(shift)
16 | )
17 | }
18 |
19 | get _rotate() {
20 | return new CSSRotate(CSS.turn(Math.random()));
21 | }
22 |
23 | get _scale() {
24 | const scaleVal = Math.random() * 2;
25 | return new CSSScale(CSS.number(scaleVal), CSS.number(scaleVal));
26 | }
27 |
28 | get transform() {
29 | return new CSSTransformValue([
30 | this._translate,
31 | this._rotate,
32 | this._scale
33 | ])
34 | }
35 |
36 | get _pickSource() {
37 | const svgs = ['star.svg', 'cross.svg', 'square.svg', 'circle.svg'];
38 | const pick = Math.floor(Math.random()*4);
39 | return svgs[pick];
40 | }
41 |
42 | get _timeAlive() {
43 | return CSS.ms(Math.ceil(Math.random()*500))
44 | }
45 |
46 | createImage() {
47 | const image = document.createElement('img');
48 | image.src = this._pickSource;
49 | image.alt = 'sparkle';
50 | image.classList.add('sparkle');
51 | image.attributeStyleMap.set('left', this.x);
52 | image.attributeStyleMap.set('top', this.y);
53 | image.attributeStyleMap.set('transform', this.transform);
54 | image.attributeStyleMap.set('animation-duration', this._timeAlive);
55 | return image;
56 | }
57 |
58 | }
59 |
60 | const sparkleBoard = document.querySelector('.sparkleArea');
61 | let boardDimensions = sparkleBoard.getBoundingClientRect();
62 | let x = 0;
63 | let y = 0;
64 |
65 | sparkleBoard.addEventListener('mousemove', function(e) {
66 |
67 | boardDimensions = sparkleBoard.getBoundingClientRect();
68 | x = e.clientX - boardDimensions.left;
69 | y = e.clientY - boardDimensions.top;
70 |
71 | const spark = new Sparkle(x, y);
72 |
73 | sparkleBoard.appendChild(spark.img);
74 |
75 | // quick and dirty way to remove sparkles from DOM to help performance
76 | setTimeout(() => sparkleBoard.firstChild.remove(), 500);
77 |
78 | }, false);
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/cssPaint/intro/worklets/hollow.js:
--------------------------------------------------------------------------------
1 |
2 | registerPaint('hollowHighlights', class {
3 |
4 | static get inputProperties() { return ['--boxColor']; }
5 | // Input arguments that can be passed to the `paint` function
6 | static get inputArguments() { return ['*','']; }
7 |
8 | static get contextOptions() { return {alpha: true}; }
9 |
10 | paint(ctx, size, props, args) {
11 | // ctx -> drawing context
12 | // size -> size of the box being painted
13 | // props -> list of custom properties available to the element
14 | // args -> list of arguments set when calling the paint() function in the css
15 |
16 | // where to start the highlight & dimensions
17 | const x = 0;
18 | const y = size.height * 0.3;
19 | const blockWidth = size.width * 0.33;
20 | const blockHeight = size.height * 0.85;
21 |
22 | // the values passed in the paint() function in the CSS
23 | const colour = props.get( '--boxColor' );
24 | const strokeType = args[0].toString();
25 | const strokeWidth = parseInt(args[1]);
26 |
27 |
28 | // set the stroke width
29 | if ( strokeWidth ) {
30 | ctx.lineWidth = strokeWidth;
31 | } else {
32 | ctx.lineWidth = 1.0;
33 | }
34 | // set the fill type
35 | if ( strokeType === 'stroke' ) {
36 | ctx.fillStyle = 'transparent';
37 | ctx.strokeStyle = colour;
38 | } else if ( strokeType === 'filled' ) {
39 | ctx.fillStyle = colour;
40 | ctx.strokeStyle = colour;
41 | } else {
42 | ctx.fillStyle = 'none';
43 | ctx.strokeStyle = 'none';
44 | }
45 |
46 | // block
47 | ctx.beginPath();
48 | ctx.moveTo( x, y );
49 | ctx.lineTo( blockWidth, y );
50 | ctx.lineTo( blockWidth + blockHeight, blockHeight );
51 | ctx.lineTo( x, blockHeight );
52 | ctx.lineTo( x, y );
53 | ctx.closePath();
54 | ctx.fill();
55 | ctx.stroke();
56 | // dashes
57 | for (let i = 0; i < 4; i++) {
58 | let start = i * 2;
59 | ctx.beginPath();
60 | ctx.moveTo( blockWidth + (start * 10) + 10, y);
61 | ctx.lineTo( blockWidth + (start * 10) + 20, y);
62 | ctx.lineTo( blockWidth + (start * 10) + 20 + blockHeight, blockHeight);
63 | ctx.lineTo( blockWidth + (start * 10) + 10 + blockHeight, blockHeight);
64 | ctx.lineTo( blockWidth + (start * 10) + 10, y);
65 | ctx.closePath();
66 | ctx.fill();
67 | ctx.stroke();
68 | }
69 |
70 | } // paint
71 | });
72 |
--------------------------------------------------------------------------------
/cssPaint/intro/worklets/hilite.js:
--------------------------------------------------------------------------------
1 |
2 | registerPaint('hollowHighlights', class {
3 |
4 | static get inputProperties() { return ['--boxColor']; }
5 | // Input arguments that can be passed to the `paint` function
6 | static get inputArguments() { return ['*','']; }
7 |
8 | static get contextOptions() { return {alpha: true}; }
9 |
10 | paint(ctx, size, props, args) {
11 | // ctx -> drawing context
12 | // size -> size of the box being painted
13 | // props -> list of custom properties available to the element
14 | // args -> list of arguments set when calling the paint() function in the css
15 |
16 | // where to start the highlight & dimensions
17 | const x = 0;
18 | const y = size.height * 0.3;
19 | const blockWidth = size.width * 0.33;
20 | const blockHeight = size.height * 0.85;
21 |
22 | // the values passed in the paint() function in the CSS
23 | const theColor = props.get( '--boxColor' );
24 | const strokeType = args[0].toString();
25 | const strokeWidth = parseInt(args[1]);
26 |
27 | console.log(theColor);
28 |
29 | // set the stroke width
30 | if ( strokeWidth ) {
31 | ctx.lineWidth = strokeWidth;
32 | } else {
33 | ctx.lineWidth = 1.0;
34 | }
35 | // set the fill type
36 | if ( strokeType === 'stroke' ) {
37 | ctx.fillStyle = 'transparent';
38 | ctx.strokeStyle = theColor;
39 | } else if ( strokeType === 'filled' ) {
40 | ctx.fillStyle = theColor;
41 | ctx.strokeStyle = theColor;
42 | } else {
43 | ctx.fillStyle = 'none';
44 | ctx.strokeStyle = 'none';
45 | }
46 |
47 | // block
48 | ctx.beginPath();
49 | ctx.moveTo( x, y );
50 | ctx.lineTo( blockWidth, y );
51 | ctx.lineTo( blockWidth + blockHeight, blockHeight );
52 | ctx.lineTo( x, blockHeight );
53 | ctx.lineTo( x, y );
54 | ctx.closePath();
55 | ctx.fill();
56 | ctx.stroke();
57 | // dashes
58 | for (let i = 0; i < 4; i++) {
59 | let start = i * 2;
60 | ctx.beginPath();
61 | ctx.moveTo( blockWidth + (start * 10) + 10, y);
62 | ctx.lineTo( blockWidth + (start * 10) + 20, y);
63 | ctx.lineTo( blockWidth + (start * 10) + 20 + blockHeight, blockHeight);
64 | ctx.lineTo( blockWidth + (start * 10) + 10 + blockHeight, blockHeight);
65 | ctx.lineTo( blockWidth + (start * 10) + 10, y);
66 | ctx.closePath();
67 | ctx.fill();
68 | ctx.stroke();
69 | }
70 |
71 | } // paint
72 | });
--------------------------------------------------------------------------------
/typedOM/intro/01partOne/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Part 1 Intro | Typed OM
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
CSS Houdini Collection
21 |
Typed OM: Part 1 Intro
22 |
23 |
24 |
25 |
26 |
27 |
28 |
Let's use this cool button to go over some of the basic features of Typed OM.
29 |
For any element you can use the computedStyleMap() method to retrieve all the styles affecting the element.
30 |
Let's use this method to get all the styles for the below button.
31 |
32 |
// get the button element
33 | const buttonEl = document.querySelector('button');
34 | // get our element to append info to
35 | const stylesList = document.querySelector('#all-styles');
36 |
37 | // let's get some styles -> we can retrieve all computed styles with `computedStyleMap`
38 | const allComputedStyles = buttonEl.computedStyleMap();
39 |
40 | // which returns a map of all computed styles -> ie those already set in non-inline css
41 | for (const [prop, val] of allComputedStyles) {
42 | // properties
43 | const term = document.createElement('dt');
44 | term.appendChild(document.createTextNode(prop));
45 | stylesList.appendChild(term);
46 |
47 | // values
48 | const valDef = document.createElement('dd');
49 | valDef.appendChild(document.createTextNode(val));
50 | stylesList.appendChild(valDef);
51 | }
It would be better if we had an idea of the size of our element, so we could create the background relative to the element; this way we could use the same background on other elements as well, and the background would always fit.
23 |
24 |
The second parameter we can pass into the paint() function gives us access to the width and the height of the element, via .width and .height properties. Pretty handy.
25 |
26 |
Let's take a look at our header-highlight.js script now we can use this functionality.
27 |
28 |
29 | registerPaint('headerHighlight', class {
30 | // Whether Alpha is allowed - This is set to true by default, if it is set to false all colours used on the canvas will have full opacity, or alpha of 1.0
31 | static get contextOptions() { return {alpha: true}; }
32 |
33 | paint(ctx, size) {
34 | // ctx - drawing context
35 | // size - size of the box being painted
36 |
37 | ctx.fillStyle = 'hsla(55, 90%, 60%, 1.0)';
38 | ctx.fillRect(0, size.height/4, size.width*0.66, size.height*0.7);
39 |
40 | }
41 | });
42 |
43 |
Our header now has a highlight which changes according to it's size.
44 |
45 |
My Cool Header
46 |
47 |
And there's more, we can start to access custom properties inside our worklet function as well. Go to Part Three
48 |
49 |
50 |
53 |
54 |
55 |
56 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/typedOM/numericValue/02mathValue/app.js:
--------------------------------------------------------------------------------
1 | console.clear();
2 |
3 | const mathVal = new CSSMathSum(CSS.px(10), CSS.vw(20));
4 | console.log('CSSMathValue example:', mathVal);
5 | console.log('Using toString(): ', mathVal.toString());
6 |
7 | // Different math value types
8 | const el = document.querySelector('.example');
9 |
10 | // addition
11 | const sumVal = new CSSMathSum(CSS.px(10), CSS.vw(20), CSS.em(1.2));
12 | el.attributeStyleMap.set('width', sumVal);
13 | const gotSumVal = el.attributeStyleMap.get('width');
14 | console.log('Sum addition:', gotSumVal);
15 |
16 | // subtraction
17 | const subVal = new CSSMathSum(CSS.s(2), CSS.ms(-200));
18 | el.attributeStyleMap.set('animation-duration', subVal);
19 | const gotSubVal = el.attributeStyleMap.get('animation-duration');
20 | console.log('Sum subtraction:', gotSubVal);
21 |
22 | // multiplication
23 | const productVal = new CSSMathProduct(CSS.em(1.6), CSS.number(1.2));
24 | el.attributeStyleMap.set('font-size', productVal);
25 | const gotProductVal = el.attributeStyleMap.get('font-size');
26 | console.log('Product:', gotProductVal);
27 |
28 | // negation
29 | const negVal = new CSSMathNegate(CSS.px(20));
30 | el.attributeStyleMap.set('margin-top', negVal.toString());
31 | const gotNegVal = el.attributeStyleMap.get('margin-top');
32 | console.log('Negate:', negVal);
33 |
34 | // invert
35 | // const invVal = new CSSMathInvert(CSS.s(10));
36 | // console.log(invVal.toString());
37 | // el.attributeStyleMap.set('padding-bottom', invVal.toString());
38 | // const gotInvVal = el.attributeStyleMap.get('padding-bottom');
39 |
40 | const minVal = new CSSMathMin(CSS.vh(10), CSS.px(300));
41 | console.log('min():', minVal);
42 | // el.attributeStyleMap.set('height', minVal.toString());
43 | // const gotMinVal = el.attributeStyleMap.get('height');
44 |
45 | const maxVal = new CSSMathMax(CSS.px(50), CSS.percent(20));
46 | console.log('max():', maxVal);
47 | // el.attributeStyleMap.set('width', maxVal);
48 | // const gotMaxVal = el.attributeStyleMap.get('width');
49 |
50 | // const clampVal = new CSSMathClamp(CSS.px(10), CSS.em(4), CSS.px(80));
51 | // console.log('clamp():', clampVal);
52 | // el.attributeStyleMap.set('width', clampVal);
53 | // const gotClampVal = el.attributeStyleMap.get('width');
54 |
55 | const nestedVal = new CSSMathMin(
56 | new CSSMathProduct(CSS.em(1.2), CSS.number(1.4)),
57 | CSS.vw(10)
58 | );
59 | console.log('Nested:', nestedVal);
60 | // el.attributeStyleMap.set('font-size', nestedVal;
61 | // const gotNestedVal = el.attributeStyleMap.get('font-size');
62 |
63 |
--------------------------------------------------------------------------------
/.github/labels.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "good first issue",
4 | "color": "028c46",
5 | "description": "A good issue for newcomers to get started with."
6 | },
7 | {
8 | "name": "help wanted",
9 | "color": "028c46",
10 | "description": "If you know something about this, we would love your help!"
11 | },
12 | {
13 | "name": "needs info",
14 | "color": "028c46",
15 | "description": "This needs more information to review or act on."
16 | },
17 | {
18 | "name": "needs triage",
19 | "color": "028c46",
20 | "description": "Triage needed by staff and/or partners. Automatically applied when an issue is opened."
21 | },
22 | {
23 | "name": "expert help needed",
24 | "color": "028c46",
25 | "description": "This needs more information from a subject matter expert (SME)."
26 | },
27 | {
28 | "name": "idle",
29 | "color": "028c46",
30 | "description": "Issues and pull requests with no activity for three months."
31 | },
32 | {
33 | "name": "on hold",
34 | "color": "028c46",
35 | "description": "Waiting on something else before this can be moved forward."
36 | },
37 | {
38 | "name": "for later",
39 | "color": "028c46",
40 | "description": "Not planned at this time."
41 | },
42 | {
43 | "name": "needs content update",
44 | "color": "028c46",
45 | "description": "Needs update to the content to support this change."
46 | },
47 | {
48 | "name": "chore",
49 | "color": "028c46",
50 | "description": "A routine task."
51 | },
52 | {
53 | "name": "enhancement",
54 | "color": "028c46",
55 | "description": "Improves an existing feature."
56 | },
57 | {
58 | "name": "bug",
59 | "color": "c05964",
60 | "description": "Indicates an unexpected problem or unintended behavior."
61 | },
62 | {
63 | "name": "wontfix",
64 | "color": "c05964",
65 | "description": "Deemed to be outside the scope of the project or would require significant time and resources to fix."
66 | },
67 | {
68 | "name": "effort: small",
69 | "color": "866dc1",
70 | "description": "Task is a small effort."
71 | },
72 | {
73 | "name": "effort: medium",
74 | "color": "866dc1",
75 | "description": "Task is a medium effort."
76 | },
77 | {
78 | "name": "effort: large",
79 | "color": "866dc1",
80 | "description": "Task is large effort."
81 | },
82 | {
83 | "name": "p0",
84 | "color": "6e8bc1",
85 | "description": "Urgent. We will address this as soon as possible."
86 | },
87 | {
88 | "name": "p1",
89 | "color": "6e8bc1",
90 | "description": "We will address this soon and will provide capacity from our team for it in the next few releases."
91 | },
92 | {
93 | "name": "p2",
94 | "color": "6e8bc1",
95 | "description": "We want to address this but may have other higher priority items."
96 | },
97 | {
98 | "name": "p3",
99 | "color": "6e8bc1",
100 | "description": "We don't have visibility when this will be addressed."
101 | }
102 | ]
103 |
--------------------------------------------------------------------------------
/typedOM/reference/README.md:
--------------------------------------------------------------------------------
1 | # Typed OM Reference
2 |
3 | ---
4 |
5 | ## Style Maps
6 |
7 | #### Computed styles
8 |
9 | `element.getComputedStyles();`
10 |
11 | #### Attribute styles
12 |
13 | `element.attributeStyleMap`
14 |
15 | #### Stylesheets
16 |
17 | `document.styleSheets`
18 |
19 | #### Methods
20 |
21 | Returns CSSStyleValue type for specified property
22 | `styleMap.get(property)`
23 |
24 | Sets property and value
25 | `styleMap.set(property, value)`
26 |
27 | Removes property
28 | `styleMap.delete(property)`
29 |
30 | Returns true if has property and false if not
31 | `styleMap.has(property)`
32 |
33 | Clears all styles
34 | `styleMap.clear()`
35 |
36 | ---
37 |
38 | ## Value Types
39 |
40 | #### CSSStyleValue
41 |
42 | Super class
43 |
44 | #### CSSKeywordValue
45 |
46 | `CSSKeywordValue {value: "inline-block"}`
47 |
48 | #### CSSImageValue
49 |
50 | At the time of writing return CSSStyleValue
51 |
52 | #### CSSNumericValue
53 |
54 | Super class for Unit & Math
55 |
56 | #### CSSUnitValue
57 |
58 | `CSSUnitValue {value: 4, unit: "px"}`
59 |
60 | #### CSSMathSum
61 |
62 | ```
63 | CSSMathSum {
64 | operator: "sum",
65 | values: CSSNumericArray
66 | 0: CSSUnitValue
67 | unit: "percent"
68 | value: 30
69 | 1: CSSUnitValue
70 | unit: "px"
71 | value: 20
72 | }
73 | ```
74 |
75 | [//]: # (Need to add all MathSum here)
76 |
77 | #### CSSTransformValue
78 |
79 | ```
80 | CSSTransformValue {0: CSSScale, 1: CSSRotate, length: 2, is2D: true}
81 |
82 | 0: CSSScale
83 | is2D: true
84 | x: CSSUnitValue {value: 0.95, unit: "number"}
85 | y: CSSUnitValue {value: 0.95, unit: "number"}
86 | z: CSSUnitValue {value: 1, unit: "number"}
87 |
88 | 1: CSSRotate
89 | angle: CSSUnitValue {value: 0, unit: "deg"}
90 | is2D: true
91 | x: CSSUnitValue {value: 0, unit: "number"}
92 | y: CSSUnitValue {value: 0, unit: "number"}
93 | z: CSSUnitValue {value: 1, unit: "number"}
94 | ```
95 |
96 | [//]: # (Need to add all Transforms here)
97 |
98 | #### CSSUnparsedValue
99 |
100 | `CSSUnparsedValue {0: valueString, length: 1}`
101 |
102 | #### CSSVariableReferenceValue
103 |
104 | `new CSSVariableReferenceValue(property, new CSSUnparsedValue([value]));`
105 |
106 | #### Methods
107 |
108 | `CSSStyleValue.parse(propertyString, valueString)`
109 |
110 | `CSSNumericValue.parse(valueString)`
111 |
112 | ---
113 |
114 | ## Operations
115 |
116 | #### Convert units
117 |
118 | `CSSUnitValue.to(unit)`
119 |
120 | Only works with absolute and not relative units
121 |
122 | ---
123 |
124 | ## Some things to look out for
125 |
126 | The difference between the style maps: getComputedStyles, attributeStyleMap and styleSheets.
127 |
128 | You can't `get()` a property value from attributeStyleMap for instance without it being present on the element first (by using `set()` for example).
129 |
130 | The spec is being worked on, holes are being plugged and new features in discussion.
131 |
132 | ---
133 |
134 | ## Resources
135 |
136 | - [Working with the new CSS Typed Object Model](https://developers.google.com/web/updates/2018/03/cssom)
137 | - [An overview of Typed OM](https://houdini.glitch.me/typed-om)
138 | - [Current Draft Specification](https://drafts.css-houdini.org/css-typed-om-1/)
--------------------------------------------------------------------------------
/cssPaint/intro/03partThree/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Part 3 Custom Properties | CSS Paint API
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
CSS Houdini Collection
17 |
CSS Paint API: Part 3 Custom Properties
18 |
19 |
20 |
21 |
22 |
So now we have our cool header with a custom paint background, let's expand on it.
23 |
24 |
We'll update the paint() function to draw a more funky background and wouldn't it be great if we could choose the colour of the background whenever we wanted to use it? Another feature of the Paint API is the ability to access custom properties available to the element.
Now we can use the inputProperties() method in the registerPaint() class, grab that property and use it within our paint() function:
40 |
41 |
static get inputProperties() { return ['--highColour']; }
42 |
43 |
44 |
Note: The inputProperties() method returns all properties affecting the element, not just custom properties.
45 |
46 |
paint(ctx, size, props) {
47 | // Paint uses Typed OM to retrieve the custom property value, so, as with the Typed OM API, we have to use the get() method to access the value
48 | ctx.fillStyle = props.get('--highColour');
49 | ...
50 | }
51 |
52 |
53 |
Back in our CSS, on elements that have this paint() function generating their backgound, we can reset the --highColour custom property to change its color:
You can check out the entire registerPaint() function in header-highlight.js here. Not only can we pass in custom properties, but also custom arguments when we call the paint() function in our css. Let's take a look in part 4.
The CSS Paint API is designed to be used wherever you would invoke an image in CSS — backgrounds, borders, masks etc.
27 |
28 |
Here's a really simple example - let's say you want to create a cool half-highlight background, like on this header:
29 |
30 |
My Cool Header
31 |
32 |
The main setup & design will happen in an external script, a worklet, which we'll discuss in a minute. We first need to register that worklet from our main script:
33 |
34 |
// in our main script
35 | await CSS.paintWorklet.addModule('header-highlight.js');
36 |
37 |
Now we'll create that header-highlight.js worklet; inside it we use the registerPaint() function to name our CSS Paint worklet, and also pass in a class that does all the magic:
38 |
39 |
registerPaint('headerHighlight', class {
40 |
41 | // Whether Alpha is allowed -> This is set to true by default, if it is set to false all colours used on the canvas will have full opacity, or alpha of 1.0
42 | static get contextOptions() { return {alpha: true}; }
43 |
44 | paint(ctx) {
45 | // ctx - drawing context
46 |
47 | ctx.fillStyle = 'hsla(55, 90%, 60%, 1.0)';
48 | ctx.fillRect(0, 15, 200, 20);
49 |
50 | }
51 | });
52 |
53 |
Now we have created a new paint worklet, and given it a name headerHighlight. We can now use that in our CSS, along with the paint() function, where we would normally call an image.
Our paint function takes one argument (we'll look at more in due course): ctx. This is the 2D Rendering Context, which is a subset of the HTML5 Canvas API. It contains pretty much all the features apart from "...CanvasImageData, CanvasUserInterface, CanvasText, or CanvasTextDrawingStyles APIs..." (taken from spec https://drafts.css-houdini.org/css-paint-api-1/#2d-rendering-context). So in short we can use it to draw whatever we like as our background image.
60 |
61 |
The above example just simple draws a filled rectangle, you can do a lot more than that (check out the Canvas API docs).
62 |
63 |
Let's take a look at some of the other data available to the paint() function. Go to Part Two
Not only do we have access to our own custom properties, but we can also pass in our own custom arguments to the paint() function as well.
23 |
24 |
We add these extra arguments when we call the function in the CSS. Let's say we want to sometimes stroke our background instead of fill it, let's pass in an extra argument for this occasion.
Now we can use the inputArguments() method in the registerPaint() class, to get a list of these custom arguments we have added to our paint() function:
34 |
35 |
static get inputArguments() { return ['*']; }
36 |
In this case we have just added the string 'stroke', but there's more — if the custom argument is a CSS value, for instance a unit, we can invoke Typed OM CSSStyleValue class (and sub classes) by using the value type keyword when we retrieve it in the registerPaint() function.
53 |
54 |
Let's say we add a second argument with how many pixels wide we want the stroke to be:
Note: It's worth noting the difference between using custom properties to control different parts of this worklet and the arguments set out here. The situation will depend on this: Custom properties (and in fact any properties on the style map) are global — they can be used elsewhere within our CSS (and JS). You may for example have a --mainColor, which will be useful for setting the color within a paint() function, but also sets colors elsewhere in your CSS. If you wanted to change it specifically for paint, it could prove difficult, so this is where thinking about custom arguments may come in. Another way to think about it is that arguments are set to control what you are actually drawing, whereas properties are set to control styling.
83 |
84 |
Now we can really start to see the benefits of this API, if we can control a myriad of drawing parameters from our CSS through both custom properties and extra paint() function arguments, then we can really start to build reusable and infinitely controlled styling elements.
85 |
86 |
In the next part we take a look at building such a styling element and how we can configure it to be used throughout our code. Carry on with CSS Paint in the next part here.
Now that we know all about the CSSStyleValue types, let's take a look at creating them and setting them on an element.
29 |
30 |
So far we've been working with computedStyleMap, which returns all the properties and values affecting an element, but there is also the attributeStyleMap for getting and setting inline styles. This is much like our already commonly used style() method, and you might wonder why we need to change something that works. With this new Typed OM method we also work with all the CSSStyleValue types, rather than just strings. This makes our code far more robust and flexible.
31 |
32 |
Note: Both the computed and attribute style maps are of type StylePropertyMap, which is a map-like object, and so supports all the common methods like get(), set(), keys(), values(), and entries() — making them intuitive to work with1. There is also styleMap, which is described further down.
33 |
34 |
Let's take a look at the methods available to us when using the attributeStyleMap. To simply add a style and then retrieve it, we can use the set() and get() methods.
A couple of things to note here: When we are setting the pixel value we are creating a CSSUnitValue using the CSS.px() factory method. We could have set it thus:
44 |
45 |
new CSSUnitValue(10, px);
46 |
47 |
We can use this to create any CSSStyleValue we've already seen
48 |
49 |
Also, when we get the property a CSSUnitValue returned. That's handy because we don't have to do any parsing to retrieve the number or the unit, they are just available to us.
50 |
51 |
And there's more, as well as the set() and get() methods, there are has(), delete(), and clear().
Might be worth noting this should be used with caution, as it's a pretty powerful way to update your styles.
81 |
82 |
Well done! You've covered all the basics of using Typed OM. There's quite a bit there and with all the values quite a bit still to think about (all the math sums for instance) There's a reference with resources here and loads more information in the MDN docs.
The maths doesn't stop there. CSSNumericValues come with their own set of operations that can be performed on all numeric values. What operation you use and with what values, depends on what is returned. Let's take a look at all the methods and a few examples of each. As these methods are available on the CSSNumericValue super class they can take a unit or a sum.
27 |
28 |
add
29 |
30 |
let sum = CSS.px(54).add(CSS.px(30));
31 | // Returns: CSSUnitValue {value: 84, unit: "px"}
32 |
33 |
In the above example we are using the same unit, and so a direct addition takes place and a CSSUnitValue is returned. If we use varying units, a CSSMathValue is returned.
let sub = CSS.mm(300).sub(CSS.mm(210));
42 | // Returns: CSSUnitValue {value: 90, unit: "mm"}
43 |
44 |
As with add above, if we use different units a CSSMathValue is returned
45 |
46 |
let sub = CSS.cm(5).add(CSS.mm(90));
47 | sub.toString() // calc(5cm + -90mm)
48 |
49 |
mul
50 |
51 |
Notice here you can pass in just a number to the multiply function. A CSSNumericValue would work as well. Differing values will return a CSSMathValue.
52 |
53 |
let mul = CSS.em(1.2).mul(1.4);
54 | // Returns: CSSUnitValue {value: 1.68, unit: "em"}
55 |
56 |
div
57 |
58 |
As with mul you can enter a number or a CSSNumericValue. Different units return a CSSMathValue
59 |
60 |
let div = CSS.turn(1).div(2);
61 | // Returns: CSSUnitValue {value: 0.5, unit: "turn"}
62 |
63 |
min
64 |
65 |
min returns the lowest value, and you can input as many values as you please. If the units differ a CSSMathMin type is returned with the values and units that have been used.
66 |
67 |
let min = CSS.px(500).min(CSS.px(400), CSS.px(200));
68 | // Returns: CSSUnitValue {value: 200, unit: "px"}
69 |
70 | min = CSS.em(1.2).min(CSS.rem(1.4));
71 | min.toString() // min(1.2em, 1.4rem)
72 |
73 |
max
74 |
75 |
Same as min, however it returns the maximum value in the list, or if the units differ, a CSSMathMax type
76 |
77 |
let max = CSS.pt(50).max(CSS.pt(90), CSS.pt(10));
78 | // Returns: CSSUnitValue {value: 90, unit: "pt"}
79 |
80 | max = CSS.px(500).max(CSS.percent(60));
81 | max.toString() // max(500px, 60%)
82 |
83 |
Conversion & Comparison
84 |
85 |
Maths methods are pretty useful, so is a way to convert units on the fly. We can do that with the to method.
86 |
87 |
to
88 |
89 |
It only allows us to convert absolute units. (Unfortunately not relative ones at this time).
90 |
91 |
// inches to centimetres
92 | const cm = CSS.in(2).to('cm');
93 | // Returns: CSSUnitValue {value: 5.08, unit: "cm"}
94 |
95 |
equals
96 |
Another very interesting bit of functionality. We can test to see if one value is equal to another with just one method.
When using these latter two pieces of functionality together we can do some clever stuff, like convert degrees to radians and check it within our code, without having to know the precise radian value, which is always a bit trickier to remember than degrees.
CSS Transform property has it's own CSSStyleValue type: CSSTransformValue, and so it's subsequent values have their own type too. This is really nice because so far in javaScript, when we've wanted to modify one transform value, we've had to save and recreate a whole string if there have been multiple transform values affecting an element.
This can get a little frustrating, especially if we have quite a few transform values and are only changing one.
40 |
41 |
It would be much better if each part could be built individually and automatically, as well as the overall transform, and with types rather than a string.
42 |
43 |
Well, with Typed OM, you can!
44 |
45 |
CSSTransformValue
46 |
47 |
This creates a new transform value, which takes an array of the transform value types. Let's see what our above example would look like:
48 |
49 |
const transform = new CSSTransformValue([
50 | new CSSRotate(CSS.deg(30)),
51 | new CSSScale(CSS.number(1.2))
52 | ])
53 |
54 |
Each different transform has it's own type, which takes relevant CSSNumericValues. Let's go through them.
Note also the values that can transform in three dimensions. There's a boolean property on CSSTransformValue and all the values we've seen above, to test if they return 2D or 3D.
165 |
166 |
167 |
168 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | CC0 1.0 Universal
2 |
3 | Statement of Purpose
4 |
5 | The laws of most jurisdictions throughout the world automatically confer
6 | exclusive Copyright and Related Rights (defined below) upon the creator and
7 | subsequent owner(s) (each and all, an "owner") of an original work of
8 | authorship and/or a database (each, a "Work").
9 |
10 | Certain owners wish to permanently relinquish those rights to a Work for the
11 | purpose of contributing to a commons of creative, cultural and scientific
12 | works ("Commons") that the public can reliably and without fear of later
13 | claims of infringement build upon, modify, incorporate in other works, reuse
14 | and redistribute as freely as possible in any form whatsoever and for any
15 | purposes, including without limitation commercial purposes. These owners may
16 | contribute to the Commons to promote the ideal of a free culture and the
17 | further production of creative, cultural and scientific works, or to gain
18 | reputation or greater distribution for their Work in part through the use and
19 | efforts of others.
20 |
21 | For these and/or other purposes and motivations, and without any expectation
22 | of additional consideration or compensation, the person associating CC0 with a
23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
25 | and publicly distribute the Work under its terms, with knowledge of his or her
26 | Copyright and Related Rights in the Work and the meaning and intended legal
27 | effect of CC0 on those rights.
28 |
29 | 1. Copyright and Related Rights. A Work made available under CC0 may be
30 | protected by copyright and related or neighboring rights ("Copyright and
31 | Related Rights"). Copyright and Related Rights include, but are not limited
32 | to, the following:
33 |
34 | i. the right to reproduce, adapt, distribute, perform, display, communicate,
35 | and translate a Work;
36 |
37 | ii. moral rights retained by the original author(s) and/or performer(s);
38 |
39 | iii. publicity and privacy rights pertaining to a person's image or likeness
40 | depicted in a Work;
41 |
42 | iv. rights protecting against unfair competition in regards to a Work,
43 | subject to the limitations in paragraph 4(a), below;
44 |
45 | v. rights protecting the extraction, dissemination, use and reuse of data in
46 | a Work;
47 |
48 | vi. database rights (such as those arising under Directive 96/9/EC of the
49 | European Parliament and of the Council of 11 March 1996 on the legal
50 | protection of databases, and under any national implementation thereof,
51 | including any amended or successor version of such directive); and
52 |
53 | vii. other similar, equivalent or corresponding rights throughout the world
54 | based on applicable law or treaty, and any national implementations thereof.
55 |
56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of,
57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
59 | and Related Rights and associated claims and causes of action, whether now
60 | known or unknown (including existing as well as future claims and causes of
61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum
62 | duration provided by applicable law or treaty (including future time
63 | extensions), (iii) in any current or future medium and for any number of
64 | copies, and (iv) for any purpose whatsoever, including without limitation
65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
66 | the Waiver for the benefit of each member of the public at large and to the
67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver
68 | shall not be subject to revocation, rescission, cancellation, termination, or
69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work
70 | by the public as contemplated by Affirmer's express Statement of Purpose.
71 |
72 | 3. Public License Fallback. Should any part of the Waiver for any reason be
73 | judged legally invalid or ineffective under applicable law, then the Waiver
74 | shall be preserved to the maximum extent permitted taking into account
75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
76 | is so judged Affirmer hereby grants to each affected person a royalty-free,
77 | non transferable, non sublicensable, non exclusive, irrevocable and
78 | unconditional license to exercise Affirmer's Copyright and Related Rights in
79 | the Work (i) in all territories worldwide, (ii) for the maximum duration
80 | provided by applicable law or treaty (including future time extensions), (iii)
81 | in any current or future medium and for any number of copies, and (iv) for any
82 | purpose whatsoever, including without limitation commercial, advertising or
83 | promotional purposes (the "License"). The License shall be deemed effective as
84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the
85 | License for any reason be judged legally invalid or ineffective under
86 | applicable law, such partial invalidity or ineffectiveness shall not
87 | invalidate the remainder of the License, and in such case Affirmer hereby
88 | affirms that he or she will not (i) exercise any of his or her remaining
89 | Copyright and Related Rights in the Work or (ii) assert any associated claims
90 | and causes of action with respect to the Work, in either case contrary to
91 | Affirmer's express Statement of Purpose.
92 |
93 | 4. Limitations and Disclaimers.
94 |
95 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
96 | surrendered, licensed or otherwise affected by this document.
97 |
98 | b. Affirmer offers the Work as-is and makes no representations or warranties
99 | of any kind concerning the Work, express, implied, statutory or otherwise,
100 | including without limitation warranties of title, merchantability, fitness
101 | for a particular purpose, non infringement, or the absence of latent or
102 | other defects, accuracy, or the present or absence of errors, whether or not
103 | discoverable, all to the greatest extent permissible under applicable law.
104 |
105 | c. Affirmer disclaims responsibility for clearing rights of other persons
106 | that may apply to the Work or any use thereof, including without limitation
107 | any person's Copyright and Related Rights in the Work. Further, Affirmer
108 | disclaims responsibility for obtaining any necessary consents, permissions
109 | or other rights required for any use of the Work.
110 |
111 | d. Affirmer understands and acknowledges that Creative Commons is not a
112 | party to this document and has no duty or obligation with respect to this
113 | CC0 or use of the Work.
114 |
115 | For more information, please see
116 |
117 |
--------------------------------------------------------------------------------
/typedOM/numericValue/04example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Typed OM Example 1: Map
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
CSS Houdini Collection
21 |
Typed OM Example 1: Map
22 |
23 |
24 |
25 |
26 |
Let's start by building a example of placing items where a mouse or pointer is clicked: A map where you can place markers.
27 |
28 |
We can take the mouse co-ordinates and know where to position a created item. This will be a lot easier with Typed OM as we can use numbers and units rather than strings.
29 |
30 |
We'll have an image of a map and where we click on the map a marker will appear, to either represent somewhere we wish to go or have been, for example.
31 |
32 |
The focus here is on how we use Typed OM - so let's keep the HTML and CSS simple to start. We'll just have the map as an image and when we click an SVG will be added. We'll absolutely position each marker, with the top and left values being added based on mouse position on click.
33 |
34 |
Let's start with the HTML and CSS.
35 |
36 |
<div class="map">
37 | <figure class="map__image">
38 | <img src="world-map.jpg" alt="A picture of the map of the world" />
39 | <figcaption>Image from: https://mapswire.com/world/physical-maps/</figcaption>
40 | </figure>
41 | </div>
The SVG is an inverted arrow shape, so we'll place it at the tip where the mouse clicks. For this we'll need the width and height of the SVG, note in the function above we're creating CSSUnitValue's for both of these properties.
88 |
89 |
When the user clicks to place a marker, we need to calculate the top and left position values. For this we'll need the mouse coordinates, given to us by the click event, the maps position and the SVG's dimensions. Below is how we'll calculate the top value.
90 |
91 |
marker.top = new CSSUnitValue(e.clientY - mapEl.y - marker.width.value, 'px')
92 |
93 |
Using Typed OM, we can both create a CSSUnitValue and set it on the SVG image.
But what's going to happen if the window changes size. We've set absolute values. We are, however, working with numbers so we can set a percentage, rather than a pixel.
119 |
120 |
We'll create a ratio based on the dimensions of the map element and use that to create a percentage value instead of a pixel value for positioning.
The benefits of this are not just better typing and using less strings, but we can just set one position and not have to worry about calling any code on window resize.
167 |
168 |
169 |
170 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
--------------------------------------------------------------------------------
/sharedAssets/normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
2 |
3 | /* Document
4 | ========================================================================== */
5 |
6 | /**
7 | * 1. Correct the line height in all browsers.
8 | * 2. Prevent adjustments of font size after orientation changes in iOS.
9 | */
10 |
11 | html {
12 | line-height: 1.15; /* 1 */
13 | -webkit-text-size-adjust: 100%; /* 2 */
14 | }
15 |
16 | /* Sections
17 | ========================================================================== */
18 |
19 | /**
20 | * Remove the margin in all browsers.
21 | */
22 |
23 | body {
24 | margin: 0;
25 | }
26 |
27 | /**
28 | * Render the `main` element consistently in IE.
29 | */
30 |
31 | main {
32 | display: block;
33 | }
34 |
35 | /**
36 | * Correct the font size and margin on `h1` elements within `section` and
37 | * `article` contexts in Chrome, Firefox, and Safari.
38 | */
39 |
40 | h1 {
41 | font-size: 2em;
42 | margin: 0.67em 0;
43 | }
44 |
45 | /* Grouping content
46 | ========================================================================== */
47 |
48 | /**
49 | * 1. Add the correct box sizing in Firefox.
50 | * 2. Show the overflow in Edge and IE.
51 | */
52 |
53 | hr {
54 | box-sizing: content-box; /* 1 */
55 | height: 0; /* 1 */
56 | overflow: visible; /* 2 */
57 | }
58 |
59 | /**
60 | * 1. Correct the inheritance and scaling of font size in all browsers.
61 | * 2. Correct the odd `em` font sizing in all browsers.
62 | */
63 |
64 | pre {
65 | font-family: monospace, monospace; /* 1 */
66 | font-size: 1em; /* 2 */
67 | }
68 |
69 | /* Text-level semantics
70 | ========================================================================== */
71 |
72 | /**
73 | * Remove the gray background on active links in IE 10.
74 | */
75 |
76 | a {
77 | background-color: transparent;
78 | }
79 |
80 | /**
81 | * 1. Remove the bottom border in Chrome 57-
82 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
83 | */
84 |
85 | abbr[title] {
86 | border-bottom: none; /* 1 */
87 | text-decoration: underline; /* 2 */
88 | text-decoration: underline dotted; /* 2 */
89 | }
90 |
91 | /**
92 | * Add the correct font weight in Chrome, Edge, and Safari.
93 | */
94 |
95 | b,
96 | strong {
97 | font-weight: bolder;
98 | }
99 |
100 | /**
101 | * 1. Correct the inheritance and scaling of font size in all browsers.
102 | * 2. Correct the odd `em` font sizing in all browsers.
103 | */
104 |
105 | code,
106 | kbd,
107 | samp {
108 | font-family: monospace, monospace; /* 1 */
109 | font-size: 1em; /* 2 */
110 | }
111 |
112 | /**
113 | * Add the correct font size in all browsers.
114 | */
115 |
116 | small {
117 | font-size: 80%;
118 | }
119 |
120 | /**
121 | * Prevent `sub` and `sup` elements from affecting the line height in
122 | * all browsers.
123 | */
124 |
125 | sub,
126 | sup {
127 | font-size: 75%;
128 | line-height: 0;
129 | position: relative;
130 | vertical-align: baseline;
131 | }
132 |
133 | sub {
134 | bottom: -0.25em;
135 | }
136 |
137 | sup {
138 | top: -0.5em;
139 | }
140 |
141 | /* Embedded content
142 | ========================================================================== */
143 |
144 | /**
145 | * Remove the border on images inside links in IE 10.
146 | */
147 |
148 | img {
149 | border-style: none;
150 | }
151 |
152 | /* Forms
153 | ========================================================================== */
154 |
155 | /**
156 | * 1. Change the font styles in all browsers.
157 | * 2. Remove the margin in Firefox and Safari.
158 | */
159 |
160 | button,
161 | input,
162 | optgroup,
163 | select,
164 | textarea {
165 | font-family: inherit; /* 1 */
166 | font-size: 100%; /* 1 */
167 | line-height: 1.15; /* 1 */
168 | margin: 0; /* 2 */
169 | }
170 |
171 | /**
172 | * Show the overflow in IE.
173 | * 1. Show the overflow in Edge.
174 | */
175 |
176 | button,
177 | input { /* 1 */
178 | overflow: visible;
179 | }
180 |
181 | /**
182 | * Remove the inheritance of text transform in Edge, Firefox, and IE.
183 | * 1. Remove the inheritance of text transform in Firefox.
184 | */
185 |
186 | button,
187 | select { /* 1 */
188 | text-transform: none;
189 | }
190 |
191 | /**
192 | * Correct the inability to style clickable types in iOS and Safari.
193 | */
194 |
195 | button,
196 | [type="button"],
197 | [type="reset"],
198 | [type="submit"] {
199 | -webkit-appearance: button;
200 | }
201 |
202 | /**
203 | * Remove the inner border and padding in Firefox.
204 | */
205 |
206 | button::-moz-focus-inner,
207 | [type="button"]::-moz-focus-inner,
208 | [type="reset"]::-moz-focus-inner,
209 | [type="submit"]::-moz-focus-inner {
210 | border-style: none;
211 | padding: 0;
212 | }
213 |
214 | /**
215 | * Restore the focus styles unset by the previous rule.
216 | */
217 |
218 | button:-moz-focusring,
219 | [type="button"]:-moz-focusring,
220 | [type="reset"]:-moz-focusring,
221 | [type="submit"]:-moz-focusring {
222 | outline: 1px dotted ButtonText;
223 | }
224 |
225 | /**
226 | * Correct the padding in Firefox.
227 | */
228 |
229 | fieldset {
230 | padding: 0.35em 0.75em 0.625em;
231 | }
232 |
233 | /**
234 | * 1. Correct the text wrapping in Edge and IE.
235 | * 2. Correct the color inheritance from `fieldset` elements in IE.
236 | * 3. Remove the padding so developers are not caught out when they zero out
237 | * `fieldset` elements in all browsers.
238 | */
239 |
240 | legend {
241 | box-sizing: border-box; /* 1 */
242 | color: inherit; /* 2 */
243 | display: table; /* 1 */
244 | max-width: 100%; /* 1 */
245 | padding: 0; /* 3 */
246 | white-space: normal; /* 1 */
247 | }
248 |
249 | /**
250 | * Add the correct vertical alignment in Chrome, Firefox, and Opera.
251 | */
252 |
253 | progress {
254 | vertical-align: baseline;
255 | }
256 |
257 | /**
258 | * Remove the default vertical scrollbar in IE 10+.
259 | */
260 |
261 | textarea {
262 | overflow: auto;
263 | }
264 |
265 | /**
266 | * 1. Add the correct box sizing in IE 10.
267 | * 2. Remove the padding in IE 10.
268 | */
269 |
270 | [type="checkbox"],
271 | [type="radio"] {
272 | box-sizing: border-box; /* 1 */
273 | padding: 0; /* 2 */
274 | }
275 |
276 | /**
277 | * Correct the cursor style of increment and decrement buttons in Chrome.
278 | */
279 |
280 | [type="number"]::-webkit-inner-spin-button,
281 | [type="number"]::-webkit-outer-spin-button {
282 | height: auto;
283 | }
284 |
285 | /**
286 | * 1. Correct the odd appearance in Chrome and Safari.
287 | * 2. Correct the outline style in Safari.
288 | */
289 |
290 | [type="search"] {
291 | -webkit-appearance: textfield; /* 1 */
292 | outline-offset: -2px; /* 2 */
293 | }
294 |
295 | /**
296 | * Remove the inner padding in Chrome and Safari on macOS.
297 | */
298 |
299 | [type="search"]::-webkit-search-decoration {
300 | -webkit-appearance: none;
301 | }
302 |
303 | /**
304 | * 1. Correct the inability to style clickable types in iOS and Safari.
305 | * 2. Change font properties to `inherit` in Safari.
306 | */
307 |
308 | ::-webkit-file-upload-button {
309 | -webkit-appearance: button; /* 1 */
310 | font: inherit; /* 2 */
311 | }
312 |
313 | /* Interactive
314 | ========================================================================== */
315 |
316 | /*
317 | * Add the correct display in Edge, IE 10+, and Firefox.
318 | */
319 |
320 | details {
321 | display: block;
322 | }
323 |
324 | /*
325 | * Add the correct display in all browsers.
326 | */
327 |
328 | summary {
329 | display: list-item;
330 | }
331 |
332 | /* Misc
333 | ========================================================================== */
334 |
335 | /**
336 | * Add the correct display in IE 10+.
337 | */
338 |
339 | template {
340 | display: none;
341 | }
342 |
343 | /**
344 | * Add the correct display in IE 10.
345 | */
346 |
347 | [hidden] {
348 | display: none;
349 | }
--------------------------------------------------------------------------------
/typedOM/transformValue/02example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Transform Values Example | Typed OM
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
CSS Houdini Collection
21 |
Typed OM Transform Values Example
22 |
23 |
24 |
25 |
26 |
Now we have all this transform power, let's use it to create an example. It is Houdini after all. How about some magical sparkles.
27 |
28 |
We'll create some randomised SVG images, that appear when the mouse is dragged around an area. We can do all of this within javaScript.
Now let's create a Sparkle class, which creates the image and all it's randomised transforms. We can create new sparkles when the mouse moves around the area.
We'll look at the createImage() method later, first let's look at all the methods to define the position, rotation and scaling.
56 |
57 |
Each sparkle will be positioned absolutely based on the mouse coordinates, but offset slightly. We'll create a new CSSTranslateValue with the randomised offset.
We want the sparkle to fade over time, we can do this by creating an animation where the start opacity is 1 and the end opacity is 0, and making sure all sparkles have this animation. We can do most of this in the CSS
And finally we need the createImage() method, which creates an image element, set's it's source and other attributes and applies the styles we've created with the above methods.
This creates a new CSSMathValue with the operator type "sum". CSSMathValues always take CSSUnitValues. As you can see with what is created in the above example, CSSMathSum actually takes a CSSNumericArray which is an array of CSSNumericValues.
40 |
41 |
If we use the toString() method on a CSSMathValue, it returns the ready made calc() function as a string. Handy.
NB As with the previous part on numeric types, there is an associated javascript file which you can find here. It is logging code to the console which you can see in the developer tools pane.
47 |
48 |
Other CSSMathValue types that associate with the calc() function are 'sum', 'product', 'negate' and 'invert'. Each of the mathematical operations returns it's own interface. Here's an example of each them, how to create each, set() the value on an element and in turn get() that value to see the interface returned:
49 |
50 |
CSSMathSum
51 |
Addition & Subtraction. Values are of type CSSNumericValue and it takes a CSSNumericArray, so you can put in as many values as you want.
Negation. Only takes one CSSNumericValue. Note here how we have to use the aforementioned toString() method, as the type itself does not negate the value, it just specifies it is of negated type.
The calc() function is not the only mathematical function we have in CSS however, there is also the min(), max() and yet to be implemented clamp() functions. These all have their own CSSMathValue types. Let's take a look at creating each in turn, and what each interface contains.
In CSS you can nest any of the above functions: calc(), min() or max(). Consider the following CSS: min( calc(1.2em * 1.4), 10vw), to recreate this using CSSMathValues we would also need to nest them:
On the surface this could seem overly complex, however it makes sense and we have to remember it's the underlying information about these CSSValueTypes that is being exposed and we have access to. It might be a bit to take in at this point, but as support starts to advance and we gain familiarity with this API, we'll probably wonder how we ever managed without it.
A huge array of properties and values is returned. Let's take a closer look at those values. They are all of type CSSStyleValue — let's retrieve some values using the get() method, which comes with computedStyleMap().
29 |
30 |
CSSStyleValue has sub classes, depending on the type of value you use for the defined property. Let's take a look at them.
31 |
32 |
33 |
CSSStyleValue
34 |
Parent class for all values set on an element.
35 |
This class holds the parse and parseAll methods, which we will look at a bit later. Before we do that, let's take a look at all the sub classes.
36 |
37 |
38 |
39 |
CSSKeywordValue
40 |
Class that defines things like keywords (see the list here) — e.g. inherit, initial, unset, and anything you don't quote such as auto, grid etc...
At the time of writing this is yet to be implemented - the spec only holds the CSSImageValue type as it's needed for the CSS Paint API. This will be expanded on in future versions: cssImageValue.value
60 |
61 |
console.log(cssImageValue.value);
62 | // Logs:
63 |
64 |
65 |
66 |
CSSNumericValue
67 |
Returned when the value is numeric. This is a superclass from which CSSUnitValue and CSSMathSum are derived, so one of these will be returned instead, depending on whether the value is determined via the calc(), min(), max() function or not.
With this type we can access the calculation that has occurred, as well as units involved in that calculation. These are returned as an array of CSSUnitValues
91 |
let units = ''
92 |
93 | for (const unit of cssMathSum.values) {
94 | units += ` value: ${unit.value}, unit: ${unit.unit}`;
95 | }
96 |
97 | console.log(`Operator: ${cssMathSum.operator}, | Values: ${units}`)
98 | // Logs:
99 |
100 |
101 |
102 |
CSSTransformValue
103 |
If a transform value is used, this type is returned.
Returns a list of all the different transforms applied to the element and their different values. The transform determines what is returned. In our example here we just have a scale applied.
This returns any values of a custom property that could be set or affect said element. Here we're specifying which property we want.
128 |
129 |
console.log(cssUnparseValue[0]);
130 | // Logs:
131 |
132 |
133 |
134 |
CSSVariableReferenceValue
135 |
136 |
If we want to create a custom property, rather than just retrieve its value, we would use the CSSVariableReferenceValue type. This is not returned, as you can use any value with a custom property when setting it, however it can be defined when created. The value we enter here needs to be of type CSSUnparsedValue.
There's more about creating properties and values using these types in the next section.
145 |
146 |
147 |
148 |
Parsing Properties & Values
149 |
150 |
We can parse CSSUnparsedValue object instances with a couple of methods we get with the CSSStyleValue type: parse() and parseAll(). As it's a numeric value we'll use the CSSNumericValue.parse() method on the value. Let's take a look:
These are all of the types we will get to work with, and there are more to come as well. Not only do we have better access to CSS value information, we also have better ways of setting and retrieving styles on an element. Let's take a look in part three.
Here we'll take a more in depth look at the CSSNumericValue type. As we've seen it's the super class for both the CSSUnitValue and CSSMathValue.
27 |
28 |
Let's start by looking at the CSSUnitValue, the different types of units there are and different ways to create them.
29 |
30 |
Before we do that, let's refresh what's returned if a value is of type CSSunitValue
31 |
32 |
NB Due to the nature of code examples on this page, the javascript file is logging results to the console, (rather than affecting an element as in the intro), so you can view the code running in the developer tools pane and you can find the javascript file here
Here we are setting a line-height value on an h2 element and retrieving it again with the set() and get() methods of the attributeStyleMap property.
44 |
45 |
A CSSUnitValue is returned, which contains a value and a unit. Here the unit is of type 'number'. Let's see how we create a CSSUnitValue and while we're at it a couple of different unit types.
46 |
47 |
Creating a unit value
48 |
49 |
There are two ways to do this. The first is to create the object directly:
In the examples above we've seen number, percent and length type units. There are also angle, time, frequency, resolution and flex; eight altogether. Here's a list of all the units, sorted by type, with examples of how to create them with both methods.
72 |
73 |
NB Remember you can use a string instead of a number in any of these examples.
NB These only create numeric values. If, for instance, you wanted to create a flex: auto; CSS syntax you would need to use the CSSKeywordVaue type instead.
305 |
306 |
There's a lot of different unit types, but it makes sense they are all implemented. Now let's see the other CSSNumericValue sub class: CSSMathValuein the next section.