From 17762f46eb35f070e45ba0fd2ea8bfb8b5b0b987 Mon Sep 17 00:00:00 2001 From: Stephanie Hobson Date: Wed, 9 Sep 2026 14:14:25 -0700 Subject: [PATCH 1/2] Remove dead browser-support CSS for the new matrix (#1084) Everything here is unconditionally true for Firefox ESR, Safari 15.6+, and evergreen browsers, so the feature-query gates and legacy prefixes around it are dead weight. - Unwrapped @supports (position: sticky) in _navigation.scss and @supports (display: flex) in _menu.scss. The menu.scss case merges align-items/display: flex directly into the existing .mzp-c-menu-title rule, replacing its display: block fallback outright rather than keeping a separate feature-query block for a feature every supported browser has. - Removed the base/elements/_reset.scss block resetting article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, and summary to display: block -- every one of these has had correct default display in every supported browser for over a decade. Left the audio/video/canvas -> inline-block reset alone: that's a deliberate style choice (those are inline-level by spec in every browser), not a legacy-browser shim, so it doesn't belong to this cleanup. - Removed the &::-ms-expand selector in the Select form reset (pure legacy IE/Edge, matches nothing in any supported browser). - Replaced -webkit-appearance with the standard unprefixed appearance property in the two remaining form resets (search decoration, file upload button) and removed their now-unnecessary stylelint-disable comments. Re-enabled property-no-vendor-prefix and value-no-vendor-prefix in .stylelintrc.json as the ongoing enforcement lever -- confirmed empirically these two were the only real hits; the rules don't flag vendor-prefixed pseudo-elements (::-moz-focus-inner, ::-webkit-details-marker) or non-standard, prefix-only properties (-moz-osx-font-smoothing, -webkit-font-smoothing) that have no unprefixed equivalent, so the other 6 remaining prefixes in the codebase are correctly left alone. - appearance: button was flagged separately as a deprecated keyword for the unprefixed property (declaration-property-value-keyword-no-deprecated); changed to appearance: auto, which is the correct modern equivalent (native appearance for that pseudo-element is already button-shaped). - Removed stale "in IE"/"in Edge and IE" references from three comment blocks in _forms.scss. Left the normalize.css resets those comments document in place -- e.g. the textarea scrollbar and legend box-sizing resets -- since I can't confirm from source alone that every supported browser makes them fully redundant, and that's a bigger, separate call from removing definitively dead code like the @supports/-ms-/reset.scss cases above. Stacked on #1135 (v23/support-config). Part of #1084. Verified: npm run lint, npm test (47 specs, Firefox + Chrome), and a direct sass --verbose compile confirming the merged menu-title rule, the unwrapped sticky-nav rule, and the removed -ms-/@supports code in the compiled CSS. --- .stylelintrc.json | 2 - CHANGELOG.md | 3 ++ .../sass/protocol/base/elements/_forms.scss | 20 ++++------ .../sass/protocol/base/elements/_reset.scss | 18 +-------- assets/sass/protocol/components/_menu.scss | 10 +---- .../sass/protocol/components/_navigation.scss | 38 +++++++++---------- 6 files changed, 32 insertions(+), 59 deletions(-) diff --git a/.stylelintrc.json b/.stylelintrc.json index 438f12c7..06dfb736 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -5,8 +5,6 @@ "declaration-no-important": true, "color-function-notation": "legacy", "alpha-value-notation": "number", - "property-no-vendor-prefix": null, - "value-no-vendor-prefix": null, "at-rule-empty-line-before": null, "no-descending-specificity": null, "value-keyword-case": [ diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c04173d..29fbddb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ Introducing theme variables! CSS variables beginning with `--theme-` will adjust * (breaking) Updated the supported browser matrix to Firefox ESR, Safari 15.6+, and evergreen browsers (`browserslist` in `package.json`). * (breaking) Removed the Babel `targets: { ie: '10' }` override in every webpack config (docs site, npm package, and test bundle). The compiled JS now targets the `browserslist` matrix above instead of IE10. * (breaking) Remove support for vendor prefixing (#957) +* Removed dead CSS for browsers outside the new matrix: unwrapped the two remaining `@supports` feature-query blocks (`position: sticky` in Navigation, `display: flex` in Menu), removed the `&::-ms-expand` selector in form Select styles, and removed the HTML5-elements-to-`display: block` reset in `_reset.scss` (every element it covered has had correct default display in every supported browser for years) +* Replaced `-webkit-appearance` with the standard unprefixed `appearance` property in two form resets, and re-enabled the `property-no-vendor-prefix`/`value-no-vendor-prefix` stylelint rules +* Removed stale "in IE"/"in Edge and IE" references from comments in `_forms.scss` (the resets they document are left in place) ### Typography diff --git a/assets/sass/protocol/base/elements/_forms.scss b/assets/sass/protocol/base/elements/_forms.scss index b00601d8..9c63ad4b 100644 --- a/assets/sass/protocol/base/elements/_forms.scss +++ b/assets/sass/protocol/base/elements/_forms.scss @@ -18,8 +18,8 @@ legend { padding: 0; } -// 1. Correct the text wrapping in Edge and IE. -// 2. Correct the color inheritance from `fieldset` elements in IE. +// 1. Correct the text wrapping. +// 2. Correct the color inheritance from `fieldset` elements. // 3. Remove the padding so developers are not caught out when they zero out // `fieldset` elements in all browsers. legend { @@ -60,7 +60,7 @@ button, appearance: auto; } -// Remove the default vertical scrollbar in IE 10+. +// Remove the default vertical scrollbar. textarea { overflow: auto; height: auto; @@ -74,21 +74,19 @@ textarea { } // Remove the inner padding in Chrome and Safari on macOS. -/* stylelint-disable-line value-no-vendor-prefix */ [type='search']::-webkit-search-decoration { - -webkit-appearance: none; + appearance: none; } // 1. Correct the inability to style clickable types in iOS and Safari. // 2. Change font properties to `inherit` in Safari. -/* stylelint-disable-next-line value-no-vendor-prefix */ ::-webkit-file-upload-button { - -webkit-appearance: button; // 1 + appearance: auto; // 1 font: inherit; // 2 } -// 1. Add the correct box sizing in IE 10. -// 2. Remove the padding in IE 10. +// 1. Add the correct box sizing. +// 2. Remove the padding. [type='checkbox'], [type='radio'] { box-sizing: border-box; // 1 @@ -325,10 +323,6 @@ select { } } - &::-ms-expand { - display: none; - } - &:hover { border-color: var(--theme-field-border-color-hover); background-image: $url-image-caret-down-link-hover, forms.$select-bg; diff --git a/assets/sass/protocol/base/elements/_reset.scss b/assets/sass/protocol/base/elements/_reset.scss index 9d88c1db..008085bb 100644 --- a/assets/sass/protocol/base/elements/_reset.scss +++ b/assets/sass/protocol/base/elements/_reset.scss @@ -2,22 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -// Set new HTML5 elements to block or inline-block for older browsers -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -main, -nav, -section, -summary { - display: block; -} - +// audio, video, and canvas are inline-level by spec in every supported +// browser; set them to inline-block instead. audio, video, canvas { diff --git a/assets/sass/protocol/components/_menu.scss b/assets/sass/protocol/components/_menu.scss index a06a428f..d198ea78 100644 --- a/assets/sass/protocol/components/_menu.scss +++ b/assets/sass/protocol/components/_menu.scss @@ -46,9 +46,10 @@ .mzp-c-menu-category { .mzp-c-menu-title { + align-items: center; border-bottom: 1px solid $color-marketing-gray-30; color: var(--theme-body-text-color); - display: block; + display: flex; font-weight: bold; margin-bottom: 0; min-height: 40px; @@ -87,13 +88,6 @@ } } - @supports (display: flex) { - .mzp-c-menu-title { - align-items: center; - display: flex; - } - } - @media #{$mq-md} { @include bidi(((float, left, right),)); display: inline-block; diff --git a/assets/sass/protocol/components/_navigation.scss b/assets/sass/protocol/components/_navigation.scss index 7fa695b6..5ae65eb0 100644 --- a/assets/sass/protocol/components/_navigation.scss +++ b/assets/sass/protocol/components/_navigation.scss @@ -41,30 +41,28 @@ // * -------------------------------------------------------------------------- */ // Sticky navigation styles -@supports (position: sticky) { - html.mzp-has-sticky-navigation { - .mzp-c-navigation.mzp-is-sticky { - transition: transform 300ms ease-in-out; - left: 0; - position: sticky; - top: 0; - z-index: 1000; - - &.mzp-is-scrolling { - // Shadow colors are equivalent to $color-ink-90, $color-blue-90, $color-ink-90 - box-shadow: 0 0 6px 1px rgb(29, 17, 51, 0.04), 0 0 8px 2px rgb(9, 32, 77, 0.12), 0 0 5px -3px rgb(29, 17, 51, 0.12); - } - - &.mzp-is-hidden { - transform: translate(0, -110%); - } +html.mzp-has-sticky-navigation { + .mzp-c-navigation.mzp-is-sticky { + transition: transform 300ms ease-in-out; + left: 0; + position: sticky; + top: 0; + z-index: 1000; + + &.mzp-is-scrolling { + // Shadow colors are equivalent to $color-ink-90, $color-blue-90, $color-ink-90 + box-shadow: 0 0 6px 1px rgb(29, 17, 51, 0.04), 0 0 8px 2px rgb(9, 32, 77, 0.12), 0 0 5px -3px rgb(29, 17, 51, 0.12); } - // add scroll-offset for anchor links. - .mzp-is-anchor-link { - scroll-margin-top: 120px; /* stylelint-disable-line property-no-unknown */ + &.mzp-is-hidden { + transform: translate(0, -110%); } } + + // add scroll-offset for anchor links. + .mzp-is-anchor-link { + scroll-margin-top: 120px; /* stylelint-disable-line property-no-unknown */ + } } // * -------------------------------------------------------------------------- */ From 8da390f318a17d5448060d92475a31ff0c8d09bd Mon Sep 17 00:00:00 2001 From: Stephanie Hobson Date: Wed, 9 Sep 2026 15:43:57 -0700 Subject: [PATCH 2/2] Remove dead browser-support JS, fix a matchMedia support-detect bug (#1084) - Removed the Element.matches() IE8 polyfill from utils.js entirely. Native Element.prototype.matches is supported in every browser in the new matrix; nextUntil() already calls el.matches() directly so nothing downstream changes. - Collapsed the addEventListener-else-addListener MediaQueryList fallback in navigation.js, menu.js, and footer.js down to a plain addEventListener call. The standard MediaQueryList.addEventListener has been supported since Safari 14 / Firefox 55 / Chrome 55 -- fully covered by the new matrix -- so the legacy addListener branch never runs in any supported browser. - Bug fix: MzpSupports.matchMedia required window.matchMedia('all').addListener -- the *deprecated* legacy MediaQueryList API -- to consider matchMedia supported. Any browser that removes the deprecated addListener while keeping standard matchMedia (as browsers increasingly do) would make this detect return false, silently disabling sticky navigation and everything else gated on window.MzpSupports.matchMedia (menu.js, footer.js). Fixed to check only for matchMedia itself. - Simplified two IE9 classList-polyfill workarounds in menu.js (removing classes one-at-a-time "in the correct order" per https://github.com/mozilla/bedrock/issues/6221) to a single classList.remove('a', 'b') call -- multi-argument remove() is reliable in every supported browser now that the IE9 bug it worked around is out of scope. Left MzpSupports' public API (matchMedia, requestAnimationFrame, cssFeatureQueries, classList, details, intersectionObserver) and its consumers' gate checks in place per the v23 plan -- it's a documented UMD entry point (webpack.entrypoints.js) referenced in components/details-component/readme.md, so removing it outright is a separate, bigger breaking-API decision than this cleanup. All six detects are now unconditionally true for the supported matrix, which is effectively dead code, but keeping the module intact avoids a second breaking change bundled into this one. Didn't add a spec for the matchMedia fix -- supports.js computes each property once at module-import time via an IIFE, which doesn't fit this test harness's plain Jasmine-in-real-browser setup without module-mocking machinery this repo doesn't have. The existing menu.js/navigation.js/footer.js specs already exercise the changed addEventListener lines in real Firefox and Chrome (not jsdom), which is the practical coverage available here. Stacked on v23/support-css (browser-support CSS cleanup). Part of #1084. Verified: npm run lint, npm test (47 specs, Firefox + Chrome), and npm run build-package all pass. --- CHANGELOG.md | 2 ++ assets/js/protocol/footer.js | 6 +----- assets/js/protocol/menu.js | 18 +++--------------- assets/js/protocol/navigation.js | 6 +----- assets/js/protocol/supports.js | 2 +- assets/js/protocol/utils.js | 20 -------------------- 6 files changed, 8 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29fbddb5..7d02c655 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ Introducing theme variables! CSS variables beginning with `--theme-` will adjust * Removed dead CSS for browsers outside the new matrix: unwrapped the two remaining `@supports` feature-query blocks (`position: sticky` in Navigation, `display: flex` in Menu), removed the `&::-ms-expand` selector in form Select styles, and removed the HTML5-elements-to-`display: block` reset in `_reset.scss` (every element it covered has had correct default display in every supported browser for years) * Replaced `-webkit-appearance` with the standard unprefixed `appearance` property in two form resets, and re-enabled the `property-no-vendor-prefix`/`value-no-vendor-prefix` stylelint rules * Removed stale "in IE"/"in Edge and IE" references from comments in `_forms.scss` (the resets they document are left in place) +* Removed the IE8 `Element.matches()` polyfill from `utils.js`, and the `addListener`-else-`addEventListener` `MediaQueryList` fallbacks in `navigation.js`, `menu.js`, and `footer.js` +* Fixed a bug in `MzpSupports.matchMedia`: it required `window.matchMedia('all').addListener`, the deprecated legacy `MediaQueryList` API, so it would incorrectly report `matchMedia` as unsupported (silently disabling sticky navigation and other features gated on it) in any browser that removes the deprecated method while keeping standard `matchMedia` ### Typography diff --git a/assets/js/protocol/footer.js b/assets/js/protocol/footer.js index 45746fd8..d52afaac 100644 --- a/assets/js/protocol/footer.js +++ b/assets/js/protocol/footer.js @@ -28,11 +28,7 @@ MzpFooter.init = () => { window.MzpDetails.init(footerHeadings); } - if (window.matchMedia('all').addEventListener) { - _mqWide.addEventListener('change', screenChange, false); - } else if (window.matchMedia('all').addListener) { - _mqWide.addListener(screenChange); - } + _mqWide.addEventListener('change', screenChange, false); } } diff --git a/assets/js/protocol/menu.js b/assets/js/protocol/menu.js index 2c066d71..87fde65d 100644 --- a/assets/js/protocol/menu.js +++ b/assets/js/protocol/menu.js @@ -44,11 +44,7 @@ MzpMenu.close = () => { const current = document.querySelectorAll('.mzp-c-menu-category.mzp-is-selected'); for (let i = 0; i < current.length; i++) { - // The following classes must be removed in the correct order - // to work around a bug in bedrock's classList polyfill for IE9. - // https://github.com/mozilla/bedrock/issues/6221 :/ - current[i].classList.remove('mzp-is-selected'); - current[i].classList.remove('mzp-is-animated'); + current[i].classList.remove('mzp-is-selected', 'mzp-is-animated'); current[i].querySelector('.mzp-c-menu-title').setAttribute('aria-expanded', false); } @@ -92,11 +88,7 @@ MzpMenu.toggle = (el) => { if (!state) { MzpMenu.open(el); } else { - // The following classes must be removed in the correct order - // to work around a bug in bedrock's classList polyfill for IE9. - // https://github.com/mozilla/bedrock/issues/6221 :/ - el.classList.remove('mzp-is-selected'); - el.classList.remove('mzp-is-animated'); + el.classList.remove('mzp-is-selected', 'mzp-is-animated'); el.querySelector('.mzp-c-menu-title').setAttribute('aria-expanded', false); if (typeof _options.onMenuClose === 'function') { @@ -205,11 +197,7 @@ MzpMenu.handleState = () => { } } - if (window.matchMedia('all').addEventListener) { - _mqWideNav.addEventListener('change', menuBind, false); - } else if (window.matchMedia('all').addListener) { - _mqWideNav.addListener(menuBind); - } + _mqWideNav.addEventListener('change', menuBind, false); if (MzpMenu.isWideViewport()) { MzpMenu.bindEventsWide(); diff --git a/assets/js/protocol/navigation.js b/assets/js/protocol/navigation.js index 70f73491..9f76b847 100644 --- a/assets/js/protocol/navigation.js +++ b/assets/js/protocol/navigation.js @@ -104,11 +104,7 @@ MzpNavigation.initSticky = () => { } } - if (window.matchMedia('all').addEventListener) { - _mqLargeNav.addEventListener('change', makeStickyNav, false); - } else if (window.matchMedia('all').addListener) { - _mqLargeNav.addListener(makeStickyNav); - } + _mqLargeNav.addEventListener('change', makeStickyNav, false); if (MzpNavigation.isLargeViewport()) { MzpNavigation.createSticky(); diff --git a/assets/js/protocol/supports.js b/assets/js/protocol/supports.js index 171995cf..db41c252 100644 --- a/assets/js/protocol/supports.js +++ b/assets/js/protocol/supports.js @@ -9,7 +9,7 @@ const MzpSupports = {}; * @return {Boolean} boolean value for if the browser supports matchMedia */ MzpSupports.matchMedia = (function() { - return typeof window.matchMedia !== 'undefined' && window.matchMedia('all').addListener; + return typeof window.matchMedia !== 'undefined'; }()); /** diff --git a/assets/js/protocol/utils.js b/assets/js/protocol/utils.js index 4dc9cf68..996724fa 100644 --- a/assets/js/protocol/utils.js +++ b/assets/js/protocol/utils.js @@ -4,26 +4,6 @@ const MzpUtils = {}; -/** - * Element.matches() polyfill (IE8 support) - * https://developer.mozilla.org/en-US/docs/Web/API/Element/matches - * - https://vanillajstoolkit.com/polyfills/matches-ie8/ - */ -if (!Element.prototype.matches) { - Element.prototype.matches = - Element.prototype.matchesSelector || - Element.prototype.mozMatchesSelector || - Element.prototype.msMatchesSelector || - Element.prototype.oMatchesSelector || - Element.prototype.webkitMatchesSelector || - function (s) { - const matches = (this.document || this.ownerDocument).querySelectorAll(s); - let i = matches.length; - while (--i >= 0 && matches.item(i) !== this) { } // eslint-disable-line no-empty - return i > -1; - }; -} - /** * nextUntil * @param {Object} el - Element that you want to get the siblings of