CINXE.COM
CSS Will Change Module Level 1
<!doctype html><html lang="en"> <head> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport"> <title>CSS Will Change Module Level 1</title> <meta content="ED" name="w3c-status"> <link href="https://www.w3.org/StyleSheets/TR/2021/W3C-ED" rel="stylesheet"> <meta content="Bikeshed version 742f3d674, updated Mon Nov 4 14:56:54 2024 -0800" name="generator"> <link href="https://www.w3.org/TR/css-will-change/" rel="canonical"> <link href="https://drafts.csswg.org/csslogo.ico" rel="icon"> <meta content="49d415561d0e925d133b99cc57c698ee24150a66" name="revision"> <meta content="dark light" name="color-scheme"> <link href="https://www.w3.org/StyleSheets/TR/2021/dark.css" media="(prefers-color-scheme: dark)" rel="stylesheet" type="text/css"> <style>/* Boilerplate: style-autolinks */ .css.css, .property.property, .descriptor.descriptor { color: var(--a-normal-text); font-size: inherit; font-family: inherit; } .css::before, .property::before, .descriptor::before { content: "‘"; } .css::after, .property::after, .descriptor::after { content: "’"; } .property, .descriptor { /* Don't wrap property and descriptor names */ white-space: nowrap; } .type { /* CSS value <type> */ font-style: italic; } pre .property::before, pre .property::after { content: ""; } [data-link-type="property"]::before, [data-link-type="propdesc"]::before, [data-link-type="descriptor"]::before, [data-link-type="value"]::before, [data-link-type="function"]::before, [data-link-type="at-rule"]::before, [data-link-type="selector"]::before, [data-link-type="maybe"]::before { content: "‘"; } [data-link-type="property"]::after, [data-link-type="propdesc"]::after, [data-link-type="descriptor"]::after, [data-link-type="value"]::after, [data-link-type="function"]::after, [data-link-type="at-rule"]::after, [data-link-type="selector"]::after, [data-link-type="maybe"]::after { content: "’"; } [data-link-type].production::before, [data-link-type].production::after, .prod [data-link-type]::before, .prod [data-link-type]::after { content: ""; } [data-link-type=element], [data-link-type=element-attr] { font-family: Menlo, Consolas, "DejaVu Sans Mono", monospace; font-size: .9em; } [data-link-type=element]::before { content: "<" } [data-link-type=element]::after { content: ">" } [data-link-type=biblio] { white-space: pre; } @media (prefers-color-scheme: dark) { :root { --selflink-text: black; --selflink-bg: silver; --selflink-hover-text: white; } } </style> <style>/* Boilerplate: style-colors */ /* Any --*-text not paired with a --*-bg is assumed to have a transparent bg */ :root { color-scheme: light dark; --text: black; --bg: white; --unofficial-watermark: url(https://www.w3.org/StyleSheets/TR/2016/logos/UD-watermark); --logo-bg: #1a5e9a; --logo-active-bg: #c00; --logo-text: white; --tocnav-normal-text: #707070; --tocnav-normal-bg: var(--bg); --tocnav-hover-text: var(--tocnav-normal-text); --tocnav-hover-bg: #f8f8f8; --tocnav-active-text: #c00; --tocnav-active-bg: var(--tocnav-normal-bg); --tocsidebar-text: var(--text); --tocsidebar-bg: #f7f8f9; --tocsidebar-shadow: rgba(0,0,0,.1); --tocsidebar-heading-text: hsla(203,20%,40%,.7); --toclink-text: var(--text); --toclink-underline: #3980b5; --toclink-visited-text: var(--toclink-text); --toclink-visited-underline: #054572; --heading-text: #005a9c; --hr-text: var(--text); --algo-border: #def; --del-text: red; --del-bg: transparent; --ins-text: #080; --ins-bg: transparent; --a-normal-text: #034575; --a-normal-underline: #bbb; --a-visited-text: var(--a-normal-text); --a-visited-underline: #707070; --a-hover-bg: rgba(75%, 75%, 75%, .25); --a-active-text: #c00; --a-active-underline: #c00; --blockquote-border: silver; --blockquote-bg: transparent; --blockquote-text: currentcolor; --issue-border: #e05252; --issue-bg: #fbe9e9; --issue-text: var(--text); --issueheading-text: #831616; --example-border: #e0cb52; --example-bg: #fcfaee; --example-text: var(--text); --exampleheading-text: #574b0f; --note-border: #52e052; --note-bg: #e9fbe9; --note-text: var(--text); --noteheading-text: hsl(120, 70%, 30%); --notesummary-underline: silver; --assertion-border: #aaa; --assertion-bg: #eee; --assertion-text: black; --advisement-border: orange; --advisement-bg: #fec; --advisement-text: var(--text); --advisementheading-text: #b35f00; --warning-border: red; --warning-bg: hsla(40,100%,50%,0.95); --warning-text: var(--text); --amendment-border: #330099; --amendment-bg: #F5F0FF; --amendment-text: var(--text); --amendmentheading-text: #220066; --def-border: #8ccbf2; --def-bg: #def; --def-text: var(--text); --defrow-border: #bbd7e9; --datacell-border: silver; --indexinfo-text: #707070; --indextable-hover-text: black; --indextable-hover-bg: #f7f8f9; --outdatedspec-bg: rgba(0, 0, 0, .5); --outdatedspec-text: black; --outdated-bg: maroon; --outdated-text: white; --outdated-shadow: red; --editedrec-bg: darkorange; } @media (prefers-color-scheme: dark) { :root { --text: #ddd; --bg: black; --unofficial-watermark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cg fill='%23100808' transform='translate(200 200) rotate(-45) translate(-200 -200)' stroke='%23100808' stroke-width='3'%3E%3Ctext x='50%25' y='220' style='font: bold 70px sans-serif; text-anchor: middle; letter-spacing: 6px;'%3EUNOFFICIAL%3C/text%3E%3Ctext x='50%25' y='305' style='font: bold 70px sans-serif; text-anchor: middle; letter-spacing: 6px;'%3EDRAFT%3C/text%3E%3C/g%3E%3C/svg%3E"); --logo-bg: #1a5e9a; --logo-active-bg: #c00; --logo-text: white; --tocnav-normal-text: #999; --tocnav-normal-bg: var(--bg); --tocnav-hover-text: var(--tocnav-normal-text); --tocnav-hover-bg: #080808; --tocnav-active-text: #f44; --tocnav-active-bg: var(--tocnav-normal-bg); --tocsidebar-text: var(--text); --tocsidebar-bg: #080808; --tocsidebar-shadow: rgba(255,255,255,.1); --tocsidebar-heading-text: hsla(203,20%,40%,.7); --toclink-text: var(--text); --toclink-underline: #6af; --toclink-visited-text: var(--toclink-text); --toclink-visited-underline: #054572; --heading-text: #8af; --hr-text: var(--text); --algo-border: #456; --del-text: #f44; --del-bg: transparent; --ins-text: #4a4; --ins-bg: transparent; --a-normal-text: #6af; --a-normal-underline: #555; --a-visited-text: var(--a-normal-text); --a-visited-underline: var(--a-normal-underline); --a-hover-bg: rgba(25%, 25%, 25%, .2); --a-active-text: #f44; --a-active-underline: var(--a-active-text); --borderedblock-bg: rgba(255, 255, 255, .05); --blockquote-border: silver; --blockquote-bg: var(--borderedblock-bg); --blockquote-text: currentcolor; --issue-border: #e05252; --issue-bg: var(--borderedblock-bg); --issue-text: var(--text); --issueheading-text: hsl(0deg, 70%, 70%); --example-border: hsl(50deg, 90%, 60%); --example-bg: var(--borderedblock-bg); --example-text: var(--text); --exampleheading-text: hsl(50deg, 70%, 70%); --note-border: hsl(120deg, 100%, 35%); --note-bg: var(--borderedblock-bg); --note-text: var(--text); --noteheading-text: hsl(120, 70%, 70%); --notesummary-underline: silver; --assertion-border: #444; --assertion-bg: var(--borderedblock-bg); --assertion-text: var(--text); --advisement-border: orange; --advisement-bg: #222218; --advisement-text: var(--text); --advisementheading-text: #f84; --warning-border: red; --warning-bg: hsla(40,100%,20%,0.95); --warning-text: var(--text); --amendment-border: #330099; --amendment-bg: #080010; --amendment-text: var(--text); --amendmentheading-text: #cc00ff; --def-border: #8ccbf2; --def-bg: #080818; --def-text: var(--text); --defrow-border: #136; --datacell-border: silver; --indexinfo-text: #aaa; --indextable-hover-text: var(--text); --indextable-hover-bg: #181818; --outdatedspec-bg: rgba(255, 255, 255, .5); --outdatedspec-text: black; --outdated-bg: maroon; --outdated-text: white; --outdated-shadow: red; --editedrec-bg: darkorange; } /* In case a transparent-bg image doesn't expect to be on a dark bg, which is quite common in practice... */ img { background: white; } } </style> <style>/* Boilerplate: style-counters */ body { counter-reset: example figure issue; } .issue { counter-increment: issue; } .issue:not(.no-marker)::before { content: "Issue " counter(issue); } .example { counter-increment: example; } .example:not(.no-marker)::before { content: "Example " counter(example); } .invalid.example:not(.no-marker)::before, .illegal.example:not(.no-marker)::before { content: "Invalid Example" counter(example); } figcaption { counter-increment: figure; } figcaption:not(.no-marker)::before { content: "Figure " counter(figure) " "; } </style> <style>/* Boilerplate: style-dfn-panel */ :root { --dfnpanel-bg: #ddd; --dfnpanel-text: var(--text); --dfnpanel-target-bg: #ffc; --dfnpanel-target-outline: orange; } @media (prefers-color-scheme: dark) { :root { --dfnpanel-bg: #222; --dfnpanel-text: var(--text); --dfnpanel-target-bg: #333; --dfnpanel-target-outline: silver; } } .dfn-panel { position: absolute; z-index: 35; width: 20em; width: 300px; height: auto; max-height: 500px; overflow: auto; padding: 0.5em 0.75em; font: small Helvetica Neue, sans-serif, Droid Sans Fallback; background: var(--dfnpanel-bg); color: var(--dfnpanel-text); border: outset 0.2em; white-space: normal; /* in case it's moved into a pre */ } .dfn-panel:not(.on) { display: none; } .dfn-panel * { margin: 0; padding: 0; text-indent: 0; } .dfn-panel > b { display: block; } .dfn-panel a { color: var(--dfnpanel-text); } .dfn-panel a:not(:hover) { text-decoration: none !important; border-bottom: none !important; } .dfn-panel a:focus { outline: 5px auto Highlight; outline: 5px auto -webkit-focus-ring-color; } .dfn-panel > b + b { margin-top: 0.25em; } .dfn-panel ul { padding: 0 0 0 1em; list-style: none; } .dfn-panel li a { max-width: calc(300px - 1.5em - 1em); overflow: hidden; text-overflow: ellipsis; } .dfn-panel.activated { display: inline-block; position: fixed; left: 8px; bottom: 2em; margin: 0 auto; max-width: calc(100vw - 1.5em - .4em - .5em); max-height: 30vh; transition: left 1s ease-out, bottom 1s ease-out; } .dfn-panel .link-item:hover { text-decoration: underline; } .dfn-panel .link-item .copy-icon { opacity: 0; } .dfn-panel .link-item:hover .copy-icon, .dfn-panel .link-item .copy-icon:focus { opacity: 1; } .dfn-panel .copy-icon { display: inline-block; margin-right: 0.5em; width: 0.85em; height: 1em; border-radius: 3px; background-color: #ccc; cursor: pointer; } .dfn-panel .copy-icon .icon { width: 100%; height: 100%; background-color: #fff; display: flex; justify-content: center; align-items: center; position: relative; } .dfn-panel .copy-icon .icon::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 1px solid black; background-color: #ccc; opacity: 0.25; transform: translate(3px, -3px); } .dfn-panel .copy-icon:active .icon::before { opacity: 1; } .dfn-paneled[role="button"] { cursor: help; } .highlighted { animation: target-fade 3s; } @keyframes target-fade { from { background-color: var(--dfnpanel-target-bg); outline: 5px solid var(--dfnpanel-target-outline); } to { color: var(--a-normal-text); background-color: transparent; outline: transparent; } } </style> <style>/* Boilerplate: style-issues */ a[href].issue-return { float: right; float: inline-end; color: var(--issueheading-text); font-weight: bold; text-decoration: none; } </style> <style>/* Boilerplate: style-md-lists */ /* This is a weird hack for me not yet following the commonmark spec regarding paragraph and lists. */ [data-md] > :first-child { margin-top: 0; } [data-md] > :last-child { margin-bottom: 0; } </style> <style>/* Boilerplate: style-mdn-anno */ :root { --mdn-bg: #EEE; --mdn-shadow: #999; --mdn-nosupport-text: #ccc; --mdn-pass: green; --mdn-fail: red; } @media (prefers-color-scheme: dark) { :root { --mdn-bg: #222; --mdn-shadow: #444; --mdn-nosupport-text: #666; --mdn-pass: #690; --mdn-fail: #d22; } } .mdn-anno { background: var(--mdn-bg, #EEE); border-radius: .25em; box-shadow: 0 0 3px var(--mdn-shadow, #999); color: var(--text, black); font: 1em sans-serif; hyphens: none; max-width: min-content; overflow: hidden; padding: 0.2em; position: absolute; right: 0.3em; top: auto; white-space: nowrap; word-wrap: normal; z-index: 8; } .mdn-anno.unpositioned { display: none; } .mdn-anno.overlapping-main { opacity: .2; transition: opacity .1s; } .mdn-anno[open] { opacity: 1; z-index: 9; min-width: 9em; } .mdn-anno:hover { opacity: 1; outline: var(--text, black) 1px solid; } .mdn-anno > summary { font-weight: normal; text-align: right; cursor: pointer; display: block; } .mdn-anno > summary > .less-than-two-engines-flag { color: var(--mdn-fail); padding-right: 2px; } .mdn-anno > summary > .all-engines-flag { color: var(--mdn-pass); padding-right: 2px; } .mdn-anno > summary > span { color: #fff; background-color: #000; font-weight: normal; font-family: zillaslab, Palatino, "Palatino Linotype", serif; padding: 2px 3px 0px 3px; line-height: 1.3em; vertical-align: top; } .mdn-anno > .feature { margin-top: 20px; } .mdn-anno > .feature:not(:first-of-type) { border-top: 1px solid #999; margin-top: 6px; padding-top: 2px; } .mdn-anno > .feature > .less-than-two-engines-text { color: var(--mdn-fail); } .mdn-anno > .feature > .all-engines-text { color: var(--mdn-pass); } .mdn-anno > .feature > p { font-size: .75em; margin-top: 6px; margin-bottom: 0; } .mdn-anno > .feature > p + p { margin-top: 3px; } .mdn-anno > .feature > .support { display: block; font-size: 0.6em; margin: 0; padding: 0; margin-top: 2px; } .mdn-anno > .feature > .support + div { padding-top: 0.5em; } .mdn-anno > .feature > .support > hr { display: block; border: none; border-top: 1px dotted #999; padding: 3px 0px 0px 0px; margin: 2px 3px 0px 3px; } .mdn-anno > .feature > .support > hr::before { content: ""; } .mdn-anno > .feature > .support > span { padding: 0.2em 0; display: block; display: table; } .mdn-anno > .feature > .support > span.no { color: var(--mdn-nosupport-text); filter: grayscale(100%); } .mdn-anno > .feature > .support > span.no::before { opacity: 0.5; } .mdn-anno > .feature > .support > span:first-of-type { padding-top: 0.5em; } .mdn-anno > .feature > .support > span > span { padding: 0 0.5em; display: table-cell; } .mdn-anno > .feature > .support > span > span:first-child { width: 100%; } .mdn-anno > .feature > .support > span > span:last-child { width: 100%; white-space: pre; padding: 0; } .mdn-anno > .feature > .support > span::before { content: ' '; display: table-cell; min-width: 1.5em; height: 1.5em; background: no-repeat center center; background-size: contain; text-align: right; font-size: 0.75em; font-weight: bold; } .mdn-anno > .feature > .support > .chrome_android::before { background-image: url(https://resources.whatwg.org/browser-logos/chrome.svg); } .mdn-anno > .feature > .support > .firefox_android::before { background-image: url(https://resources.whatwg.org/browser-logos/firefox.png); } .mdn-anno > .feature > .support > .chrome::before { background-image: url(https://resources.whatwg.org/browser-logos/chrome.svg); } .mdn-anno > .feature > .support > .edge_blink::before { background-image: url(https://resources.whatwg.org/browser-logos/edge.svg); } .mdn-anno > .feature > .support > .edge::before { background-image: url(https://resources.whatwg.org/browser-logos/edge_legacy.svg); } .mdn-anno > .feature > .support > .firefox::before { background-image: url(https://resources.whatwg.org/browser-logos/firefox.png); } .mdn-anno > .feature > .support > .ie::before { background-image: url(https://resources.whatwg.org/browser-logos/ie.png); } .mdn-anno > .feature > .support > .safari_ios::before { background-image: url(https://resources.whatwg.org/browser-logos/safari-ios.svg); } .mdn-anno > .feature > .support > .nodejs::before { background-image: url(https://nodejs.org/static/images/favicons/favicon.ico); } .mdn-anno > .feature > .support > .opera_android::before { background-image: url(https://resources.whatwg.org/browser-logos/opera.svg); } .mdn-anno > .feature > .support > .opera::before { background-image: url(https://resources.whatwg.org/browser-logos/opera.svg); } .mdn-anno > .feature > .support > .safari::before { background-image: url(https://resources.whatwg.org/browser-logos/safari.png); } .mdn-anno > .feature > .support > .samsunginternet_android::before { background-image: url(https://resources.whatwg.org/browser-logos/samsung.svg); } .mdn-anno > .feature > .support > .webview_android::before { background-image: url(https://resources.whatwg.org/browser-logos/android-webview.png); } .name-slug-mismatch { color: red; } .caniuse-status:hover { z-index: 9; } /* dt, li, .issue, .note, and .example are "position: relative", so to put annotation at right margin, must move to right of containing block */; .h-entry:not(.status-LS) dt > .mdn-anno, .h-entry:not(.status-LS) li > .mdn-anno, .h-entry:not(.status-LS) .issue > .mdn-anno, .h-entry:not(.status-LS) .note > .mdn-anno, .h-entry:not(.status-LS) .example > .mdn-anno { right: -6.7em; } .h-entry p + .mdn-anno { margin-top: 0; } h2 + .mdn-anno.after { margin: -48px 0 0 0; } h3 + .mdn-anno.after { margin: -46px 0 0 0; } h4 + .mdn-anno.after { margin: -42px 0 0 0; } h5 + .mdn-anno.after { margin: -40px 0 0 0; } h6 + .mdn-anno.after { margin: -40px 0 0 0; } </style> <style>/* Boilerplate: style-ref-hints */ :root { --ref-hint-bg: #ddd; --ref-hint-text: var(--text); } @media (prefers-color-scheme: dark) { :root { --ref-hint-bg: #222; --ref-hint-text: var(--text); } } .ref-hint { display: inline-block; position: absolute; z-index: 35; width: 20em; width: 300px; height: auto; max-height: 500px; overflow: auto; padding: 0.5em 0.5em; font: small Helvetica Neue, sans-serif, Droid Sans Fallback; background: var(--ref-hint-bg); color: var(--ref-hint-text); border: outset 0.2em; white-space: normal; /* in case it's moved into a pre */ } .ref-hint * { margin: 0; padding: 0; text-indent: 0; } .ref-hint ul { padding: 0 0 0 1em; list-style: none; } </style> <style>/* Boilerplate: style-selflinks */ :root { --selflink-text: white; --selflink-bg: gray; --selflink-hover-text: black; } .heading, .issue, .note, .example, li, dt { position: relative; } a.self-link { position: absolute; top: 0; left: calc(-1 * (3.5rem - 26px)); width: calc(3.5rem - 26px); height: 2em; text-align: center; border: none; transition: opacity .2s; opacity: .5; } a.self-link:hover { opacity: 1; } .heading > a.self-link { font-size: 83%; } .example > a.self-link, .note > a.self-link, .issue > a.self-link { /* These blocks are overflow:auto, so positioning outside doesn't work. */ left: auto; right: 0; } li > a.self-link { left: calc(-1 * (3.5rem - 26px) - 2em); } dfn > a.self-link { top: auto; left: auto; opacity: 0; width: 1.5em; height: 1.5em; background: var(--selflink-bg); color: var(--selflink-text); font-style: normal; transition: opacity .2s, background-color .2s, color .2s; } dfn:hover > a.self-link { opacity: 1; } dfn > a.self-link:hover { color: var(--selflink-hover-text); } a.self-link::before { content: "¶"; } .heading > a.self-link::before { content: "§"; } dfn > a.self-link::before { content: "#"; } </style> <style>/* Boilerplate: style-wpt */ :root { --wpt-border: hsl(0, 0%, 60%); --wpt-bg: hsl(0, 0%, 95%); --wpt-text: var(--text); --wptheading-text: hsl(0, 0%, 30%); } @media (prefers-color-scheme: dark) { :root { --wpt-border: hsl(0, 0%, 30%); --wpt-bg: var(--borderedblock-bg); --wpt-text: var(--text); --wptheading-text: hsl(0, 0%, 60%); } } .wpt-tests-block { list-style: none; border-left: .5em solid var(--wpt-border); background: var(--wpt-bg); color: var(--wpt-text); margin: 1em auto; padding: .5em; } .wpt-tests-block summary { color: var(--wptheading-text); font-weight: normal; text-transform: uppercase; } .wpt-tests-block summary::marker{ color: var(--wpt-border); } .wpt-tests-block summary:hover::marker{ color: var(--wpt-text); } /* The only content of a wpt test block in its closed state is the <summary>, which contains the word TESTS, and that is absolutely positioned. In that closed state, wpt test blocks are styled to have a top margin whose height is exactly equal to the height of the absolutely positioned <summary>, and no other background/padding/margin/border. The wpt test block elements will therefore allow the maring of the previous/next block elements to collapse through them; if this combined margin would be larger than its own top margin, it stays as is, and therefore the pre-existing vertical rhythm of the document is undisturbed. If that combined margin would be smaller, it is grown to that size. This means that the wpt test block ensures that there's always enough vertical space to insert the summary, without adding more than is needed. */ .wpt-tests-block:not([open]){ padding: 0; border: none; background: none; font-size: 0.75em; line-height: 1; position: relative; margin: 1em 0 0; } .wpt-tests-block:not([open]) summary { position: absolute; right: 0; bottom: 0; } /* It is possible that both the last child of a block element and the block element itself would be annotated with a <wpt> block each. If the block element has a padding or a border, that's fine, but otherwise the bottom margin of the block and of its last child would collapse and both <wpt> elements would overlap, being both placed there. To avoid that, add 1px of padding to the <wpt> element annotating the last child to prevent the bottom margin of the block and of its last child from collapsing (and as much negative margin, as wel only want to prevent margin collapsing, but are not trying to actually take more space). */ .wpt-tests-block:not([open]):last-child { padding-bottom: 1px; margin-bottom: -1px; } /* Exception to the previous rule: don't do that in non-last list items, because it's not necessary, and would therefore consume more space than strictly needed. Lists must have list items as children, not <wpt> elements, so a <wpt> element cannot be a sibling of a list item, and the collision that the previous rule avoids cannot happen. */ li:not(:last-child) > .wpt-tests-block:not([open]):last-child, dd:not(:last-child) > .wpt-tests-block:not([open]):last-child { padding-bottom: 0; margin-bottom: 0; } .wpt-tests-block:not([open]):not(:hover){ opacity: 0.5; } .wpt-tests-list { list-style: none; display: grid; margin: 0; padding: 0; grid-template-columns: 1fr max-content auto auto; grid-column-gap: .5em; } .wpt-tests-block hr:last-child { display: none; } .wpt-test { display: contents; } .wpt-test > a { text-decoration: underline; border: none; } .wpt-test > .wpt-name { grid-column: 1; } .wpt-test > .wpt-results { grid-column: 2; } .wpt-test > .wpt-live { grid-column: 3; } .wpt-test > .wpt-source { grid-column: 4; } .wpt-test > .wpt-results { display: flex; gap: .1em; } .wpt-test .wpt-result { display: inline-block; height: 1em; width: 1em; border-radius: 50%; position: relative; } </style> <body class="h-entry"> <div class="head"> <p data-fill-with="logo"><a class="logo" href="https://www.w3.org/"> <img alt="W3C" height="48" src="https://www.w3.org/StyleSheets/TR/2021/logos/W3C" width="72"> </a> </p> <h1 class="p-name no-ref" id="title">CSS Will Change Module Level 1</h1> <p id="w3c-state"><a href="https://www.w3.org/standards/types/#ED">Editor’s Draft</a>, <time class="dt-updated" datetime="2022-04-29">29 April 2022</time></p> <details open> <summary>More details about this document</summary> <div data-fill-with="spec-metadata"> <dl> <dt>This version: <dd><a class="u-url" href="https://drafts.csswg.org/css-will-change/">https://drafts.csswg.org/css-will-change/</a> <dt>Latest published version: <dd><a href="https://www.w3.org/TR/css-will-change/">https://www.w3.org/TR/css-will-change/</a> <dt>Previous Versions: <dd><a href="https://www.w3.org/TR/2022/CRD-css-will-change-1-20220505/" rel="prev">https://www.w3.org/TR/2022/CRD-css-will-change-1-20220505/</a> <dd><a href="https://www.w3.org/TR/2015/CR-css-will-change-1-20151203/" rel="prev">https://www.w3.org/TR/2015/CR-css-will-change-1-20151203/</a> <dd><a href="https://www.w3.org/TR/2014/WD-css-will-change-1-20140429/" rel="prev">https://www.w3.org/TR/2014/WD-css-will-change-1-20140429/</a> <dt>Implementation Report: <dd><a href="https://wpt.fyi/results/css/css-will-change">https://wpt.fyi/results/css/css-will-change</a> <dt>Test Suite: <dd><a href="https://wpt.fyi/results/css/css-will-change">https://wpt.fyi/results/css/css-will-change</a> <dt>Feedback: <dd><a href="https://github.com/w3c/csswg-drafts/labels/css-will-change-1">CSSWG Issues Repository</a> <dt class="editor">Editor: <dd class="editor p-author h-card vcard" data-editor-id="42199"><a class="p-name fn u-url url" href="http://xanthir.com/contact/">Tab Atkins Jr.</a> (<span class="p-org org">Google</span>) <dt>Suggest an Edit for this Spec: <dd><a href="https://github.com/w3c/csswg-drafts/blob/main/css-will-change-1/Overview.bs">GitHub Editor</a> </dl> </div> </details> <div data-fill-with="warning"></div> <p class="copyright" data-fill-with="copyright"><a href="https://www.w3.org/policies/#copyright">Copyright</a> © 2022 <a href="https://www.w3.org/">World Wide Web Consortium</a>. <abbr title="World Wide Web Consortium">W3C</abbr><sup>®</sup> <a href="https://www.w3.org/policies/#Legal_Disclaimer">liability</a>, <a href="https://www.w3.org/policies/#W3C_Trademarks">trademark</a> and <a href="https://www.w3.org/copyright/software-license/" rel="license" title="W3C Software and Document License">permissive document license</a> rules apply. </p> <hr title="Separator for header"> </div> <div class="p-summary" data-fill-with="abstract"> <h2 class="no-num no-toc no-ref heading settled" id="abstract"><span class="content">Abstract</span></h2> <p>This document defines the <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change">will-change</a> CSS property, which allows an author to inform the UA ahead of time of what kinds of changes they are likely to make to an element. This allows the UA to optimize how they handle the element ahead of time, performing potentially-expensive work preparing for an animation before the animation actually begins.</p> <a href="https://www.w3.org/TR/CSS/">CSS</a> is a language for describing the rendering of structured documents (such as HTML and XML) on screen, on paper, etc. <script> const githubPrefix = "https://w3c.github.io/csswg-drafts/"; if(location.href.slice(0, githubPrefix.length) == githubPrefix) { const suffix = location.href.slice(githubPrefix.length); const draftUrl = "https://drafts.csswg.org/" + suffix; window.location.replace(draftUrl); } </script> </div> <h2 class="no-num no-toc no-ref heading settled" id="sotd"><span class="content">Status of this document</span></h2> <div data-fill-with="status"> <p> This is a public copy of the editors’ draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C. Don’t cite this document other than as work in progress. </p> <p>Please send feedback by <a href="https://github.com/w3c/csswg-drafts/issues">filing issues in GitHub</a> (preferred), including the spec code “css-will-change” in the title, like this: “[css-will-change] <i>…summary of comment…</i>”. All issues and comments are <a href="https://lists.w3.org/Archives/Public/public-css-archive/">archived</a>. Alternately, feedback can be sent to the (<a href="https://lists.w3.org/Archives/Public/www-style/">archived</a>) public mailing list <a href="mailto:www-style@w3.org?Subject=%5Bcss-will-change%5D%20PUT%20SUBJECT%20HERE">www-style@w3.org</a>. </p> <p>This document is governed by the <a href="https://www.w3.org/policies/process/20231103/" id="w3c_process_revision">03 November 2023 W3C Process Document</a>. </p> <p></p> </div> <div data-fill-with="at-risk"></div> <nav data-fill-with="table-of-contents" id="toc"> <h2 class="no-num no-toc no-ref" id="contents">Table of Contents</h2> <ol class="toc" role="directory"> <li> <a href="#intro"><span class="secno">1</span> <span class="content"> Introduction</span></a> <ol class="toc"> <li><a href="#values"><span class="secno">1.1</span> <span class="content"> Value Definitions</span></a> <li><a href="#using"><span class="secno">1.2</span> <span class="content"> Using <span class="property">will-change</span> Well</span></a> </ol> <li><a href="#will-change"><span class="secno">2</span> <span class="content"> Hinting at Future Behavior: the <span class="property">will-change</span> property</span></a> <li><a href="#security"><span class="secno">3</span> <span class="content">Security Considerations</span></a> <li><a href="#privacy"><span class="secno">4</span> <span class="content">Privacy Considerations</span></a> <li><a href="#acks"><span class="secno">5</span> <span class="content">Acknowledgements</span></a> <li><a href="#changes"><span class="secno">6</span> <span class="content">Changes</span></a> <li> <a href="#w3c-conformance"><span class="secno"></span> <span class="content"> Conformance</span></a> <ol class="toc"> <li><a href="#w3c-conventions"><span class="secno"></span> <span class="content"> Document conventions</span></a> <li><a href="#w3c-conformance-classes"><span class="secno"></span> <span class="content"> Conformance classes</span></a> <li> <a href="#w3c-partial"><span class="secno"></span> <span class="content"> Partial implementations</span></a> <ol class="toc"> <li><a href="#w3c-conform-future-proofing"><span class="secno"></span> <span class="content"> Implementations of Unstable and Proprietary Features</span></a> </ol> <li><a href="#w3c-testing"><span class="secno"></span> <span class="content"> Non-experimental implementations</span></a> </ol> <li> <a href="#index"><span class="secno"></span> <span class="content">Index</span></a> <ol class="toc"> <li><a href="#index-defined-here"><span class="secno"></span> <span class="content">Terms defined by this specification</span></a> <li><a href="#index-defined-elsewhere"><span class="secno"></span> <span class="content">Terms defined by reference</span></a> </ol> <li> <a href="#references"><span class="secno"></span> <span class="content">References</span></a> <ol class="toc"> <li><a href="#normative"><span class="secno"></span> <span class="content">Normative References</span></a> <li><a href="#informative"><span class="secno"></span> <span class="content">Informative References</span></a> </ol> <li><a href="#property-index"><span class="secno"></span> <span class="content">Property Index</span></a> </ol> </nav> <main> <h2 class="heading settled" data-level="1" id="intro"><span class="secno">1. </span><span class="content"> Introduction</span><a class="self-link" href="#intro"></a></h2> <p>Modern CSS renderers perform a number of complex optimizations in order to render webpages quickly and efficiently. Unfortunately, employing these optimizations often has a non-trivial start-up cost, which can have a negative impact on the responsiveness of a page.</p> <div class="example" id="example-d1b18fd8"> <a class="self-link" href="#example-d1b18fd8"></a> For example, when using CSS 3D Transforms to move an element around the screen, the element and its contents might be promoted to a “layer”, where they can render independently from the rest of the page and be composited in later. This isolates the rendering of the content so that the rest of the page doesn’t have to be rerendered if the element’s transform is the only thing that changes between frames, and often provides significant speed benefits. <p>However, setting up the element in a fresh layer is a relatively expensive operation, which can delay the start of a <a class="property css" data-link-type="property" href="https://drafts.csswg.org/css-transforms-1/#propdef-transform" id="ref-for-propdef-transform">transform</a> animation by a noticeable fraction of a second.</p> </div> <p>The <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change①">will-change</a> property defined in this specification allows an author to declare ahead-of-time what properties are likely to change in the future, so the UA can set up the appropriate optimizations some time before they’re needed. This way, when the actual change happens, the page updates in a snappy manner.</p> <h3 class="heading settled" data-level="1.1" id="values"><span class="secno">1.1. </span><span class="content"> Value Definitions</span><a class="self-link" href="#values"></a></h3> <p>This specification follows the <a href="https://www.w3.org/TR/CSS2/about.html#property-defs">CSS property definition conventions</a> from <a data-link-type="biblio" href="#biblio-css2" title="Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification">[CSS2]</a> using the <a href="https://www.w3.org/TR/css-values-3/#value-defs">value definition syntax</a> from <a data-link-type="biblio" href="#biblio-css-values-3" title="CSS Values and Units Module Level 3">[CSS-VALUES-3]</a>. Value types not defined in this specification are defined in CSS Values & Units <span title="CSS Values and Units Module Level 3">[CSS-VALUES-3]</span>. Combination with other CSS modules may expand the definitions of these value types.</p> <p>In addition to the property-specific values listed in their definitions, all properties defined in this specification also accept the <a data-link-type="dfn" href="https://drafts.csswg.org/css-values-4/#css-wide-keywords" id="ref-for-css-wide-keywords">CSS-wide keywords</a> as their property value. For readability they have not been repeated explicitly.</p> <h3 class="heading settled" data-level="1.2" id="using"><span class="secno">1.2. </span><span class="content"> Using <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change②">will-change</a> Well</span><a class="self-link" href="#using"></a></h3> <p>The <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change③">will-change</a> property, like all performance hints, can be somewhat difficult to learn how to use “properly”, particularly since it has very little, if any, effect an author can directly detect. However, there are several simple “Dos and Don’ts” which hopefully will help develop a good intuition about how to use <span class="property" id="ref-for-propdef-will-change④">will-change</span> well.</p> <h4 class="no-num no-toc heading settled" id="dont-global"><span class="content"> Don’t Spam <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change⑤">will-change</a> Across Too Many Properties or Elements</span><a class="self-link" href="#dont-global"></a></h4> <p>A common initial response to seeing <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change⑥">will-change</a> is to assume that code like this is a good idea:</p> <pre>* { will-change: transform, opacity /* , ... */; }</pre> <p>After all, this tells the browser to go ahead and optimize everything, which has to be good right?</p> <p>Wrong. The browser <em>already</em> tries as hard as it can to optimize everything. Telling it to do so explicitly doesn’t help anything, and in fact has the capacity to do a lot of harm; some of the stronger optimizations that are likely to be tied to <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change⑦">will-change</a> end up using a lot of a machine’s resources, and when overused like this can cause the page to slow down or even crash.</p> <p>In addition, <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change⑧">will-change</a> does have <strong>some</strong> side-effects, and it’s very unlikely that pages actually want all those side-effects on every element.</p> <h4 class="no-num no-toc heading settled" id="css-sparingly"><span class="content"> Use <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change⑨">will-change</a> Sparingly In Stylesheets</span><a class="self-link" href="#css-sparingly"></a></h4> <p>Using <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change①⓪">will-change</a> directly in a stylesheet implies that the targeted elements are always a few moments away from changing. This is <em>usually</em> not what you actually mean; instead, <span class="property" id="ref-for-propdef-will-change①①">will-change</span> should usually be flipped on and off via scripting before and after the change occurs (see <a href="#dont-waste">Don’t Waste Resources On Elements That Have Stopped Changing</a>). However, there are some common circumstances in which it is appropriate to use <span class="property" id="ref-for-propdef-will-change①②">will-change</span> directly in a stylesheet.</p> <div class="example" id="example-831888c0"> <a class="self-link" href="#example-831888c0"></a> For example, specifying <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change①③">will-change</a> for a small number of persistent UI elements in a page which should react snappily to the user is appropriate: <pre>body > .sidebar { will-change: transform; /* Will use 'transform' to slide it out when the user requests. */ } </pre> <p>Because this is limited to a small number of elements, the fact that the optimization is rarely actually used doesn’t hurt very much.</p> </div> <div class="example" id="example-1ea11531"> <a class="self-link" href="#example-1ea11531"></a> Sometimes an element really <em>does</em> change a property nearly constantly. Perhaps it responds to the user’s mouse movements, or just regularly takes some action that causes an animation. In this case, just declaring the <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change①④">will-change</a> value in the stylesheet is fine, as it accurately describes that the element will regularly/constantly change, and so should be kept optimized. <pre>.cats-flying-around-the-screen { will-change: left, top; } </pre> </div> <h4 class="no-num no-toc heading settled" id="give-time"><span class="content"> Give <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change①⑤">will-change</a> Sufficient Time To Work</span><a class="self-link" href="#give-time"></a></h4> <p>Another common bad pattern is to apply <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change①⑥">will-change</a> to an element <em>immediately</em> before starting the animation or property change that it’s meant to help with. Unfortunately, most of those optimizations need time to be applied, and so they don’t have enough time to set-up when this is done, and the <span class="property" id="ref-for-propdef-will-change①⑦">will-change</span> has little to no effect. Instead, find some way to predict at least slightly ahead of time that something will change, and set <span class="property" id="ref-for-propdef-will-change①⑧">will-change</span> <em>then</em>.</p> <div class="example" id="example-8e9e08f2"> <a class="self-link" href="#example-8e9e08f2"></a> For example, if an element is going to change when a user clicks on it, setting <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change①⑨">will-change</a> on hover will usually give at least 200 milliseconds for the optimizations to be set up, as human reaction time is relatively slow. This can be done either via scripting, or rather simply with a CSS rule: <pre>.element { transition: opacity .2s; opacity: 1; } .element:hover { will-change: opacity; } .element:active { opacity: .3; } </pre> <p>However, a rule like that is useless if the effect is going to happen on hover. In cases like these, it is often still possible to find some way to predict the action before it occurs. For example, hovering an ancestor may give enough lead time:</p> <pre>.element { transition: opacity .2s; opacity: 1; } .container:hover > .element { will-change: opacity; } .element:hover { opacity: .3; } </pre> </div> <h4 class="no-num no-toc heading settled" id="dont-waste"><span class="content"> Don’t Waste Resources On Elements That Have Stopped Changing</span><a class="self-link" href="#dont-waste"></a></h4> <p>Because the optimizations browsers use for changing some properties are expensive, browsers remove them and revert to normal behavior as soon as they can in normal circumstances. However, <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change②⓪">will-change</a> will generally override this behavior, maintaining the optimizations for much longer than the browser would otherwise do.</p> <p>As such, whenever you add <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change②①">will-change</a> to an element, especially via scripting, don’t forget to <em>remove</em> it after the element is done changing, so the browser can recover whatever resources the optimizations are claiming.</p> <h2 class="heading settled" data-level="2" id="will-change"><span class="secno">2. </span><span class="content"> Hinting at Future Behavior: the <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change②②">will-change</a> property</span><a class="self-link" href="#will-change"></a></h2> <table class="def propdef" data-link-for-hint="will-change"> <tbody> <tr> <th>Name: <td><dfn class="dfn-paneled css" data-dfn-type="property" data-export id="propdef-will-change">will-change</dfn> <tr class="value"> <th><a href="https://www.w3.org/TR/css-values/#value-defs">Value:</a> <td class="prod">auto <a data-link-type="grammar" href="https://drafts.csswg.org/css-values-4/#comb-one" id="ref-for-comb-one">|</a> <a class="production css" data-link-type="type" href="#typedef-animateable-feature" id="ref-for-typedef-animateable-feature"><animateable-feature></a><a data-link-type="grammar" href="https://drafts.csswg.org/css-values-4/#mult-comma" id="ref-for-mult-comma">#</a> <tr> <th><a href="https://www.w3.org/TR/css-cascade/#initial-values">Initial:</a> <td>auto <tr> <th><a href="https://www.w3.org/TR/css-cascade/#applies-to">Applies to:</a> <td><a href="https://www.w3.org/TR/css-pseudo/#generated-content" title="Includes ::before and ::after pseudo-elements.">all elements</a> <tr> <th><a href="https://www.w3.org/TR/css-cascade/#inherited-property">Inherited:</a> <td>no <tr> <th><a href="https://www.w3.org/TR/css-values/#percentages">Percentages:</a> <td>n/a <tr> <th><a href="https://www.w3.org/TR/css-cascade/#computed">Computed value:</a> <td>specified value <tr> <th><a href="https://www.w3.org/TR/cssom/#serializing-css-values">Canonical order:</a> <td>per grammar <tr> <th><a href="https://www.w3.org/TR/web-animations/#animation-type">Animation type:</a> <td>not animatable </table> <pre class="prod"><dfn class="dfn-paneled" data-dfn-type="type" data-export id="typedef-animateable-feature"><animateable-feature></dfn> = scroll-position <a data-link-type="grammar" href="https://drafts.csswg.org/css-values-4/#comb-one" id="ref-for-comb-one①">|</a> contents <a data-link-type="grammar" href="https://drafts.csswg.org/css-values-4/#comb-one" id="ref-for-comb-one②">|</a> <a class="production" data-link-type="type" href="https://drafts.csswg.org/css-values-4/#identifier-value" id="ref-for-identifier-value"><custom-ident></a></pre> <p>The <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change②③">will-change</a> property provides a rendering hint to the user agent, stating what kinds of changes the author expects to perform on the element. This allows the user agent to perform ahead-of-time any optimizations necessary for rendering those changes smoothly, avoiding “jank” when the author does begin changing or animating that feature.</p> <div class="note" role="note"> Different browsers can use the information from <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change②④">will-change</a> in different ways, and even a single browser might use it in different ways at different time. For example, a browser that promotes elements to their own “GPU layer” when they have <span class="css" id="ref-for-propdef-will-change②⑤">will-change: transform</span> specified might avoid doing that when there are <em>too many</em> elements declaring that, to avoid exhausting GPU memory. </div> <p>Values have the following meanings:</p> <dl> <dt><dfn class="dfn-paneled css" data-dfn-for="will-change" data-dfn-type="value" data-export id="valdef-will-change-auto">auto</dfn> <dd> Expresses no particular intent; the user agent should apply whatever heuristics and optimizations it normally does. <dt><dfn class="dfn-paneled css" data-dfn-for="will-change" data-dfn-type="value" data-export id="valdef-will-change-scroll-position">scroll-position</dfn> <dd> Indicates that the author expects to animate or change the scroll position of the element in the near future. <p class="example" id="example-c0594e8a"><a class="self-link" href="#example-c0594e8a"></a> For example, browsers often only render the content in the "scroll window" on a scrollable element, and some of the content past that window, balancing memory and time savings from the skipped rendering against making scrolling look nice. A browser might take this value as a signal to expand the range of content around the scroll window that is rendered, so that longer/faster scrolls can be done smoothly. </p> <dt><dfn class="dfn-paneled css" data-dfn-for="will-change" data-dfn-type="value" data-export id="valdef-will-change-contents">contents</dfn> <dd> Indicates that the author expects to animate or change something about the element’s contents in the near future. <div class="example" id="example-5dd10a2f"> <a class="self-link" href="#example-5dd10a2f"></a> For example, browsers often “cache” rendering of elements over time, because most things don’t change very often, or only change their position. However, if an element <em>does</em> change its contents continually, producing and maintaining this cache is a waste of time. A browser might take this value as a signal to cache less aggressively on the element, or avoid caching at all and just continually re-render the element from scratch. <p>This value is mostly intended to help browsers optimize JS-based animations of content, which change aspects of an element’s contents many times per second. This kind of optimization, when possible, is already done automatically by browsers when declarative animations are used.</p> </div> <p class="note" role="note"><span class="marker">Note:</span> This value more-or-less applies to the entire subtree of the element its declared on, as it indicates the browser should count on *any* of the descendants changing in some way. Using this on an element “high up” in your document might be very bad for your page’s performance; try to only use this on elements near the “bottom” of your document tree, containing as little of the document as possible.</p> <dt><dfn class="dfn-paneled css" data-dfn-for="will-change" data-dfn-type="value" data-export id="valdef-will-change-custom-ident"><a class="production css" data-link-type="type" href="https://drafts.csswg.org/css-values-4/#identifier-value" id="ref-for-identifier-value①"><custom-ident></a></dfn> <dd> If the <a class="production css" data-link-type="type" href="https://drafts.csswg.org/css-values-4/#identifier-value" id="ref-for-identifier-value②"><custom-ident></a> is an <a data-link-type="dfn" href="https://infra.spec.whatwg.org/#ascii-case-insensitive" id="ref-for-ascii-case-insensitive">ASCII case-insensitive</a> match for the name of a built-in CSS property, it indicates that the author expects to animate or change the property with the given name on the element in the near future. If the property given is a shorthand, it indicates the expectation for all the longhands the shorthand expands to. <p class="example" id="example-03a1e696"><a class="self-link" href="#example-03a1e696"></a> For example, setting <a class="css" data-link-type="propdesc" href="#propdef-will-change" id="ref-for-propdef-will-change②⑥">will-change: background;</a> is identical to setting <span class="css" id="ref-for-propdef-will-change②⑦">will-change: background-image, background-position, ...</span> for all the properties that <a class="property css" data-link-type="property" href="https://drafts.csswg.org/css-backgrounds-3/#propdef-background" id="ref-for-propdef-background">background</a> expands into. </p> <p>The <a class="production css" data-link-type="type" href="https://drafts.csswg.org/css-values-4/#identifier-value" id="ref-for-identifier-value③"><custom-ident></a> production used here excludes the keywords <span class="css">will-change</span>, <span class="css">none</span>, <span class="css">all</span>, <a class="css" data-link-type="maybe" href="#valdef-will-change-auto" id="ref-for-valdef-will-change-auto">auto</a>, <a class="css" data-link-type="maybe" href="#valdef-will-change-scroll-position" id="ref-for-valdef-will-change-scroll-position">scroll-position</a>, and <a class="css" data-link-type="maybe" href="#valdef-will-change-contents" id="ref-for-valdef-will-change-contents">contents</a>, in addition to the keywords normally excluded from <span class="production" id="ref-for-identifier-value④"><custom-ident></span>.</p> <p class="note" role="note"><span class="marker">Note:</span> Note that most properties will have no effect when specified, as the user agent doesn’t perform any special optimizations for changes in most properties. It is still <em>safe</em> to specify them, though; it’ll simply have no effect.</p> <p>Specifying a custom property must have no effect, which means that effects that happen through custom properties do not count for the rules below that are conditioned on any non-initial value of a property causing something.</p> <p class="note" role="note"><span class="marker">Note:</span> Specifying a value that’s not recognized as a property is fine; it simply has no effect. This allows you to safely specify <em>new</em> properties that exist in some user agents without negatively affecting down-level user agents that don’t know about that property.</p> <p class="example" id="example-7225dcbc"><a class="self-link" href="#example-7225dcbc"></a> For example, browsers often handle elements with <a class="property css" data-link-type="property" href="https://drafts.csswg.org/css-transforms-1/#propdef-transform" id="ref-for-propdef-transform①">transform</a> set to a non-initial value very differently from normal elements, perhaps rendering them to their own “GPU layer” or using other mechanisms to make it easier to quickly make the sort of transformations that <span class="property" id="ref-for-propdef-transform②">transform</span> can produce. A browser might take a value of <span class="property" id="ref-for-propdef-transform③">transform</span> as a signal that it should go ahead and promote the element to its own layer immediately, before the element starts to be transformed, to avoid any delay involved in rerendering the old and new layers. </p> <p>If any non-initial value of a property would create a stacking context on the element, specifying that property in <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change②⑧">will-change</a> must create a stacking context on the element.</p> <p>If any non-initial value of a property would cause the element to generate a containing block for absolutely positioned elements, specifying that property in <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change②⑨">will-change</a> must cause the element to generate a containing block for absolutely positioned elements.</p> <p>If any non-initial value of a property would cause the element to generate a containing block for fixed positioned elements, specifying that property in <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change③⓪">will-change</a> must cause the element to generate a containing block for fixed positioned elements.</p> <p>If any non-initial value of a property would cause rendering differences on the element (such as using a different anti-aliasing strategy for text), the user agent should use that alternate rendering when the property is specified in <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change③①">will-change</a>, to avoid sudden rendering differences when the property is eventually changed.</p> <p class="example" id="example-e1300843"><a class="self-link" href="#example-e1300843"></a> For example, setting <a class="property css" data-link-type="property" href="https://drafts.csswg.org/css-color-4/#propdef-opacity" id="ref-for-propdef-opacity">opacity</a> to any value other than <span class="css">1</span> creates a stacking context on the element. Thus, setting <a class="css" data-link-type="propdesc" href="#propdef-will-change" id="ref-for-propdef-will-change③②">will-change: opacity</a> also creates a stacking context, even if <span class="property" id="ref-for-propdef-opacity①">opacity</span> is <em>currently</em> still equal to <span class="css">1</span>. </p> </dl> <p>The <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change③③">will-change</a> property has no <em>direct</em> effect on the element it is specified on, beyond the creation of stacking contexts and containing blocks as specified above. It is solely a rendering hint to the user agent, allowing it set up potentially-expensive optimizations for certain types of changes before the changes actually start occurring.</p> <h2 class="heading settled" data-level="3" id="security"><span class="secno">3. </span><span class="content">Security Considerations</span><a class="self-link" href="#security"></a></h2> <p>No Security concerns have been raised against this document</p> <h2 class="heading settled" data-level="4" id="privacy"><span class="secno">4. </span><span class="content">Privacy Considerations</span><a class="self-link" href="#privacy"></a></h2> <p>No Privacy concerns have been raised against this document</p> <h2 class="heading settled" data-level="5" id="acks"><span class="secno">5. </span><span class="content">Acknowledgements</span><a class="self-link" href="#acks"></a></h2> <p>Thanks to Benoit Girard for originally suggesting the <span class="css">will-animate</span> property, and doing a lot of the initial design work.</p> <h2 class="heading settled" data-level="6" id="changes"><span class="secno">6. </span><span class="content">Changes</span><a class="self-link" href="#changes"></a></h2> <p>Since the <a href="http://www.w3.org/TR/2015/CR-css-will-change-1-20151203/">03 December 2015 CR</a>:</p> <ul> <li data-md> <p>Added Security and Privacy sections</p> <li data-md> <p>Clarified that unknown values are fine, and have no effect</p> <li data-md> <p>Specified that ASCII Case-Insensitive matching is used against property names</p> <li data-md> <p>Changed the animation type of the will-change property to not animatable</p> <li data-md> <p>Dropped the "Media:" entry from propdef tables, as with other CSS specifications</p> <li data-md> <p>Minor editorial clarifications, markup improvements</p> </ul> <p>Since the <a href="https://www.w3.org/TR/2014/WD-css-will-change-1-20140429/">April 29 2014 Working Draft</a>:</p> <ul> <li data-md> <p>Added an explanatory section giving guidance on how to use <a class="property css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change③④">will-change</a> well.</p> <li data-md> <p>Specified the behavior of shorthands</p> </ul> </main> <h2 class="no-ref no-num heading settled" id="w3c-conformance"><span class="content"> Conformance</span><a class="self-link" href="#w3c-conformance"></a></h2> <h3 class="no-ref heading settled" id="w3c-conventions"><span class="content"> Document conventions</span><a class="self-link" href="#w3c-conventions"></a></h3> <p>Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification. </p> <p>All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. <a data-link-type="biblio" href="#biblio-rfc2119" title="Key words for use in RFCs to Indicate Requirement Levels">[RFC2119]</a></p> <p>Examples in this specification are introduced with the words “for example” or are set apart from the normative text with <code>class="example"</code>, like this: </p> <div class="example" id="w3c-example"> <a class="self-link" href="#w3c-example"></a> <p>This is an example of an informative example.</p> </div> <p>Informative notes begin with the word “Note” and are set apart from the normative text with <code>class="note"</code>, like this: </p> <p class="note" role="note">Note, this is an informative note.</p> <p>Advisements are normative sections styled to evoke special attention and are set apart from other normative text with <code><strong class="advisement"></code>, like this: <strong class="advisement"> UAs MUST provide an accessible alternative. </strong></p> <details class="wpt-tests-block" dir="ltr" lang="en" open> <summary>Tests</summary> <p>Tests relating to the content of this specification may be documented in “Tests” blocks like this one. Any such block is non-normative.</p> <ul class="wpt-tests-list"></ul> <hr> </details> <h3 class="no-ref heading settled" id="w3c-conformance-classes"><span class="content"> Conformance classes</span><a class="self-link" href="#w3c-conformance-classes"></a></h3> <p>Conformance to this specification is defined for three conformance classes: </p> <dl> <dt>style sheet <dd>A <a href="http://www.w3.org/TR/CSS21/conform.html#style-sheet">CSS style sheet</a>. <dt>renderer <dd>A <a href="http://www.w3.org/TR/CSS21/conform.html#user-agent">UA</a> that interprets the semantics of a style sheet and renders documents that use them. <dt>authoring tool <dd>A <a href="http://www.w3.org/TR/CSS21/conform.html#user-agent">UA</a> that writes a style sheet. </dl> <p>A style sheet is conformant to this specification if all of its statements that use syntax defined in this module are valid according to the generic CSS grammar and the individual grammars of each feature defined in this module. </p> <p>A renderer is conformant to this specification if, in addition to interpreting the style sheet as defined by the appropriate specifications, it supports all the features defined by this specification by parsing them correctly and rendering the document accordingly. However, the inability of a UA to correctly render a document due to limitations of the device does not make the UA non-conformant. (For example, a UA is not required to render color on a monochrome monitor.) </p> <p>An authoring tool is conformant to this specification if it writes style sheets that are syntactically correct according to the generic CSS grammar and the individual grammars of each feature in this module, and meet all other conformance requirements of style sheets as described in this module. </p> <h3 class="no-ref heading settled" id="w3c-partial"><span class="content"> Partial implementations</span><a class="self-link" href="#w3c-partial"></a></h3> <p>So that authors can exploit the forward-compatible parsing rules to assign fallback values, CSS renderers <strong>must</strong> treat as invalid (and <a href="http://www.w3.org/TR/CSS21/conform.html#ignore">ignore as appropriate</a>) any at-rules, properties, property values, keywords, and other syntactic constructs for which they have no usable level of support. In particular, user agents <strong>must not</strong> selectively ignore unsupported component values and honor supported values in a single multi-value property declaration: if any value is considered invalid (as unsupported values must be), CSS requires that the entire declaration be ignored.</p> <h4 class="heading settled" id="w3c-conform-future-proofing"><span class="content"> Implementations of Unstable and Proprietary Features</span><a class="self-link" href="#w3c-conform-future-proofing"></a></h4> <p>To avoid clashes with future stable CSS features, the CSSWG recommends <a href="http://www.w3.org/TR/CSS/#future-proofing">following best practices</a> for the implementation of <a href="http://www.w3.org/TR/CSS/#unstable">unstable</a> features and <a href="http://www.w3.org/TR/CSS/#proprietary-extension">proprietary extensions</a> to CSS. </p> <h3 class="no-ref heading settled" id="w3c-testing"><span class="content"> Non-experimental implementations</span><a class="self-link" href="#w3c-testing"></a></h3> <p>Once a specification reaches the Candidate Recommendation stage, non-experimental implementations are possible, and implementors should release an unprefixed implementation of any CR-level feature they can demonstrate to be correctly implemented according to spec. </p> <p>To establish and maintain the interoperability of CSS across implementations, the CSS Working Group requests that non-experimental CSS renderers submit an implementation report (and, if necessary, the testcases used for that implementation report) to the W3C before releasing an unprefixed implementation of any CSS features. Testcases submitted to W3C are subject to review and correction by the CSS Working Group. </p> <p>Further information on submitting testcases and implementation reports can be found from on the CSS Working Group’s website at <a href="http://www.w3.org/Style/CSS/Test/">http://www.w3.org/Style/CSS/Test/</a>. Questions should be directed to the <a href="http://lists.w3.org/Archives/Public/public-css-testsuite">public-css-testsuite@w3.org</a> mailing list.</p> <script src="https://www.w3.org/scripts/TR/2021/fixup.js"></script> <h2 class="no-num no-ref heading settled" id="index"><span class="content">Index</span><a class="self-link" href="#index"></a></h2> <h3 class="no-num no-ref heading settled" id="index-defined-here"><span class="content">Terms defined by this specification</span><a class="self-link" href="#index-defined-here"></a></h3> <ul class="index"> <li><a href="#typedef-animateable-feature"><animateable-feature></a><span>, in § 2</span> <li><a href="#valdef-will-change-auto">auto</a><span>, in § 2</span> <li><a href="#valdef-will-change-contents">contents</a><span>, in § 2</span> <li><a href="#valdef-will-change-custom-ident"><custom-ident></a><span>, in § 2</span> <li><a href="#valdef-will-change-scroll-position">scroll-position</a><span>, in § 2</span> <li><a href="#propdef-will-change">will-change</a><span>, in § 2</span> </ul> <h3 class="no-num no-ref heading settled" id="index-defined-elsewhere"><span class="content">Terms defined by reference</span><a class="self-link" href="#index-defined-elsewhere"></a></h3> <ul class="index"> <li> <a data-link-type="biblio">[CSS-BACKGROUNDS-3]</a> defines the following terms: <ul> <li><span class="dfn-paneled" id="f5eca8c9">background</span> </ul> <li> <a data-link-type="biblio">[CSS-COLOR-4]</a> defines the following terms: <ul> <li><span class="dfn-paneled" id="91bfbe18">opacity</span> </ul> <li> <a data-link-type="biblio">[CSS-TRANSFORMS-1]</a> defines the following terms: <ul> <li><span class="dfn-paneled" id="e2e08d07">transform</span> </ul> <li> <a data-link-type="biblio">[CSS-VALUES-4]</a> defines the following terms: <ul> <li><span class="dfn-paneled" id="68487d22">#</span> <li><span class="dfn-paneled" id="e274345c"><custom-ident></span> <li><span class="dfn-paneled" id="358fd6ff">CSS-wide keywords</span> <li><span class="dfn-paneled" id="6ec67710">|</span> </ul> <li> <a data-link-type="biblio">[INFRA]</a> defines the following terms: <ul> <li><span class="dfn-paneled" id="7f9469b5">ASCII case-insensitive</span> </ul> </ul> <h2 class="no-num no-ref heading settled" id="references"><span class="content">References</span><a class="self-link" href="#references"></a></h2> <h3 class="no-num no-ref heading settled" id="normative"><span class="content">Normative References</span><a class="self-link" href="#normative"></a></h3> <dl> <dt id="biblio-css-values-3">[CSS-VALUES-3] <dd>Tab Atkins Jr.; Elika Etemad. <a href="https://drafts.csswg.org/css-values-3/"><cite>CSS Values and Units Module Level 3</cite></a>. URL: <a href="https://drafts.csswg.org/css-values-3/">https://drafts.csswg.org/css-values-3/</a> <dt id="biblio-css-values-4">[CSS-VALUES-4] <dd>Tab Atkins Jr.; Elika Etemad. <a href="https://drafts.csswg.org/css-values-4/"><cite>CSS Values and Units Module Level 4</cite></a>. URL: <a href="https://drafts.csswg.org/css-values-4/">https://drafts.csswg.org/css-values-4/</a> <dt id="biblio-css2">[CSS2] <dd>Bert Bos; et al. <a href="https://drafts.csswg.org/css2/"><cite>Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification</cite></a>. URL: <a href="https://drafts.csswg.org/css2/">https://drafts.csswg.org/css2/</a> <dt id="biblio-infra">[INFRA] <dd>Anne van Kesteren; Domenic Denicola. <a href="https://infra.spec.whatwg.org/"><cite>Infra Standard</cite></a>. Living Standard. URL: <a href="https://infra.spec.whatwg.org/">https://infra.spec.whatwg.org/</a> <dt id="biblio-rfc2119">[RFC2119] <dd>S. Bradner. <a href="https://datatracker.ietf.org/doc/html/rfc2119"><cite>Key words for use in RFCs to Indicate Requirement Levels</cite></a>. March 1997. Best Current Practice. URL: <a href="https://datatracker.ietf.org/doc/html/rfc2119">https://datatracker.ietf.org/doc/html/rfc2119</a> </dl> <h3 class="no-num no-ref heading settled" id="informative"><span class="content">Informative References</span><a class="self-link" href="#informative"></a></h3> <dl> <dt id="biblio-css-backgrounds-3">[CSS-BACKGROUNDS-3] <dd>Elika Etemad; Brad Kemper. <a href="https://drafts.csswg.org/css-backgrounds/"><cite>CSS Backgrounds and Borders Module Level 3</cite></a>. URL: <a href="https://drafts.csswg.org/css-backgrounds/">https://drafts.csswg.org/css-backgrounds/</a> <dt id="biblio-css-color-4">[CSS-COLOR-4] <dd>Chris Lilley; Tab Atkins Jr.; Lea Verou. <a href="https://drafts.csswg.org/css-color-4/"><cite>CSS Color Module Level 4</cite></a>. URL: <a href="https://drafts.csswg.org/css-color-4/">https://drafts.csswg.org/css-color-4/</a> <dt id="biblio-css-transforms-1">[CSS-TRANSFORMS-1] <dd>Simon Fraser; et al. <a href="https://drafts.csswg.org/css-transforms/"><cite>CSS Transforms Module Level 1</cite></a>. URL: <a href="https://drafts.csswg.org/css-transforms/">https://drafts.csswg.org/css-transforms/</a> </dl> <h2 class="no-num no-ref heading settled" id="property-index"><span class="content">Property Index</span><a class="self-link" href="#property-index"></a></h2> <div class="big-element-wrapper"> <table class="index"> <thead> <tr> <th scope="col">Name <th scope="col">Value <th scope="col">Initial <th scope="col">Applies to <th scope="col">Inh. <th scope="col">%ages <th scope="col">Animation type <th scope="col">Canonical order <th scope="col">Computed value <tbody> <tr> <th scope="row"><a class="css" data-link-type="property" href="#propdef-will-change" id="ref-for-propdef-will-change③⑤">will-change</a> <td>auto | <animateable-feature># <td>auto <td>all elements <td>no <td>n/a <td>not animatable <td>per grammar <td>specified value </table> </div> <details class="mdn-anno unpositioned" data-anno-for="will-change"> <summary><b class="all-engines-flag" title="This feature is in all current engines.">✔</b><span>MDN</span></summary> <div class="feature"> <p><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/will-change" title="The will-change CSS property hints to browsers how an element is expected to change. Browsers may set up optimizations before an element is actually changed. These kinds of optimizations can increase the responsiveness of a page by doing potentially expensive work before they are actually required.">will-change</a></p> <p class="all-engines-text">In all current engines.</p> <div class="support"> <span class="firefox yes"><span>Firefox</span><span>36+</span></span><span class="safari yes"><span>Safari</span><span>9.1+</span></span><span class="chrome yes"><span>Chrome</span><span>36+</span></span> <hr> <span class="opera yes"><span>Opera</span><span>24+</span></span><span class="edge_blink yes"><span>Edge</span><span>79+</span></span> <hr> <span class="edge no"><span>Edge (Legacy)</span><span>?</span></span><span class="ie no"><span>IE</span><span>None</span></span> <hr> <span class="firefox_android no"><span>Firefox for Android</span><span>?</span></span><span class="safari_ios no"><span>iOS Safari</span><span>?</span></span><span class="chrome_android no"><span>Chrome for Android</span><span>?</span></span><span class="webview_android no"><span>Android WebView</span><span>?</span></span><span class="samsunginternet_android no"><span>Samsung Internet</span><span>?</span></span><span class="opera_android no"><span>Opera Mobile</span><span>?</span></span> </div> </div> </details> <script>/* Boilerplate: script-dom-helper */ "use strict"; function query(sel) { return document.querySelector(sel); } function queryAll(sel) { return [...document.querySelectorAll(sel)]; } function iter(obj) { if(!obj) return []; var it = obj[Symbol.iterator]; if(it) return it; return Object.entries(obj); } function mk(tagname, attrs, ...children) { const el = document.createElement(tagname); for(const [k,v] of iter(attrs)) { if(k.slice(0,3) == "_on") { const eventName = k.slice(3); el.addEventListener(eventName, v); } else if(k[0] == "_") { // property, not attribute el[k.slice(1)] = v; } else { if(v === false || v == null) { continue; } else if(v === true) { el.setAttribute(k, ""); continue; } else { el.setAttribute(k, v); } } } append(el, children); return el; } /* Create shortcuts for every known HTML element */ [ "a", "abbr", "acronym", "address", "applet", "area", "article", "aside", "audio", "b", "base", "basefont", "bdo", "big", "blockquote", "body", "br", "button", "canvas", "caption", "center", "cite", "code", "col", "colgroup", "datalist", "dd", "del", "details", "dfn", "dialog", "div", "dl", "dt", "em", "embed", "fieldset", "figcaption", "figure", "font", "footer", "form", "frame", "frameset", "head", "header", "h1", "h2", "h3", "h4", "h5", "h6", "hr", "html", "i", "iframe", "img", "input", "ins", "kbd", "label", "legend", "li", "link", "main", "map", "mark", "meta", "meter", "nav", "nobr", "noscript", "object", "ol", "optgroup", "option", "output", "p", "param", "pre", "progress", "q", "s", "samp", "script", "section", "select", "small", "source", "span", "strike", "strong", "style", "sub", "summary", "sup", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "title", "tr", "u", "ul", "var", "video", "wbr", "xmp", ].forEach(tagname=>{ mk[tagname] = (...args) => mk(tagname, ...args); }); function* nodesFromChildList(children) { for(const child of children.flat(Infinity)) { if(child instanceof Node) { yield child; } else { yield new Text(child); } } } function append(el, ...children) { for(const child of nodesFromChildList(children)) { if(el instanceof Node) el.appendChild(child); else el.push(child); } return el; } function insertAfter(el, ...children) { for(const child of nodesFromChildList(children)) { el.parentNode.insertBefore(child, el.nextSibling); } return el; } function clearContents(el) { el.innerHTML = ""; return el; } function parseHTML(markup) { if(markup.toLowerCase().trim().indexOf('<!doctype') === 0) { const doc = document.implementation.createHTMLDocument(""); doc.documentElement.innerHTML = markup; return doc; } else { const el = mk.template({}); el.innerHTML = markup; return el.content; } }</script> <script>/* Boilerplate: script-dfn-panel */ "use strict"; { let dfnPanelData = { "358fd6ff": {"dfnID":"358fd6ff","dfnText":"CSS-wide keywords","external":true,"refSections":[{"refs":[{"id":"ref-for-css-wide-keywords"}],"title":"1.1. \nValue Definitions"}],"url":"https://drafts.csswg.org/css-values-4/#css-wide-keywords"}, "68487d22": {"dfnID":"68487d22","dfnText":"#","external":true,"refSections":[{"refs":[{"id":"ref-for-mult-comma"}],"title":"2. \nHinting at Future Behavior: the will-change property"}],"url":"https://drafts.csswg.org/css-values-4/#mult-comma"}, "6ec67710": {"dfnID":"6ec67710","dfnText":"|","external":true,"refSections":[{"refs":[{"id":"ref-for-comb-one"},{"id":"ref-for-comb-one\u2460"},{"id":"ref-for-comb-one\u2461"}],"title":"2. \nHinting at Future Behavior: the will-change property"}],"url":"https://drafts.csswg.org/css-values-4/#comb-one"}, "7f9469b5": {"dfnID":"7f9469b5","dfnText":"ASCII case-insensitive","external":true,"refSections":[{"refs":[{"id":"ref-for-ascii-case-insensitive"}],"title":"2. \nHinting at Future Behavior: the will-change property"}],"url":"https://infra.spec.whatwg.org/#ascii-case-insensitive"}, "91bfbe18": {"dfnID":"91bfbe18","dfnText":"opacity","external":true,"refSections":[{"refs":[{"id":"ref-for-propdef-opacity"},{"id":"ref-for-propdef-opacity\u2460"}],"title":"2. \nHinting at Future Behavior: the will-change property"}],"url":"https://drafts.csswg.org/css-color-4/#propdef-opacity"}, "e274345c": {"dfnID":"e274345c","dfnText":"<custom-ident>","external":true,"refSections":[{"refs":[{"id":"ref-for-identifier-value"},{"id":"ref-for-identifier-value\u2460"},{"id":"ref-for-identifier-value\u2461"},{"id":"ref-for-identifier-value\u2462"},{"id":"ref-for-identifier-value\u2463"}],"title":"2. \nHinting at Future Behavior: the will-change property"}],"url":"https://drafts.csswg.org/css-values-4/#identifier-value"}, "e2e08d07": {"dfnID":"e2e08d07","dfnText":"transform","external":true,"refSections":[{"refs":[{"id":"ref-for-propdef-transform"}],"title":"1. \nIntroduction"},{"refs":[{"id":"ref-for-propdef-transform\u2460"},{"id":"ref-for-propdef-transform\u2461"},{"id":"ref-for-propdef-transform\u2462"}],"title":"2. \nHinting at Future Behavior: the will-change property"}],"url":"https://drafts.csswg.org/css-transforms-1/#propdef-transform"}, "f5eca8c9": {"dfnID":"f5eca8c9","dfnText":"background","external":true,"refSections":[{"refs":[{"id":"ref-for-propdef-background"}],"title":"2. \nHinting at Future Behavior: the will-change property"}],"url":"https://drafts.csswg.org/css-backgrounds-3/#propdef-background"}, "propdef-will-change": {"dfnID":"propdef-will-change","dfnText":"will-change","external":false,"refSections":[{"refs":[{"id":"ref-for-propdef-will-change\u2460"}],"title":"1. \nIntroduction"},{"refs":[{"id":"ref-for-propdef-will-change\u2461"},{"id":"ref-for-propdef-will-change\u2462"},{"id":"ref-for-propdef-will-change\u2463"}],"title":"1.2. \nUsing will-change Well"},{"refs":[{"id":"ref-for-propdef-will-change\u2464"},{"id":"ref-for-propdef-will-change\u2465"},{"id":"ref-for-propdef-will-change\u2466"},{"id":"ref-for-propdef-will-change\u2467"}],"title":"\nDon\u2019t Spam will-change Across Too Many Properties or Elements"},{"refs":[{"id":"ref-for-propdef-will-change\u2468"},{"id":"ref-for-propdef-will-change\u2460\u24ea"},{"id":"ref-for-propdef-will-change\u2460\u2460"},{"id":"ref-for-propdef-will-change\u2460\u2461"},{"id":"ref-for-propdef-will-change\u2460\u2462"},{"id":"ref-for-propdef-will-change\u2460\u2463"}],"title":"\nUse will-change Sparingly In Stylesheets"},{"refs":[{"id":"ref-for-propdef-will-change\u2460\u2464"},{"id":"ref-for-propdef-will-change\u2460\u2465"},{"id":"ref-for-propdef-will-change\u2460\u2466"},{"id":"ref-for-propdef-will-change\u2460\u2467"},{"id":"ref-for-propdef-will-change\u2460\u2468"}],"title":"\nGive will-change Sufficient Time To Work"},{"refs":[{"id":"ref-for-propdef-will-change\u2461\u24ea"},{"id":"ref-for-propdef-will-change\u2461\u2460"}],"title":"\nDon\u2019t Waste Resources On Elements That Have Stopped Changing"},{"refs":[{"id":"ref-for-propdef-will-change\u2461\u2461"},{"id":"ref-for-propdef-will-change\u2461\u2462"},{"id":"ref-for-propdef-will-change\u2461\u2463"},{"id":"ref-for-propdef-will-change\u2461\u2464"},{"id":"ref-for-propdef-will-change\u2461\u2465"},{"id":"ref-for-propdef-will-change\u2461\u2466"},{"id":"ref-for-propdef-will-change\u2461\u2467"},{"id":"ref-for-propdef-will-change\u2461\u2468"},{"id":"ref-for-propdef-will-change\u2462\u24ea"},{"id":"ref-for-propdef-will-change\u2462\u2460"},{"id":"ref-for-propdef-will-change\u2462\u2461"},{"id":"ref-for-propdef-will-change\u2462\u2462"}],"title":"2. \nHinting at Future Behavior: the will-change property"},{"refs":[{"id":"ref-for-propdef-will-change\u2462\u2463"}],"title":"6. Changes"}],"url":"#propdef-will-change"}, "typedef-animateable-feature": {"dfnID":"typedef-animateable-feature","dfnText":"<animateable-feature>","external":false,"refSections":[{"refs":[{"id":"ref-for-typedef-animateable-feature"}],"title":"2. \nHinting at Future Behavior: the will-change property"}],"url":"#typedef-animateable-feature"}, "valdef-will-change-auto": {"dfnID":"valdef-will-change-auto","dfnText":"auto","external":false,"refSections":[{"refs":[{"id":"ref-for-valdef-will-change-auto"}],"title":"2. \nHinting at Future Behavior: the will-change property"}],"url":"#valdef-will-change-auto"}, "valdef-will-change-contents": {"dfnID":"valdef-will-change-contents","dfnText":"contents","external":false,"refSections":[{"refs":[{"id":"ref-for-valdef-will-change-contents"}],"title":"2. \nHinting at Future Behavior: the will-change property"}],"url":"#valdef-will-change-contents"}, "valdef-will-change-custom-ident": {"dfnID":"valdef-will-change-custom-ident","dfnText":"<custom-ident>","external":false,"refSections":[],"url":"#valdef-will-change-custom-ident"}, "valdef-will-change-scroll-position": {"dfnID":"valdef-will-change-scroll-position","dfnText":"scroll-position","external":false,"refSections":[{"refs":[{"id":"ref-for-valdef-will-change-scroll-position"}],"title":"2. \nHinting at Future Behavior: the will-change property"}],"url":"#valdef-will-change-scroll-position"}, }; document.addEventListener("DOMContentLoaded", ()=>{ genAllDfnPanels(); document.body.addEventListener("click", (e) => { // If not handled already, just hide all dfn panels. hideAllDfnPanels(); }); }); window.addEventListener("resize", () => { // Pin any visible dfn panel queryAll(".dfn-panel.on, .dfn-panel.activated").forEach(el=>positionDfnPanel(el)); }); function genAllDfnPanels() { for(const panelData of Object.values(dfnPanelData)) { const dfnID = panelData.dfnID; const dfn = document.getElementById(dfnID); if(!dfn) { console.log(`Can't find dfn#${dfnID}.`, panelData); continue; } dfn.panelData = panelData; insertDfnPopupAction(dfn); } } function genDfnPanel(dfn, { dfnID, url, dfnText, refSections, external }) { const dfnPanel = mk.aside({ class: "dfn-panel on", id: `infopanel-for-${dfnID}`, "data-for": dfnID, "aria-labelled-by":`infopaneltitle-for-${dfnID}`, }, mk.span({id:`infopaneltitle-for-${dfnID}`, style:"display:none"}, `Info about the '${dfnText}' ${external?"external":""} reference.`), mk.a({href:url, class:"dfn-link"}, url), refSections.length == 0 ? [] : mk.b({}, "Referenced in:"), mk.ul({}, ...refSections.map(section=> mk.li({}, ...section.refs.map((ref, refI)=> [ mk.a({ href: `#${ref.id}` }, (refI == 0) ? section.title : `(${refI + 1})` ), " ", ] ), ), ), ), genLinkingSyntaxes(dfn), ); dfnPanel.addEventListener('click', (event) => { if (event.target.nodeName == 'A') { scrollToTargetAndHighlight(event); pinDfnPanel(dfnPanel); } event.stopPropagation(); refocusOnTarget(event); }); dfnPanel.addEventListener('keydown', (event) => { if(event.keyCode == 27) { // Escape key hideDfnPanel({dfnPanel}); event.stopPropagation(); event.preventDefault(); } }); dfnPanel.dfn = dfn; dfn.dfnPanel = dfnPanel; return dfnPanel; } function hideAllDfnPanels() { // Delete the currently-active dfn panel. queryAll(".dfn-panel").forEach(dfnPanel=>hideDfnPanel({dfnPanel})); } function showDfnPanel(dfn) { hideAllDfnPanels(); // Only display one at a time. dfn.setAttribute("aria-expanded", "true"); const dfnPanel = genDfnPanel(dfn, dfn.panelData); // Give the dfn a unique tabindex, and then // give all the tabbable panel bits successive indexes. let tabIndex = 100; dfn.tabIndex = tabIndex++; const tabbable = dfnPanel.querySelectorAll(":is(a, button)"); for (const el of tabbable) { el.tabIndex = tabIndex++; } append(document.body, dfnPanel); positionDfnPanel(dfnPanel); } function positionDfnPanel(dfnPanel) { const dfn = dfnPanel.dfn; const dfnPos = getBounds(dfn); dfnPanel.style.top = dfnPos.bottom + "px"; dfnPanel.style.left = dfnPos.left + "px"; const panelPos = dfnPanel.getBoundingClientRect(); const panelMargin = 8; const maxRight = document.body.parentNode.clientWidth - panelMargin; if (panelPos.right > maxRight) { const overflowAmount = panelPos.right - maxRight; const newLeft = Math.max(panelMargin, dfnPos.left - overflowAmount); dfnPanel.style.left = newLeft + "px"; } } function pinDfnPanel(dfnPanel) { // Switch it to "activated" state, which pins it. dfnPanel.classList.add("activated"); dfnPanel.style.position = "fixed"; dfnPanel.style.left = null; dfnPanel.style.top = null; } function hideDfnPanel({dfn, dfnPanel}) { if(!dfnPanel) dfnPanel = dfn.dfnPanel; if(!dfn) dfn = dfnPanel.dfn; dfn.dfnPanel = undefined; dfnPanel.dfn = undefined; dfn.setAttribute("aria-expanded", "false"); dfn.tabIndex = undefined; dfnPanel.remove() } function toggleDfnPanel(dfn) { if(dfn.dfnPanel) { hideDfnPanel(dfn); } else { showDfnPanel(dfn); } } function insertDfnPopupAction(dfn) { dfn.setAttribute('role', 'button'); dfn.setAttribute('aria-expanded', 'false') dfn.tabIndex = 0; dfn.classList.add('has-dfn-panel'); dfn.addEventListener('click', (event) => { toggleDfnPanel(dfn); event.stopPropagation(); }); dfn.addEventListener('keypress', (event) => { const kc = event.keyCode; // 32->Space, 13->Enter if(kc == 32 || kc == 13) { toggleDfnPanel(dfn); event.stopPropagation(); event.preventDefault(); } }); } function refocusOnTarget(event) { const target = event.target; setTimeout(() => { // Refocus on the event.target element. // This is needed after browser scrolls to the destination. target.focus(); }); } // TODO: shared util // Returns the root-level absolute position {left and top} of element. function getBounds(el, relativeTo=document.body) { const relativeRect = relativeTo.getBoundingClientRect(); const elRect = el.getBoundingClientRect(); const top = elRect.top - relativeRect.top; const left = elRect.left - relativeRect.left; return { top, left, bottom: top + elRect.height, right: left + elRect.width, } } function scrollToTargetAndHighlight(event) { let hash = event.target.hash; if (hash) { hash = decodeURIComponent(hash.substring(1)); const dest = document.getElementById(hash); if (dest) { dest.classList.add('highlighted'); setTimeout(() => dest.classList.remove('highlighted'), 1000); } } } // Functions, divided by link type, that wrap an autolink's // contents with the appropriate outer syntax. // Alternately, a string naming another type they format // the same as. function needsFor(type) { switch(type) { case "descriptor": case "value": case "element-attr": case "attr-value": case "element-state": case "method": case "constructor": case "argument": case "attribute": case "const": case "dict-member": case "event": case "enum-value": case "stringifier": case "serializer": case "iterator": case "maplike": case "setlike": case "state": case "mode": case "context": case "facet": return true; default: return false; } } function refusesFor(type) { switch(type) { case "property": case "element": case "interface": case "namespace": case "callback": case "dictionary": case "enum": case "exception": case "typedef": case "http-header": case "permission": return true; default: return false; } } function linkFormatterFromType(type) { switch(type) { case 'scheme': case 'permission': case 'dfn': return (text) => `[=${text}=]`; case 'abstract-op': return (text) => `[\$${text}\$]`; case 'function': case 'at-rule': case 'selector': case 'value': return (text) => `''${text}''`; case 'http-header': return (text) => `[:${text}:]`; case 'interface': case 'constructor': case 'method': case 'argument': case 'attribute': case 'callback': case 'dictionary': case 'dict-member': case 'enum': case 'enum-value': case 'exception': case 'const': case 'typedef': case 'stringifier': case 'serializer': case 'iterator': case 'maplike': case 'setlike': case 'extended-attribute': case 'event': case 'idl': return (text) => `{{${text}}}`; case 'element-state': case 'element-attr': case 'attr-value': case 'element': return (element) => `<{${element}}>`; case 'grammar': return (text) => `${text} (within a <pre class=prod>)`; case 'type': return (text)=> `<<${text}>>`; case 'descriptor': case 'property': return (text) => `'${text}'`; default: return; }; }; function genLinkingSyntaxes(dfn) { if(dfn.tagName != "DFN") return; const type = dfn.getAttribute('data-dfn-type'); if(!type) { console.log(`<dfn> doesn't have a data-dfn-type:`, dfn); return []; } // Return a function that wraps link text based on the type const linkFormatter = linkFormatterFromType(type); if(!linkFormatter) { console.log(`<dfn> has an unknown data-dfn-type:`, dfn); return []; } let ltAlts; if(dfn.hasAttribute('data-lt')) { ltAlts = dfn.getAttribute('data-lt') .split("|") .map(x=>x.trim()); } else { ltAlts = [dfn.textContent.trim()]; } if(type == "type") { // lt of "<foo>", but "foo" is the interior; // <<foo/bar>> is how you write it with a for, // not <foo/<bar>> or whatever. for(var i = 0; i < ltAlts.length; i++) { const lt = ltAlts[i]; const match = /<(.*)>/.exec(lt); if(match) { ltAlts[i] = match[1]; } } } let forAlts; if(dfn.hasAttribute('data-dfn-for')) { forAlts = dfn.getAttribute('data-dfn-for') .split(",") .map(x=>x.trim()); } else { forAlts = ['']; } let linkingSyntaxes = []; if(!needsFor(type)) { for(const lt of ltAlts) { linkingSyntaxes.push(linkFormatter(lt)); } } if(!refusesFor(type)) { for(const f of forAlts) { linkingSyntaxes.push(linkFormatter(`${f}/${ltAlts[0]}`)) } } return [ mk.b({}, 'Possible linking syntaxes:'), mk.ul({}, ...linkingSyntaxes.map(link => { const copyLink = async () => await navigator.clipboard.writeText(link); return mk.li({}, mk.div({ class: 'link-item' }, mk.button({ class: 'copy-icon', title: 'Copy', type: 'button', _onclick: copyLink, tabindex: 0, }, mk.span({ class: 'icon' }) ), mk.span({}, link) ) ); }) ) ]; } } </script> <script>/* Boilerplate: script-position-annos */ "use strict"; { function repositionAnnoPanels(){ const panels = [...document.querySelectorAll("[data-anno-for]")]; hydratePanels(panels); let vSoFar = 0; for(const panel of panels.sort(cmpTops)) { if(panel.top < vSoFar) { panel.top = vSoFar; panel.style.top = vSoFar + "px"; } vSoFar = panel.top + panel.height + 15; } } function hydratePanels(panels) { const main = document.querySelector("main"); let mainRect; if(main) mainRect = main.getBoundingClientRect(); // First display them all, if they're not already visible. for(const panel of panels) { panel.classList.remove("unpositioned"); } // Measure them all for(const panel of panels) { const dfn = document.getElementById(panel.getAttribute("data-anno-for")); if(!dfn) { console.log("Can't find the annotation panel target:", panel); continue; } panel.dfn = dfn; panel.top = window.scrollY + dfn.getBoundingClientRect().top; let panelRect = panel.getBoundingClientRect(); panel.height = panelRect.height; if(main) { panel.overlappingMain = panelRect.left < mainRect.right; } else { panel.overlappingMain = false; } } // And finally position them for(const panel of panels) { const dfn = panel.dfn; if(!dfn) continue; panel.style.top = panel.top + "px"; panel.classList.toggle("overlapping-main", panel.overlappingMain); } } function cmpTops(a,b) { return a.top - b.top; } window.addEventListener("load", repositionAnnoPanels); window.addEventListener("resize", repositionAnnoPanels); } </script> <script>/* Boilerplate: script-ref-hints */ "use strict"; { let refsData = { "#propdef-will-change": {"displayText":"will-change","export":true,"for_":[],"level":"1","normative":true,"shortname":"css-will-change","spec":"css-will-change-1","status":"local","text":"will-change","type":"property","url":"#propdef-will-change"}, "#typedef-animateable-feature": {"displayText":"<animateable-feature>","export":true,"for_":[],"level":"1","normative":true,"shortname":"css-will-change","spec":"css-will-change-1","status":"local","text":"<animateable-feature>","type":"type","url":"#typedef-animateable-feature"}, "#valdef-will-change-auto": {"displayText":"auto","export":true,"for_":["will-change"],"level":"1","normative":true,"shortname":"css-will-change","spec":"css-will-change-1","status":"local","text":"auto","type":"value","url":"#valdef-will-change-auto"}, "#valdef-will-change-contents": {"displayText":"contents","export":true,"for_":["will-change"],"level":"1","normative":true,"shortname":"css-will-change","spec":"css-will-change-1","status":"local","text":"contents","type":"value","url":"#valdef-will-change-contents"}, "#valdef-will-change-scroll-position": {"displayText":"scroll-position","export":true,"for_":["will-change"],"level":"1","normative":true,"shortname":"css-will-change","spec":"css-will-change-1","status":"local","text":"scroll-position","type":"value","url":"#valdef-will-change-scroll-position"}, "https://drafts.csswg.org/css-backgrounds-3/#propdef-background": {"displayText":"background","export":true,"for_":[],"level":"3","normative":true,"shortname":"css-backgrounds","spec":"css-backgrounds-3","status":"current","text":"background","type":"property","url":"https://drafts.csswg.org/css-backgrounds-3/#propdef-background"}, "https://drafts.csswg.org/css-color-4/#propdef-opacity": {"displayText":"opacity","export":true,"for_":[],"level":"4","normative":true,"shortname":"css-color","spec":"css-color-4","status":"current","text":"opacity","type":"property","url":"https://drafts.csswg.org/css-color-4/#propdef-opacity"}, "https://drafts.csswg.org/css-transforms-1/#propdef-transform": {"displayText":"transform","export":true,"for_":[],"level":"1","normative":true,"shortname":"css-transforms","spec":"css-transforms-1","status":"current","text":"transform","type":"property","url":"https://drafts.csswg.org/css-transforms-1/#propdef-transform"}, "https://drafts.csswg.org/css-values-4/#comb-one": {"displayText":"|","export":true,"for_":[],"level":"4","normative":true,"shortname":"css-values","spec":"css-values-4","status":"current","text":"|","type":"grammar","url":"https://drafts.csswg.org/css-values-4/#comb-one"}, "https://drafts.csswg.org/css-values-4/#css-wide-keywords": {"displayText":"CSS-wide keywords","export":true,"for_":[],"level":"4","normative":true,"shortname":"css-values","spec":"css-values-4","status":"current","text":"css-wide keywords","type":"dfn","url":"https://drafts.csswg.org/css-values-4/#css-wide-keywords"}, "https://drafts.csswg.org/css-values-4/#identifier-value": {"displayText":"<custom-ident>","export":true,"for_":[],"level":"4","normative":true,"shortname":"css-values","spec":"css-values-4","status":"current","text":"<custom-ident>","type":"type","url":"https://drafts.csswg.org/css-values-4/#identifier-value"}, "https://drafts.csswg.org/css-values-4/#mult-comma": {"displayText":"#","export":true,"for_":[],"level":"4","normative":true,"shortname":"css-values","spec":"css-values-4","status":"current","text":"#","type":"grammar","url":"https://drafts.csswg.org/css-values-4/#mult-comma"}, "https://infra.spec.whatwg.org/#ascii-case-insensitive": {"displayText":"ASCII case-insensitive","export":true,"for_":[],"level":"1","normative":true,"shortname":"infra","spec":"infra","status":"current","text":"ascii case-insensitive","type":"dfn","url":"https://infra.spec.whatwg.org/#ascii-case-insensitive"}, }; function mkRefHint(link, ref) { const linkText = link.textContent; let dfnTextElements = ''; if (ref.displayText.toLowerCase() != linkText.toLowerCase()) { // Give the original term if it's being displayed in a different way. // But allow casing differences, they're insignificant. dfnTextElements = mk.li({}, mk.b({}, "Term: "), mk.span({}, ref.displayText) ); } const forList = ref.for_; let forListElements; if(forList.length == 0) { forListElements = []; } else if(forList.length == 1) { forListElements = mk.li({}, mk.b({}, "For: "), mk.span({}, forList[0]), ); } else { forListElements = mk.li({}, mk.b({}, "For: "), mk.ul({}, ...forList.map(forItem => mk.li({}, mk.span({}, forItem) ), ), ), ); } const url = ref.url; const safeUrl = encodeURIComponent(url); const hintPanel = mk.aside({ class: "ref-hint", id: `ref-hint-for-${safeUrl}`, "data-for": url, "aria-labelled-by": `ref-hint-for-${safeUrl}`, }, mk.ul({}, dfnTextElements, mk.li({}, mk.b({}, "URL: "), mk.a({ href: url, class: "ref" }, url), ), mk.li({}, mk.b({}, "Type: "), mk.span({}, `${ref.type}`), ), mk.li({}, mk.b({}, "Spec: "), mk.span({}, `${ref.spec ? ref.spec : ''}`), ), forListElements ), ); hintPanel.forLink = link; setupRefHintEventListeners(link, hintPanel); return hintPanel; } function hideAllRefHints() { queryAll(".ref-hint").forEach(el=>hideRefHint(el)); } function hideRefHint(refHint) { const link = refHint.forLink; link.setAttribute("aria-expanded", "false"); if(refHint.teardownEventListeners) { refHint.teardownEventListeners(); } refHint.remove(); } function showRefHint(link) { if(link.classList.contains("dfn-link")) return; const url = link.getAttribute("href"); const ref = refsData[url]; if(!ref) return; hideAllRefHints(); // Only display one at this time. const refHint = mkRefHint(link, ref); append(document.body, refHint); link.setAttribute("aria-expanded", "true"); positionRefHint(refHint); } function setupRefHintEventListeners(link, refHint) { if (refHint.teardownEventListeners) return; // Add event handlers to hide the refHint after the user moves away // from both the link and refHint, if not hovering either within one second. let timeout = null; const startHidingRefHint = (event) => { if (timeout) { clearTimeout(timeout); } timeout = setTimeout(() => { hideRefHint(refHint); }, 1000); } const resetHidingRefHint = (event) => { if (timeout) clearTimeout(timeout); timeout = null; }; link.addEventListener("mouseleave", startHidingRefHint); link.addEventListener("mouseenter", resetHidingRefHint); link.addEventListener("blur", startHidingRefHint); link.addEventListener("focus", resetHidingRefHint); refHint.addEventListener("mouseleave", startHidingRefHint); refHint.addEventListener("mouseenter", resetHidingRefHint); refHint.addEventListener("blur", startHidingRefHint); refHint.addEventListener("focus", resetHidingRefHint); refHint.teardownEventListeners = () => { // remove event listeners resetHidingRefHint(); link.removeEventListener("mouseleave", startHidingRefHint); link.removeEventListener("mouseenter", resetHidingRefHint); link.removeEventListener("blur", startHidingRefHint); link.removeEventListener("focus", resetHidingRefHint); refHint.removeEventListener("mouseleave", startHidingRefHint); refHint.removeEventListener("mouseenter", resetHidingRefHint); refHint.removeEventListener("blur", startHidingRefHint); refHint.removeEventListener("focus", resetHidingRefHint); }; } function positionRefHint(refHint) { const link = refHint.forLink; const linkPos = getBounds(link); refHint.style.top = linkPos.bottom + "px"; refHint.style.left = linkPos.left + "px"; const panelPos = refHint.getBoundingClientRect(); const panelMargin = 8; const maxRight = document.body.parentNode.clientWidth - panelMargin; if (panelPos.right > maxRight) { const overflowAmount = panelPos.right - maxRight; const newLeft = Math.max(panelMargin, linkPos.left - overflowAmount); refHint.style.left = newLeft + "px"; } } // TODO: shared util // Returns the root-level absolute position {left and top} of element. function getBounds(el, relativeTo=document.body) { const relativeRect = relativeTo.getBoundingClientRect(); const elRect = el.getBoundingClientRect(); const top = elRect.top - relativeRect.top; const left = elRect.left - relativeRect.left; return { top, left, bottom: top + elRect.height, right: left + elRect.width, } } function showRefHintListener(e) { // If the target isn't in a link (or is a link), // just ignore it. let link = e.target.closest("a"); if(!link) return; // If the target is in a ref-hint panel // (aka a link in the already-open one), // also just ignore it. if(link.closest(".ref-hint")) return; // Otherwise, show the panel for the link. showRefHint(link); } function hideAllHintsListener(e) { // If the click is inside a ref-hint panel, ignore it. if(e.target.closest(".ref-hint")) return; // Otherwise, close all the current panels. hideAllRefHints(); } document.addEventListener("DOMContentLoaded", () => { document.body.addEventListener("mousedown", showRefHintListener); document.body.addEventListener("focus", showRefHintListener); document.body.addEventListener("click", hideAllHintsListener); }); window.addEventListener("resize", () => { // Hide any open ref hint. hideAllRefHints(); }); } </script>