Backdrop-filter (blur) не работает для .menu-panel, хотя прозрачность фона действует

Я настраиваю долгоживущую пользовательскую тему и хотел бы придать гамбургер-меню/боковой панели (.menu-panel) тот же полупрозрачный размытый вид, который уже отлично работает для .d-header. Прозрачность работает, но размытие нет — и я хотел бы сообщить об этом как о проблеме, поскольку несколько особенностей того, как ядро стилизует этот компонент, сделали задачу сложнее, чем ожидалось.

Что я пытаюсь достичь

Полупрозрачная панель меню с backdrop-filter: blur() на заднем плане, чтобы контент страницы всё ещё просвечивал через панель, подобно эффекту матового стекла, который используют многие нативные приложения. Мне важны и эффект просвечивания, и размытие — прозрачность без размытия выглядит неопрятно поверх загруженных списков тем.

Что уже работает

Для .d-header достаточно вот этого, и оно работает надёжно (проверено в iOS Safari и настольном Chrome):

.d-header {
  background-color: color-mix(in srgb, var(--header_background) 50%, transparent);
  -webkit-backdrop-filter: blur(3px) saturate(1.2);
  backdrop-filter: blur(3px) saturate(1.2);
}

Что не работает

Тот же самый подход, применённый к .menu-panel, даёт прозрачность, но никогда не даёт размытия в iOS Safari:

.menu-panel {
  background-color: color-mix(in srgb, var(--secondary) 85%, transparent) !important;
  -webkit-backdrop-filter: blur(6px) saturate(1.2);
  backdrop-filter: blur(6px) saturate(1.2);
  border-radius: 14px;
}

Я пробовал заставить размытие появиться, но ничего не помогло:

  • Добавление !important к самим объявлениям backdrop-filter/-webkit-backdrop-filter.
  • Принудительное создание отдельного слоя композитинга с помощью transform: translateZ(0) в сочетании с overflow: hidden (общий обходной путь для Safari при других проблемах с backdrop-filter) — здесь это не дало никакого эффекта, поэтому я снова убрал его, чтобы не оставлять хак, который не оправдывает своего присутствия.
  • Убедился, что я нацеливаюсь на правильный элемент: согласно menu-panel.scss, непрозрачный фон устанавливается непосредственно на .menu-panel (а не на дочерний элемент, например .panel-body), что я изначально понял неверно, а затем исправил.

Если кто-то знает, почему .menu-panel ведёт себя иначе, чем .d-header в этом случае, или знает рабочий рецепт, я буду рад узнать об этом.

Вторая проблема: захардкоженные фоны отдельных строк меню

Даже если сделать собственный фон панели прозрачным, несколько элементов внутри неё всё ещё рендерятся непрозрачными, потому что ядро устанавливает их фон напрямую, а не через фон самой панели:

  • .user-notifications-list .read и .bookmark — прочитанные уведомления и закладки в пользовательском меню получают background-color: var(--secondary) напрямую, поэтому каждая строка отображается как непрозрачный блок, плавающий на полупрозрачной панели.
  • .hamburger-panel .sidebar-footer-wrapper .sidebar-footer-container — подвал профиля/входа внизу боковой панели имеет ту же проблему.

Я могу (и уже сделал) переопределить это в своей теме, но это означает, что нужно находить каждый захардкоженный var(--secondary) в menu-panel.scss по одному, и это снова сломается в следующий раз, когда ядро добавит новый элемент с тем же паттерном. Было бы очень полезно, если бы эти элементы использовали CSS-переменную по умолчанию, например, что-то вроде --d-menu-panel-background со значением по умолчанию var(--secondary), чтобы теме нужно было переопределить только одну переменную, чтобы сделать всю панель — включая её строки — последовательно прозрачной, вместо того чтобы гоняться за отдельными селекторами.

С удовольствием поделюсь скриншотами «до/после», если это поможет, и протестирую любое предложенное решение на своей стороне.

1 лайк

Вопрос для продолжения: та же проблема с отсутствием видимой прозрачности/размытия теперь проявляется и на другом элементе, который использует тот же путь стилей .menu-panel — поле ввода в выпадающем меню поиска в шапке (.search-input-wrapper, часть меню поиска glimmer).

Рецепт (идентичен рабочему варианту для .d-header и для .menu-panel выше):

.search-menu .search-input-wrapper {
  background: color-mix(in srgb, var(--header_background) 85%, transparent) !important;
  -webkit-backdrop-filter: blur(6px) saturate(1.2);
  backdrop-filter: blur(6px) saturate(1.2);
  border-radius: 14px;
  box-shadow: 0 0 0 1px var(--primary-low-mid);
  overflow: hidden;
}

.search-menu .search-input {
  background: transparent !important;
}

Что отображается корректно: тонкая рамка (box-shadow) и border-radius отображаются именно так, как ожидается, — значит, селектор находит нужный элемент, правило применяется и не затирается другими стилями.

Что не отображается: нет видимой полупрозрачности и нет видимого размытия того, что находится за полем, — та же симптоматика, что и у .menu-panel (боковой панели/меню-гамбургера), о которой говорилось выше. При этом .d-header, использующий буквально те же самые три строки (background-color через color-mix, -webkit-backdrop-filter, backdrop-filter), продолжает работать без проблем.

Всё больше складывается впечатление, что дело не в самом .menu-panel, а в чём-то, что объединяет эти элементы типа выпадающих меню/оверлеев (контекст наложения, создаваемый где-то в ядре, слой композитинга, который не является надлежащим содержащим блоком для backdrop-filter, или что-то подобное), — а не в наших собственных селекторах или значениях свойств, ведь одни и те же три CSS-свойства ведут себя по-разному в зависимости от того, к какому элементу ядра они привязаны.

Кто-нибудь сталкивался с тем, что backdrop-filter/полупрозрачный фон не отображается именно в выпадающем меню поиска или в других оверлеях семейства .menu-panel, хотя тот же рецепт работает в шапке?

Проблема в том, что у каждого прочитанного уведомления свой цвет фона, который также нужно переопределить. Это должно помочь в дополнение к вашим другим изменениям

.user-menu .quick-access-panel .read {
  background: transparent;
}

Аналогично с полем поиска: там применяется отдельный фон, который нужно удалить:

.search-menu .search-input, .search-menu-container .search-input {
  background: transparent;
}

У нас есть руководство, которое пошагово объясняет, как вносить подобные изменения в CSS, оно может пригодиться: Making custom CSS changes on your site

1 лайк

Большое спасибо! — оба исправления сработали ровно так, как описано.

Для тех, кто столкнулся с тем же: помимо двух переопределений, которые вы опубликовали, у меня также был вложенный элемент .results внутри .search-menu-panel, который независимо от .menu-panel рисовал собственный непрозрачный фон и которому потребовалось такое же лечение:

.search-menu-panel .results {
  background: transparent !important;
}

С этим и вашими двумя сниппетами прозрачность теперь работает чисто везде — сайдбар, панель бургера, уведомления быстрого доступа и полное выпадающее меню поиска, включая список результатов. Текст остается полностью читаемым во всех местах, так что с точки зрения прозрачности вопрос для нас полностью закрыт.

Единственный нерешенный пункт — это исходная тема этого треда: backdrop-filter/размытие само по себе. Даже при том, что все фоны теперь корректно прозрачны, ни один из этих элементов не показывает никакого размытия — тот же симптом, что и раньше, и это по-прежнему контрастирует с .d-header, где идентичный рецепт backdrop-filter рендерится нормально. Так что сторона прозрачности решена, но вопрос с размытием остается открытым.

Еще раз спасибо за то, что уделили время и разобрались в этом — это действительно помогло.

1 лайк

Хорошо, это немного сложнее… когда элемент, например шапка, получает backdrop-filter, он становится корнем для эффекта. Поэтому любой вложенный в этот корень элемент (например, выпадающие панели) может размывать только то, что находится внутри этого корня… он не может «увидеть» контент страницы за пределами шапки, даже если панели выходят за её границы, поэтому в этих областях размытия не будет.

Вместо этого вы можете использовать псевдоэлемент на шапке, чтобы обойти это ограничение корня.

.d-header {
  position: relative;
  isolation: isolate;
  background-color: transparent;

  &::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background-color: color-mix(in srgb, var(--header_background) 70%, transparent);
    backdrop-filter: blur(12px);
    pointer-events: none;
  }
}

.menu-panel {
  background-color: color-mix(in srgb, var(--secondary) 70%, transparent);
  backdrop-filter: blur(12px);
}

.user-menu .quick-access-panel .read {
  background: transparent;
}
1 лайк

(пост удалён автором)

1 лайк