<!doctype html>
<title>CSS Container Queries Test: custom property style queries</title>
<link rel="help" href="https://drafts.csswg.org/css-conditional-5/#style-container">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/cq-testcommon.js"></script>
<style>
#outer {
container-name: outer;
--inner: false;
--outer: true;
--inner-no-space:false;
--outer-no-space:true;
--inner-space-after:false ;
--outer-space-after:true ;
}
#inner {
--inner: true;
--outer: false;
--inner-no-space:true;
--outer-no-space:false;
--inner-space-after:true ;
--outer-space-after:false ;
}
</style>
<div id="outer">
<div id="inner">
<div id="target"></div>
<div id="fliptarget"></div>
</div>
</div>
<script>
const green = "rgb(0, 128, 0)";
function test_evaluation(name, query, expected) {
test((t) => {
let style_node = document.createElement('style');
t.add_cleanup(() => {
style_node.remove();
});
style_node.innerText = `
@container ${name} ${query} { #target { --applied:true; } }
@container ${name} not ${query} { #fliptarget { --applied:true; } }
`;
assert_equals(getComputedStyle(target).getPropertyValue('--applied'), '',
'Initial --applied for target');
assert_equals(getComputedStyle(fliptarget).getPropertyValue('--applied'), '',
'Initial --applied for fliptarget');
document.head.append(style_node);
assert_equals(getComputedStyle(target).getPropertyValue('--applied'), expected ? 'true' : '',
'Matching query for #target');
assert_equals(getComputedStyle(fliptarget).getPropertyValue('--applied'), expected ? '' : 'true',
'Matching negated query for #fliptarget');
}, `${name} ${query}`);
}
setup(() => assert_implements_container_queries());
test_evaluation('', 'style(--inner: true)', true);
test_evaluation('', 'style(--inner:true)', true);
test_evaluation('', 'style(--inner:true )', true);
test_evaluation('', 'style(--inner: true )', true);
test_evaluation('', 'style(--inner-no-space: true)', true);
test_evaluation('', 'style(--inner-no-space:true)', true);
test_evaluation('', 'style(--inner-no-space:true )', true);
test_evaluation('', 'style(--inner-no-space: true )', true);
test_evaluation('', 'style(--inner-space-after: true)', true);
test_evaluation('', 'style(--inner-space-after:true)', true);
test_evaluation('', 'style(--inner-space-after:true )', true);
test_evaluation('', 'style(--inner-space-after: true )', true);
test_evaluation('', 'style(--outer: true)', false);
test_evaluation('', 'style(--outer:true)', false);
test_evaluation('', 'style(--outer:true )', false);
test_evaluation('', 'style(--outer: true )', false);
test_evaluation('', 'style(--outer-no-space: true)', false);
test_evaluation('', 'style(--outer-no-space:true)', false);
test_evaluation('', 'style(--outer-no-space:true )', false);
test_evaluation('', 'style(--outer-no-space: true )', false);
test_evaluation('', 'style(--outer-space-after: true)', false);
test_evaluation('', 'style(--outer-space-after:true)', false);
test_evaluation('', 'style(--outer-space-after:true )', false);
test_evaluation('', 'style(--outer-space-after: true )', false);
test_evaluation('outer', 'style(--inner: true)', false);
test_evaluation('outer', 'style(--inner:true)', false);
test_evaluation('outer', 'style(--inner:true )', false);
test_evaluation('outer', 'style(--inner: true )', false);
test_evaluation('outer', 'style(--inner-no-space: true)', false);
test_evaluation('outer', 'style(--inner-no-space:true)', false);
test_evaluation('outer', 'style(--inner-no-space:true )', false);
test_evaluation('outer', 'style(--inner-no-space: true )', false);
test_evaluation('outer', 'style(--inner-space-after: true)', false);
test_evaluation('outer', 'style(--inner-space-after:true)', false);
test_evaluation('outer', 'style(--inner-space-after:true )', false);
test_evaluation('outer', 'style(--inner-space-after: true )', false);
test_evaluation('outer', 'style(--outer: true)', true);
test_evaluation('outer', 'style(--outer:true)', true);
test_evaluation('outer', 'style(--outer:true )', true);
test_evaluation('outer', 'style(--outer: true )', true);
test_evaluation('outer', 'style(--outer-no-space: true)', true);
test_evaluation('outer', 'style(--outer-no-space:true)', true);
test_evaluation('outer', 'style(--outer-no-space:true )', true);
test_evaluation('outer', 'style(--outer-no-space: true )', true);
test_evaluation('outer', 'style(--outer-space-after: true)', true);
test_evaluation('outer', 'style(--outer-space-after:true)', true);
test_evaluation('outer', 'style(--outer-space-after:true )', true);
test_evaluation('outer', 'style(--outer-space-after: true )', true);
</script>
<style>
#important {
--foo: bar;
}
@container style(--foo: bar !important) {
#important-child { color: green; }
}
</style>
<div id="important">
<div id="important-child"></div>
</div>
<script>
test(() => {
assert_equals(getComputedStyle(document.querySelector("#important-child")).color, green);
}, "Query custom property with !important declaration");
</script>
<style>
#var-query {
--foo: baz;
--bar: baz;
}
@container style(--foo: var(--bar)) {
#var-subst { color: green; }
}
@container not style(--foo: var(--unknown)) {
#var-subst-unknown { color: green; }
}
@container not style(--foo: var(--unknown, nomatch)) {
#var-subst-unknown-fallback { color: green; }
}
@container style(--foo: var(--unknown, baz)) {
#var-subst-matching-fallback { color: green; }
}
@container style(--baz: var(--unknown)) {
#var-subst-unknown-matching { color: green; }
}
</style>
<div id="var-query">
<div id="var-subst"></div>
<div id="var-subst-unknown"></div>
<div id="var-subst-unknown-fallback"></div>
<div id="var-subst-matching-fallback"></div>
<div id="var-subst-unknown-matching"></div>
</div>
<script>
test(() => {
assert_equals(getComputedStyle(document.querySelector("#var-subst")).color, green);
}, "Query custom property using var()");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#var-subst-unknown")).color, green);
}, "Query custom property including unknown var() reference");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#var-subst-unknown-fallback")).color, green);
}, "Query custom property including unknown var() reference with non-matching fallback");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#var-subst-matching-fallback")).color, green);
}, "Query custom property including unknown var() reference with matching fallback");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#var-subst-unknown-matching")).color, green);
}, "Query custom property matching guaranteed-invalid values");
</script>
<style>
#revert {
--foo: revert;
}
#revert-layer {
--foo: revert-layer;
}
@container not style(--foo: revert) {
#revert-child { color: green; }
}
@container not style(--foo: revert-layer) {
#revert-layer-child { color: green; }
}
@container style(--foo: revert) {
#revert-child { color: red; }
}
@container style(--foo: revert-layer) {
#revert-layer-child { color: red; }
}
</style>
<div id="revert">
<div id="revert-child"></div>
</div>
<div id="revert-layer">
<div id="revert-layer-child"></div>
</div>
<script>
test(() => {
assert_equals(getComputedStyle(document.querySelector("#revert-child")).color, green);
}, "Style query with revert keyword is false");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#revert-layer-child")).color, green);
}, "Style query with revert-layer keyword is false");
</script>
<style>
#defaulting {
--inherit: baz;
--inherit-no: baz;
}
#defaulting-container {
--inherit-no: bar;
--unset-no: baz;
--initial-no: baz;
--space-no: baz;
--explicit-initial: initial;
--space: ;
}
@container style(--initial: initial) {
#initial { color: green; }
}
@container not style(--initial) {
#initial-implicit { color: green; }
}
@container not style(--initial-no: initial) {
#initial-no { color: green; }
}
@container style(--initial-no) {
#initial-no-implicit { color: green; }
}
@container style(--inherit: inherit) {
#inherit { color: green; }
}
@container not style(--inherit-no: inherit) {
#inherit-no { color: green; }
}
@container style(--explicit-initial: initial) {
#explicit-initial { color: green; }
}
@container not style(--explicit-initial) {
#explicit-initial-implicit { color: green; }
}
@container style(--space: ) {
#space { color: green; }
}
@container not style(--space-no: ) {
#space-no { color: green; }
}
@container style(--unset: unset) {
#unset { color: green; }
}
@container not style(--unset-no: unset) {
#unset-no { color: green; }
}
</style>
<div id="defaulting">
<div id="defaulting-container">
<div id="initial"></div>
<div id="initial-implicit"></div>
<div id="initial-no"></div>
<div id="initial-no-implicit"></div>
<div id="explicit-initial"></div>
<div id="explicit-initial-implicit"></div>
<div id="space"></div>
<div id="space-no"></div>
<div id="inherit"></div>
<div id="inherit-no"></div>
<div id="unset"></div>
<div id="unset-no"></div>
</div>
</div>
<script>
test(() => {
assert_equals(getComputedStyle(document.querySelector("#initial")).color, green);
}, "Style query 'initial' matching");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#initial-implicit")).color, green);
}, "Style query matching negated value-less query against initial value");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#initial-no")).color, green);
}, "Style query 'initial' not matching");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#initial-no-implicit")).color, green);
}, "Style query matching value-less query against non-initial value");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#explicit-initial")).color, green);
}, "Style query 'initial' matching (with explicit 'initial' value)");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#explicit-initial-implicit")).color, green);
}, "Style query matching negated value-less query against initial value (with explicit 'initial' value)");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#space")).color, green);
}, "Style query 'space' matching");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#space-no")).color, green);
}, "Style query 'space' not matching");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#inherit")).color, green);
}, "Style query 'inherit' matching");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#inherit-no")).color, green);
}, "Style query 'inherit' not matching");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#unset")).color, green);
}, "Style query 'unset' matching");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#unset-no")).color, green);
}, "Style query 'unset' not matching");
</script>
<style>
@property --reg-length {
syntax: "<length>";
inherits: false;
initial-value: 10px;
}
#registered {
container-type: inline-size;
width: 200px;
font-size: 20px;
}
#reg-container-px {
--reg-length: 10px;
}
@container style(--reg-length: 10px) {
#reg-px { color: green; }
}
@container style(--reg-length: initial) {
#reg-px-initial { color: green; }
}
@container not style(--reg-length) {
#reg-px-initial-implicit { color: green; }
}
#reg-container-font-relative {
--reg-length: 10px;
}
@container style(--reg-length: 0.5em) {
#reg-font-relative { color: green; }
}
#reg-container-font-relative-2 {
--reg-length: 0.5em;
}
@container style(--reg-length: 10px) {
#reg-font-relative-2 { color: green; }
}
#reg-container-container-relative {
width: 100px;
--reg-length: 100px;
}
@container style(--reg-length: 50cqi) {
#reg-container-relative { color: green; }
}
#reg-container-initial {
--reg-length: 10px;
}
@container style(--reg-length: 10px) {
#reg-initial-value { color: green; }
}
@container style(--reg-length: initial) {
#reg-initial-keyword { color: green; }
}
@container not style(--reg-length) {
#reg-initial-implicit { color: green; }
}
</style>
<div id="registered">
<div id="reg-container-px">
<div id="reg-px"></div>
<div id="reg-px-initial"></div>
<div id="reg-px-initial-implicit"></div>
</div>
<div id="reg-container-font-relative">
<div id="reg-font-relative"></div>
</div>
<div id="reg-container-font-relative-2">
<div id="reg-font-relative-2"></div>
</div>
<div id="reg-container-container-relative">
<div id="reg-container-relative"></div>
</div>
<div id="reg-container-initial">
<div id="reg-initial-value"></div>
<div id="reg-initial-keyword"></div>
<div id="reg-initial-implicit"></div>
</div>
</div>
<script>
test(() => {
assert_equals(getComputedStyle(document.querySelector("#reg-px")).color, green);
}, "Match registered <length> custom property with px.");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#reg-px-initial")).color, green);
}, "Match registered <length> custom property with px via initial keyword.");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#reg-font-relative")).color, green);
}, "Match registered <length> custom property with em in query.");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#reg-font-relative-2")).color, green);
}, "Match registered <length> custom property with em in computed value.");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#reg-container-relative")).color, green);
}, "Match registered <length> custom property with cqi unit.");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#reg-initial-value")).color, green);
}, "Match registered <length> custom property with initial value.");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#reg-initial-keyword")).color, green);
}, "Match registered <length> custom property with initial value via initial keyword.");
</script>
<style>
#original-text {
--number: 100.00;
--spaces: a b;
}
@container style(--number: 100.00) {
#original-text-number {
color: green;
}
}
@container style(--number: 100.0) {
#original-text-number {
color: red;
}
}
@container style(--number: 100) {
#original-text-number {
color: red;
}
}
@container style(--spaces: a b) {
#original-text-spaces {
color: green;
}
}
@container style(--spaces: a b) {
#original-text-spaces {
color: red;
}
}
</style>
<div id="original-text">
<div id="original-text-number"></div>
<div id="original-text-spaces"></div>
</div>
<script>
test(() => {
assert_equals(getComputedStyle(document.querySelector("#original-text-number")).color, green);
}, "Should only match exact string for numbers in non-registered custom properties");
test(() => {
assert_equals(getComputedStyle(document.querySelector("#original-text-spaces")).color, green);
}, "Spaces should not collapse in non-registered custom properties");
</script>