<!DOCTYPE html>
<title>Tests the CSSOM interfaces of @position-try rules</title>
<link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#interfaces">
<link rel="author" href="mailto:[email protected]">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="anchor"></div>
<div id="other-anchor"></div>
<div id="target"></div>
<script>
function createStyle(t, text) {
const style = document.createElement('style');
style.textContent = text;
t.add_cleanup(() => style.remove());
document.head.appendChild(style);
return style;
}
test(t => {
const style = createStyle(
t, '@position-try --pf { left: anchor(right); }');
const positionTryRule = style.sheet.cssRules[0];
assert_true(positionTryRule instanceof CSSPositionTryRule);
assert_equals(positionTryRule.name, '--pf');
assert_true(positionTryRule.style instanceof CSSPositionTryDescriptors);
assert_equals(positionTryRule.style.length, 1);
assert_equals(positionTryRule.style.left, 'anchor(right)');
}, 'CSSPositionTryRule attribute values');
test(t => {
const style = createStyle(t, `
@position-try --pf { top: anchor(top); left: 0; }
#anchor, #other-anchor, #target {
position: absolute; width: 100px; height: 100px;
}
#anchor { top: 100px; left: 0; anchor-name: --a; }
#other-anchor { top: 200px; left: 0; anchor-name: --b; }
#target { position-try-fallbacks: --pf; position-anchor: --a; left: 999999px; }
`);
const positionTryRule = style.sheet.cssRules[0];
// Check the initial position fallback result
assert_equals(target.getBoundingClientRect().left, 0);
assert_equals(target.getBoundingClientRect().top, 100);
// `left` is an allowed property in `@position-try` and should affect position fallback.
positionTryRule.style.setProperty('left', 'anchor(right)');
assert_equals(target.getBoundingClientRect().left, 100);
assert_equals(target.getBoundingClientRect().top, 100);
// This property are disallowed in `@position-try` rule, and hence should not affect
// position fallback.
positionTryRule.style.setProperty('position', 'static');
assert_equals(target.getBoundingClientRect().left, 100);
assert_equals(target.getBoundingClientRect().top, 100);
// `position-anchor` is an allowed property in `@position-try` and should affect position fallback.
positionTryRule.style.setProperty('position-anchor', '--b');
assert_equals(target.getBoundingClientRect().left, 100);
assert_equals(target.getBoundingClientRect().top, 200);
}, 'CSSPositionTryRule.style.setProperty setting allowed and disallowed properties');
test(t => {
const style = createStyle(t, `
@position-try --pf {
top: 10px;
left: 20px;
--x: 200px;
color: red;
}
`);
let declarations = style.sheet.cssRules[0].style;
assert_equals(declarations.length, 2);
assert_equals(declarations.item(0), 'top');
assert_equals(declarations.item(1), 'left');
}, 'CSSPositionTryDescriptors.item');
test(t => {
const style = createStyle(t, '@position-try --pf {}');
let declarations = style.sheet.cssRules[0].style;
assert_equals(declarations.length, 0);
declarations.cssText = `color:red;top:10px;`;
assert_equals(declarations.length, 1);
}, 'CSSPositionTryDescriptors.cssText');
let supported_properties = [
'margin',
'margin-top',
'margin-right',
'margin-bottom',
'margin-left',
'margin-block',
'margin-block-start',
'margin-block-end',
'margin-inline',
'margin-inline-start',
'margin-inline-end',
'inset',
'top',
'left',
'right',
'bottom',
'inset-block',
'inset-block-start',
'inset-block-end',
'inset-inline',
'inset-inline-start',
'inset-inline-end',
'width',
'height',
'min-width',
'max-width',
'min-height',
'max-height',
'block-size',
'min-block-size',
'max-block-size',
'inline-size',
'min-inline-size',
'max-inline-size',
'place-self',
'align-self',
'justify-self',
'position-anchor',
'position-area',
];
// A selection of unsupported properties.
let unsupported_properties = [
'color',
'align-items',
'align-content',
'background',
'display',
'position',
'writing-mode',
'direction',
'syntax', // @property
];
let upperFirst = (x) => x[0].toUpperCase() + x.slice(1);
let lowerFirst = (x) => x[0].toLowerCase() + x.slice(1);
let toLowerCamelCase = (x) => lowerFirst(x.split('-').map(upperFirst).join(''));
// Test getting/setting the specified property on a CSSPositionTryDescriptors
// object. The property can either be supported or not supported,
// which determines the expected results.
function test_property(prop, supported) {
test(t => {
let decls = supported_properties.map(x => `${x}:unset;`).join('');
let style = createStyle(t, `@position-try --pf { ${decls} }`);
let declarations = style.sheet.cssRules[0].style;
assert_equals(declarations.getPropertyValue(prop), supported ? 'unset' : '');
}, `CSSPositionTryDescriptors.getPropertyValue(${prop})`);
test(t => {
let style = createStyle(t, '@position-try --pf {}');
let declarations = style.sheet.cssRules[0].style;
declarations.setProperty(prop, 'unset');
assert_equals(declarations.getPropertyValue(prop), supported ? 'unset' : '');
}, `CSSPositionTryDescriptors.setProperty(${prop})`);
test(t => {
let decls = supported_properties.map(x => `${x}:unset;`).join('');
let style = createStyle(t, `@position-try --pf { ${decls} }`);
let declarations = style.sheet.cssRules[0].style;
assert_equals(declarations[prop], supported ? 'unset' : undefined);
}, `CSSPositionTryDescriptors[${prop}] (set)`);
test(t => {
let style = createStyle(t, '@position-try --pf {}');
let declarations = style.sheet.cssRules[0].style;
declarations[prop] = 'unset';
assert_equals(declarations.getPropertyValue(prop), supported ? 'unset' : '');
}, `CSSPositionTryDescriptors[${prop}] (get)`);
let camelCaseAttr = toLowerCamelCase(prop);
if (camelCaseAttr != prop) {
// Also test the camelCase version of the attribute.
test(t => {
let decls = supported_properties.map(x => `${x}:unset;`).join('');
let style = createStyle(t, `@position-try --pf { ${decls} }`);
let declarations = style.sheet.cssRules[0].style;
assert_equals(declarations[camelCaseAttr], supported ? 'unset' : undefined);
}, `CSSPositionTryDescriptors[${camelCaseAttr}] (get)`);
test(t => {
let style = createStyle(t, '@position-try --pf {}');
let declarations = style.sheet.cssRules[0].style;
declarations[camelCaseAttr] = 'unset';
assert_equals(declarations.getPropertyValue(prop), supported ? 'unset' : '');
}, `CSSPositionTryDescriptors[${camelCaseAttr}] (set)`);
}
}
supported_properties.forEach(x => { test_property(x, /* supported */ true); });
unsupported_properties.forEach(x => { test_property(x, /* supported */ false); });
</script>