The following CSS rules are used in a theme that multiple sites share. Some sites have menu items while others don't. These are styles applied to an element with the header
class before it is eventually mounted by a JS web component, after which it will have multiple child elements and thus will be unaffected by the styles. Sites that do not have a menu attach the no-menu
class as well.
Just vanilla CSS without preprocessors.
I have the following CSS rule:
:is(.header:empty,.header:has(div:only-child)) {
--header-min-height: 114px;
--header-title-height: 63px;
&.no-menu {
--header-min-height: 101px;
--header-title-height: 50px;
}
}
/* If on a smaller screen, a hamburger nav appears, so
apply the "no-menu" styles to both versions. */
@media (max-width: 1100px) {
:is(.header:empty,.header:has(div:only-child)) {
--header-min-height: 101px;
--header-main-gradient: 50px;
}
}
Due to specificity, the media query rule does not affect the no-menu
variant on smaller screens.
Is there a way to adjust the media-query-contained rule to address this issue exclusively by manipulating the selectors and without introducing duplicate information?
The following solutions solve the problem, but introduce duplication that I'd like to avoid.
Duplicating the selector and adding .no-menu
to the end of it:
@media (max-width: 1100px) {
:is(.header:empty,.header:has(div:only-child)),
:is(.header:empty,.header:has(div:only-child)).no-menu {
--header-min-height: 101px;
--header-main-gradient: 50px;
}
}
Add a nested CSS rule of &.no-menu { ... }
(duplicates the declarations):
@media (max-width: 1100px) {
:is(.header:empty,.header:has(div:only-child)) {
--header-min-height: 101px;
--header-main-gradient: 50px;
&.no-menu {
--header-min-height: 101px;
--header-main-gradient: 50px;
}
}
}
Happened upon this solution while experimenting and was surprised it works.
I thought to myself that, in the ideal case, you'd be able to leverage CSS nesting, but have the nested rule apply to both the current scope as well as the context with the class. Turns out, you can use :scope
with :is()
to achieve this:
@media (max-width: 1100px) {
:is(.header:empty,.header:has(div:only-child)) {
&:is(:scope,.no-menu) {
--header-min-height: 101px;
--header-main-gradient: 50px;
}
}
}