diff --git a/.stylelintrc.json b/.stylelintrc.json index 3fbc98ab7e..11cd3594eb 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -1,6 +1,6 @@ { "extends": ["stylelint-config-standard-scss"], - "plugins": ["stylelint-order"], + "plugins": ["stylelint-order", "stylelint-use-logical"], "rules": { "alpha-value-notation": ["percentage"], "at-rule-empty-line-before": null, @@ -9,6 +9,7 @@ "color-function-notation": ["modern"], "color-no-invalid-hex": true, "comment-no-empty": true, + "csstools/use-logical": true, "custom-property-pattern": "^_?(ams|nl|utrecht)-[a-z0-9-]+$", "declaration-block-no-duplicate-properties": true, "declaration-block-no-redundant-longhand-properties": null, @@ -50,16 +51,18 @@ "order/properties-alphabetical-order": true, "property-disallowed-list": [ [ + "contain-intrinsic-height", + "contain-intrinsic-width", "margin", - "margin-bottom", - "margin-left", - "margin-right", - "margin-top", "padding", - "padding-bottom", - "padding-left", - "padding-right", - "padding-top" + "scroll-margin-bottom", + "scroll-margin-left", + "scroll-margin-right", + "scroll-margin-top", + "scroll-padding-bottom", + "scroll-padding-left", + "scroll-padding-right", + "scroll-padding-top" ] ], "property-no-unknown": true, diff --git a/package.json b/package.json index f217eb6b49..7975a2975c 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "stylelint": "16.5.0", "stylelint-config-standard-scss": "13.1.0", "stylelint-order": "6.0.4", + "stylelint-use-logical": "2.1.2", "typescript": "5.4.5", "wait-on": "7.2.0" }, diff --git a/packages/css/src/common/hide-input.scss b/packages/css/src/common/hide-input.scss index 3bffc3da23..e7c3026bc0 100644 --- a/packages/css/src/common/hide-input.scss +++ b/packages/css/src/common/hide-input.scss @@ -5,7 +5,7 @@ @mixin hide-input { appearance: none; + inline-size: 0; // Make sure the input doesn’t take up space on iOS margin-block: 0; margin-inline: 0; - width: 0; // Make sure the input doesn’t take up space on iOS } diff --git a/packages/css/src/components/accordion/accordion.scss b/packages/css/src/components/accordion/accordion.scss index d6ef1a0e1a..58652366d0 100644 --- a/packages/css/src/components/accordion/accordion.scss +++ b/packages/css/src/components/accordion/accordion.scss @@ -29,10 +29,10 @@ font-size: var(--ams-accordion-button-font-size); font-weight: var(--ams-accordion-button-font-weight); gap: var(--ams-accordion-button-gap); + inline-size: 100%; line-height: var(--ams-accordion-button-line-height); padding-block: var(--ams-accordion-button-padding-block); padding-inline: var(--ams-accordion-button-padding-inline); - width: 100%; &:focus { outline-offset: var(--ams-accordion-button-focus-outline-offset); diff --git a/packages/css/src/components/avatar/avatar.scss b/packages/css/src/components/avatar/avatar.scss index b267996dea..229ea363ae 100644 --- a/packages/css/src/components/avatar/avatar.scss +++ b/packages/css/src/components/avatar/avatar.scss @@ -9,11 +9,11 @@ display: inline-flex; font-family: var(--ams-avatar-font-family); font-size: var(--ams-avatar-font-size); + inline-size: calc(var(--ams-avatar-line-height) * var(--ams-avatar-font-size)); line-height: var(--ams-avatar-line-height); padding-block: var(--ams-avatar-padding-block); padding-inline: var(--ams-avatar-padding-inline); place-content: center; - width: calc(var(--ams-avatar-line-height) * var(--ams-avatar-font-size)); svg { fill: currentColor; @@ -21,11 +21,11 @@ } .ams-avatar--has-image { + inline-size: calc(var(--ams-avatar-line-height) * var(--ams-avatar-font-size) + 2 * var(--ams-avatar-padding-inline)); overflow: hidden; padding-block: 0; padding-inline: 0; vertical-align: middle; /* Remove ‘phantom’ white space when image doesn’t load */ - width: calc(var(--ams-avatar-line-height) * var(--ams-avatar-font-size) + 2 * var(--ams-avatar-padding-inline)); } .ams-avatar--blue { diff --git a/packages/css/src/components/breadcrumb/breadcrumb.scss b/packages/css/src/components/breadcrumb/breadcrumb.scss index c3c59c2897..1a43f4ffd6 100644 --- a/packages/css/src/components/breadcrumb/breadcrumb.scss +++ b/packages/css/src/components/breadcrumb/breadcrumb.scss @@ -33,11 +33,11 @@ .ams-breadcrumb__item:not(:last-child)::after { background-image: var(--ams-breadcrumb-separator-background-image); background-repeat: no-repeat; + block-size: 1ex; content: ""; display: inline-block; - height: 1ex; + inline-size: 1ex; margin-inline: 0.5rem; - width: 1ex; } .ams-breadcrumb__link { diff --git a/packages/css/src/components/checkbox/checkbox.scss b/packages/css/src/components/checkbox/checkbox.scss index 408eab9f65..c05ba3e980 100644 --- a/packages/css/src/components/checkbox/checkbox.scss +++ b/packages/css/src/components/checkbox/checkbox.scss @@ -14,22 +14,22 @@ .ams-checkbox__checkmark { align-items: center; + block-size: calc(var(--ams-checkbox-font-size) * var(--ams-checkbox-line-height)); display: flex; flex-shrink: 0; - height: calc(var(--ams-checkbox-font-size) * var(--ams-checkbox-line-height)); - width: 1.5rem; + inline-size: 1.5rem; &::after { background-position: center; background-repeat: no-repeat; background-size: 1rem; + block-size: 1.5rem; border-color: var(--ams-checkbox-checkmark-border-color); border-style: solid; border-width: var(--ams-checkbox-checkmark-border-width); box-sizing: border-box; content: ""; - height: 1.5rem; - width: 100%; + inline-size: 100%; } } diff --git a/packages/css/src/components/date-input/date-input.scss b/packages/css/src/components/date-input/date-input.scss index 616c67dc90..74855c3bef 100644 --- a/packages/css/src/components/date-input/date-input.scss +++ b/packages/css/src/components/date-input/date-input.scss @@ -23,13 +23,13 @@ font-weight: var(--ams-date-input-font-weight); line-height: var(--ams-date-input-line-height); - // Set min height for iOS, otherwise an empty box is a lot smaller than a filled one. - min-height: calc( + // Set min block size for iOS, otherwise an empty box is a lot smaller than a filled one. + min-block-size: calc( (var(--ams-date-input-font-size) * var(--ams-date-input-line-height)) + 2 * var(--ams-date-input-padding-block) ); - // Set min width for iOS, so the width is closer to the filled in width. - min-width: calc(8ch + (2 * var(--ams-date-input-padding-inline))); + // Set min inline size for iOS, so the size is closer to the filled in size. + min-inline-size: calc(8ch + (2 * var(--ams-date-input-padding-inline))); outline-offset: var(--ams-date-input-outline-offset); padding-block: var(--ams-date-input-padding-block); padding-inline: var(--ams-date-input-padding-inline); diff --git a/packages/css/src/components/field-set/field-set.scss b/packages/css/src/components/field-set/field-set.scss index f90ffc60d0..c5dbd83589 100644 --- a/packages/css/src/components/field-set/field-set.scss +++ b/packages/css/src/components/field-set/field-set.scss @@ -25,9 +25,9 @@ } @mixin reset-legend { - float: left; // [1] + float: inline-start; // [1] + inline-size: 100%; // [1] padding-inline: 0; - width: 100%; // [1] } // [1] This combination allows the fieldset border to go around the legend, instead of through it. diff --git a/packages/css/src/components/header/header.scss b/packages/css/src/components/header/header.scss index c04ef1ad5c..02743d4a7a 100644 --- a/packages/css/src/components/header/header.scss +++ b/packages/css/src/components/header/header.scss @@ -51,16 +51,16 @@ flex: 1 1 100%; @media screen and (min-width: $ams-breakpoint-wide) { - min-width: 0; + min-inline-size: 0; order: 2; .ams-header__title-heading { display: block; + inline-size: 100%; line-height: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - width: 100%; } } } diff --git a/packages/css/src/components/icon/icon.scss b/packages/css/src/components/icon/icon.scss index 5b963992ae..ac959de509 100644 --- a/packages/css/src/components/icon/icon.scss +++ b/packages/css/src/components/icon/icon.scss @@ -18,37 +18,37 @@ } .ams-icon--size-3 { - height: calc(var(--ams-icon-size-3-font-size) * var(--ams-icon-size-3-line-height)); + block-size: calc(var(--ams-icon-size-3-font-size) * var(--ams-icon-size-3-line-height)); } .ams-icon--size-3 svg { - height: var(--ams-icon-size-3-font-size); - width: var(--ams-icon-size-3-font-size); + block-size: var(--ams-icon-size-3-font-size); + inline-size: var(--ams-icon-size-3-font-size); } .ams-icon--size-4 { - height: calc(var(--ams-icon-size-4-font-size) * var(--ams-icon-size-4-line-height)); + block-size: calc(var(--ams-icon-size-4-font-size) * var(--ams-icon-size-4-line-height)); } .ams-icon--size-4 svg { - height: var(--ams-icon-size-4-font-size); - width: var(--ams-icon-size-4-font-size); + block-size: var(--ams-icon-size-4-font-size); + inline-size: var(--ams-icon-size-4-font-size); } .ams-icon--size-5 { - height: calc(var(--ams-icon-size-5-font-size) * var(--ams-icon-size-5-line-height)); + block-size: calc(var(--ams-icon-size-5-font-size) * var(--ams-icon-size-5-line-height)); } .ams-icon--size-5 svg { - height: var(--ams-icon-size-5-font-size); - width: var(--ams-icon-size-5-font-size); + block-size: var(--ams-icon-size-5-font-size); + inline-size: var(--ams-icon-size-5-font-size); } .ams-icon--size-6 { - height: calc(var(--ams-icon-size-6-font-size) * var(--ams-icon-size-6-line-height)); + block-size: calc(var(--ams-icon-size-6-font-size) * var(--ams-icon-size-6-line-height)); } .ams-icon--size-6 svg { - height: var(--ams-icon-size-6-font-size); - width: var(--ams-icon-size-6-font-size); + block-size: var(--ams-icon-size-6-font-size); + inline-size: var(--ams-icon-size-6-font-size); } diff --git a/packages/css/src/components/image/image.scss b/packages/css/src/components/image/image.scss index 9851e30279..05d5a99a70 100644 --- a/packages/css/src/components/image/image.scss +++ b/packages/css/src/components/image/image.scss @@ -4,9 +4,9 @@ */ .ams-image { + block-size: auto; /* [1] */ font-style: italic; /* [3] */ - height: auto; /* [1] */ - max-width: 100%; /* [1] */ + max-inline-size: 100%; /* [1] */ vertical-align: middle; /* [2] */ &--cover { @@ -14,7 +14,7 @@ } } -// [1] Allow for fluid image sizing while maintaining aspect ratio governed by width/height attributes +// [1] Allow for fluid image sizing while maintaining aspect ratio governed by inline/block size attributes // [2] Remove ‘phantom’ white space // [3] Italicise alt text to visually offset it from surrounding copy // Source: https://x.com/csswizardry/status/1717841334462005661 diff --git a/packages/css/src/components/logo/logo.scss b/packages/css/src/components/logo/logo.scss index 7388462302..43247d6eaf 100644 --- a/packages/css/src/components/logo/logo.scss +++ b/packages/css/src/components/logo/logo.scss @@ -4,8 +4,8 @@ */ .ams-logo { + block-size: var(--ams-logo-block-size); display: block; - height: var(--ams-logo-height); } .ams-logo__emblem { diff --git a/packages/css/src/components/pagination/pagination.scss b/packages/css/src/components/pagination/pagination.scss index fe7329f3f4..be46cfa012 100644 --- a/packages/css/src/components/pagination/pagination.scss +++ b/packages/css/src/components/pagination/pagination.scss @@ -56,8 +56,8 @@ // Override for icon size span.ams-icon svg { - height: 1rem; - width: 1rem; + block-size: 1rem; + inline-size: 1rem; } @include text-rendering; diff --git a/packages/css/src/components/radio/radio.scss b/packages/css/src/components/radio/radio.scss index b062428c55..54667dd758 100644 --- a/packages/css/src/components/radio/radio.scss +++ b/packages/css/src/components/radio/radio.scss @@ -14,23 +14,23 @@ .ams-radio__circle { align-items: center; + block-size: calc(var(--ams-radio-font-size) * var(--ams-radio-line-height)); display: flex; flex-shrink: 0; - height: calc(var(--ams-radio-font-size) * var(--ams-radio-line-height)); - width: 1.5rem; + inline-size: 1.5rem; &::after { background-position: center; background-repeat: no-repeat; background-size: 1rem; + block-size: 1.5rem; border-color: var(--ams-radio-circle-border-color); border-radius: 100%; border-style: solid; border-width: var(--ams-radio-circle-border-width); box-sizing: border-box; content: ""; - height: 1.5rem; - width: 100%; + inline-size: 100%; } } diff --git a/packages/css/src/components/screen/screen.scss b/packages/css/src/components/screen/screen.scss index 48836ea58c..a14abfcb55 100644 --- a/packages/css/src/components/screen/screen.scss +++ b/packages/css/src/components/screen/screen.scss @@ -15,13 +15,13 @@ } .ams-screen--full-height { - min-height: 100vh; + min-block-size: 100vh; } .ams-screen--wide { - max-width: var(--ams-screen-wide-max-width); + max-inline-size: var(--ams-screen-wide-max-inline-size); } .ams-screen--x-wide { - max-width: var(--ams-screen-x-wide-max-width); + max-inline-size: var(--ams-screen-x-wide-max-inline-size); } diff --git a/packages/css/src/components/switch/switch.scss b/packages/css/src/components/switch/switch.scss index 016ab1100f..88816cac2f 100644 --- a/packages/css/src/components/switch/switch.scss +++ b/packages/css/src/components/switch/switch.scss @@ -19,28 +19,28 @@ --ams-switch-track-padding: 0.0625rem; background-color: var(--ams-switch-background-color); - border-radius: calc(var(--ams-switch-thumb-width) * 2); + border-radius: calc(var(--ams-switch-thumb-inline-size) * 2); cursor: pointer; display: inline-block; + inline-size: var(--ams-switch-inline-size); outline-offset: var(--ams-switch-outline-offset); padding-block: var(--ams-switch-track-padding); padding-inline: var(--ams-switch-track-padding); transition: background-color 0.2s ease-in-out; - width: var(--ams-switch-width); @include reset; } .ams-switch__label::before { background-color: var(--ams-switch-thumb-background-color); + block-size: var(--ams-switch-thumb-block-size); border-radius: 50%; content: ""; display: block; - height: var(--ams-switch-thumb-height); + inline-size: var(--ams-switch-thumb-inline-size); transition-duration: 0.1s; transition-property: box-shadow, transform; transition-timing-function: ease-in-out; - width: var(--ams-switch-thumb-width); } .ams-switch__input:checked + .ams-switch__label { @@ -54,7 +54,7 @@ .ams-switch__input:checked + .ams-switch__label::before { transform: translate( - calc(var(--ams-switch-width) - var(--ams-switch-thumb-width) - 2 * var(--ams-switch-track-padding)) + calc(var(--ams-switch-inline-size) - var(--ams-switch-thumb-inline-size) - 2 * var(--ams-switch-track-padding)) ); } diff --git a/packages/css/src/components/table/table.scss b/packages/css/src/components/table/table.scss index 3d20a1f977..bfc3ecf346 100644 --- a/packages/css/src/components/table/table.scss +++ b/packages/css/src/components/table/table.scss @@ -24,7 +24,7 @@ .ams-table__cell, .ams-table__header-cell { - border-bottom: var(--ams-table-cell-border-bottom); + border-block-end: var(--ams-table-cell-border-block-end); padding-block: var(--ams-table-cell-padding-block); padding-inline: var(--ams-table-cell-padding-inline); text-align: start; diff --git a/packages/css/src/components/tabs/tabs.scss b/packages/css/src/components/tabs/tabs.scss index 8fa763dd76..29913fe2b4 100644 --- a/packages/css/src/components/tabs/tabs.scss +++ b/packages/css/src/components/tabs/tabs.scss @@ -12,7 +12,7 @@ .ams-tabs__list { background-color: var(--ams-tabs-list-background-color); - border-bottom: var(--ams-tabs-list-border-bottom); + border-block-end: var(--ams-tabs-list-border-block-end); display: flex; overflow-x: auto; } diff --git a/packages/css/src/components/time-input/time-input.scss b/packages/css/src/components/time-input/time-input.scss index d27ae0cad4..48144c8b90 100644 --- a/packages/css/src/components/time-input/time-input.scss +++ b/packages/css/src/components/time-input/time-input.scss @@ -11,8 +11,8 @@ border: 0; border-radius: 0; // Reset rounded borders on iOS devices box-sizing: border-box; + inline-size: auto; // Reset inline size of 10em set by Android devices margin-block: 0; - width: auto; // Reset width of 10em set by Android devices } .ams-time-input { @@ -24,13 +24,13 @@ font-weight: var(--ams-time-input-font-weight); line-height: var(--ams-time-input-line-height); - // Set min height for iOS, otherwise an empty box is a lot smaller than a filled one. - min-height: calc( + // Set min block size for iOS, otherwise an empty box is a lot smaller than a filled one. + min-block-size: calc( (var(--ams-time-input-font-size) * var(--ams-time-input-line-height)) + 2 * var(--ams-time-input-padding-block) ); - // Set min width for iOS, so the width is closer to the filled in width. - min-width: calc(4ch + (2 * var(--ams-time-input-padding-inline))); + // Set min inline size for iOS, so the size is closer to the filled in size. + min-inline-size: calc(4ch + (2 * var(--ams-time-input-padding-inline))); outline-offset: var(--ams-time-input-outline-offset); padding-block: var(--ams-time-input-padding-block); padding-inline: var(--ams-time-input-padding-inline); diff --git a/packages/css/src/components/visually-hidden/visually-hidden.scss b/packages/css/src/components/visually-hidden/visually-hidden.scss index ea8035d215..ab9ca60648 100644 --- a/packages/css/src/components/visually-hidden/visually-hidden.scss +++ b/packages/css/src/components/visually-hidden/visually-hidden.scss @@ -5,11 +5,11 @@ // Source: https://css-tricks.com/inclusively-hidden/ .ams-visually-hidden:not(:active, :focus) { + block-size: 1px; clip: rect(0 0 0 0); clip-path: inset(50%); - height: 1px; + inline-size: 1px; overflow: hidden; position: absolute; white-space: nowrap; - width: 1px; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 573f74b303..3beec55b4b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -89,6 +89,9 @@ importers: stylelint-order: specifier: 6.0.4 version: 6.0.4(stylelint@16.5.0(typescript@5.4.5)) + stylelint-use-logical: + specifier: 2.1.2 + version: 2.1.2(stylelint@16.5.0(typescript@5.4.5)) typescript: specifier: 5.4.5 version: 5.4.5 @@ -7425,6 +7428,12 @@ packages: peerDependencies: stylelint: ^16.0.2 + stylelint-use-logical@2.1.2: + resolution: {integrity: sha512-4ffvPNk/swH4KS3izExWuzQOuzLmi0gb0uOhvxWJ20vDA5W5xKCjcHHtLoAj1kKvTIX6eGIN5xGtaVin9PD0wg==} + engines: {node: '>=14.0.0'} + peerDependencies: + stylelint: '>= 11 < 17' + stylelint@16.5.0: resolution: {integrity: sha512-IlCBtVrG+qTy3v+tZTk50W8BIomjY/RUuzdrDqdnlCYwVuzXtPbiGfxYqtyYAyOMcb+195zRsuHn6tgfPmFfbw==} engines: {node: '>=18.12.0'} @@ -17370,6 +17379,10 @@ snapshots: postcss-value-parser: 4.2.0 stylelint: 16.5.0(typescript@5.4.5) + stylelint-use-logical@2.1.2(stylelint@16.5.0(typescript@5.4.5)): + dependencies: + stylelint: 16.5.0(typescript@5.4.5) + stylelint@16.5.0(typescript@5.4.5): dependencies: '@csstools/css-parser-algorithms': 2.6.1(@csstools/css-tokenizer@2.2.4) diff --git a/proprietary/tokens/src/components/ams/logo.tokens.json b/proprietary/tokens/src/components/ams/logo.tokens.json index 26e4ec2b77..a13e362f6a 100644 --- a/proprietary/tokens/src/components/ams/logo.tokens.json +++ b/proprietary/tokens/src/components/ams/logo.tokens.json @@ -1,7 +1,7 @@ { "ams": { "logo": { - "height": { "value": "2.5rem" }, + "block-size": { "value": "2.5rem" }, "emblem": { "color": { "value": "{ams.color.primary-red}" } }, "title": { "color": { "value": "{ams.color.primary-red}" } }, "subsite": { "color": { "value": "{ams.color.primary-black}" } } diff --git a/proprietary/tokens/src/components/ams/screen.tokens.json b/proprietary/tokens/src/components/ams/screen.tokens.json index 75987af9a3..122f5a114c 100644 --- a/proprietary/tokens/src/components/ams/screen.tokens.json +++ b/proprietary/tokens/src/components/ams/screen.tokens.json @@ -3,10 +3,10 @@ "screen": { "background-color": { "value": "{ams.color.primary-white}" }, "wide": { - "max-width": { "value": "100rem" } + "max-inline-size": { "value": "100rem" } }, "x-wide": { - "max-width": { "value": "132rem" } + "max-inline-size": { "value": "132rem" } } } } diff --git a/proprietary/tokens/src/components/ams/switch.tokens.json b/proprietary/tokens/src/components/ams/switch.tokens.json index 2813abc8f7..98bd5b9aca 100644 --- a/proprietary/tokens/src/components/ams/switch.tokens.json +++ b/proprietary/tokens/src/components/ams/switch.tokens.json @@ -4,11 +4,11 @@ "background-color": { "value": "{ams.color.neutral-grey3}" }, "font-family": { "value": "{ams.text.font-family}" }, "outline-offset": { "value": "{ams.focus.outline-offset}" }, - "width": { "value": "3.5rem" }, + "inline-size": { "value": "3.5rem" }, "thumb": { "background-color": { "value": "{ams.color.primary-white}" }, - "width": { "value": "1.75rem" }, - "height": { "value": "1.75rem" }, + "inline-size": { "value": "1.75rem" }, + "block-size": { "value": "1.75rem" }, "hover": { "box-shadow": { "value": "0 0 0 0.125rem {ams.switch.thumb.hover.color}" }, "color": { "value": "{ams.color.dark-blue}" } diff --git a/proprietary/tokens/src/components/ams/table.tokens.json b/proprietary/tokens/src/components/ams/table.tokens.json index fede742d34..535723394b 100644 --- a/proprietary/tokens/src/components/ams/table.tokens.json +++ b/proprietary/tokens/src/components/ams/table.tokens.json @@ -10,7 +10,7 @@ "font-weight": { "value": "{ams.text.font-weight.bold}" } }, "cell": { - "border-bottom": { "value": "{ams.border.width.sm} solid {ams.color.neutral-grey1}" }, + "border-block-end": { "value": "{ams.border.width.sm} solid {ams.color.neutral-grey1}" }, "padding-block": { "value": "{ams.space.inside.md}" }, "padding-inline": { "value": "{ams.space.inside.md}" } }, diff --git a/proprietary/tokens/src/components/ams/tabs.tokens.json b/proprietary/tokens/src/components/ams/tabs.tokens.json index 403e9630ae..83adfb5694 100644 --- a/proprietary/tokens/src/components/ams/tabs.tokens.json +++ b/proprietary/tokens/src/components/ams/tabs.tokens.json @@ -3,7 +3,7 @@ "tabs": { "list": { "background-color": { "value": "{ams.color.primary-white}" }, - "border-bottom": { "value": "{ams.border.width.md} solid {ams.color.primary-blue}" } + "border-block-end": { "value": "{ams.border.width.md} solid {ams.color.primary-blue}" } }, "button": { "color": { "value": "{ams.color.primary-blue}" },