У меня есть контейнеры с цветным фоном, которые попадают в одну из трех разных категорий, представленных sass-заполнителями %dark-box
, %light-box
и %gradient-box
. Мне нужно настроить стиль элементов, которые являются потомками этих блоков. Эти элементы могут быть вложены на любую произвольную глубину внутри блока.
Проблема в том, что ящики могут быть вложены друг в друга, причем на любую произвольную глубину, и нет ограничений на количество уровней вложенности. Блоки, внутренние блоки, внутренние блоки и т. д. Таким образом, селекторы, нацеленные на элементы внутри блоков, должны нацеливаться на элементы только в том случае, если этот блок является ближайшим ?-box
предком.
Рассмотрим этот HTML:
<div class = "dark-box"> <!-- backgrund-color:$dark-box-bg-color -->
<div>
<div>
<div>
<p>This should have color:$dark-box-text-color</p>
</div>
</div>
</div>
<div>
<div class = "light-box"> <!-- backgrund-color:$light-box-bg-color -->
<div>
<div>
<div>
<p>This should have color:$light-box-text-color</p>
</div>
<div>
<p>This should have color:$light-box-text-color</p>
</div>
<div>
<div class = "dark-box"> <!-- backgrund-color:$dark-box-bg-color -->
<div>
<div class = "light-box"> <!-- backgrund-color:$light-box-bg-color -->
<div>
<div class = "dark-box"> <!-- backgrund-color:$dark-box-bg-color -->
<div>
<div>
<p>This should have color:$dark-box-text-color</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
С помощью этого scss:
%dark-box {
background-color: $dark-box-bg-color;
// other stuff ...
}
%light-box {
background-color: $light-box-bg-color;
// other stuff ...
}
%gradient-box {
background-color: $gradient-box-bg-color;
// other stuff ...
}
.dark-box {@extend %dark-box;}
.light-box {@extend %light-box;}
.gradient-box {@extend %gradient-box;}
%dark-box-text {
color: $dark-box-text-color;
// other stuff ...
}
%light-box-text {
color: $light-box-text-color;
// other stuff ...
}
%gradient-box-text {
color: $gradient-box-text-color;
// other stuff ...
}
:is(%dark-box) > p,
:is(%dark-box) > /*! n descendants, none of which have a %light-box or %gradient-box class */ > p {
@extend %dark-box-text;
}
:is(%light-box) > p,
:is(%light-box) > /*! n descendants, none of which have a %dark-box or %gradient-box class */ > p {
@extend %light-box-text;
}
:is(%gradient-box) > p,
:is(%gradient-box) > /*! n descendants, none of which have a %dark-box or %light-box class */ > p {
@extend %gradient-box-text;
}
Как я могу создать селектор, нацеленный на первый и последний абзац, но ни на один из абзацев в середине? И наоборот?
Я знаю, что могу сделать что-то, что явно нацелено на каждую возможную глубину абзаца (как показано ниже), но тогда мне придется установить максимальный предел глубины. Это также будет означать неприемлемое увеличение времени предварительной обработки Sass, если учесть, что заполнители блоков могут быть расширены с помощью множества различных селекторов, а абзацы — лишь один из многих элементов, на которые мне нужно будет ориентироваться таким образом.
:is(%dark-box) > p,
:is(%dark-box) > :not(:where(%light-box), :where(%gradient-box)) > p,
:is(%dark-box) > :not(:where(%light-box), :where(%gradient-box)) > :not(:where(%light-box), :where(%gradient-box)) > p,
:is(%dark-box) > :not(:where(%light-box), :where(%gradient-box)) > :not(:where(%light-box), :where(%gradient-box)) > :not(:where(%light-box), :where(%gradient-box)) > p,
// etc...
{
@extend %dark-box-text;
}
Я попробовал несколько вариантов следующего, но пока не нашел ничего работающего.
:is(%dark-box) > p,
:is(%dark-box) :not(:where(:where(%light-box), :where(%gradient-box))) p {
@extend %dark-box-text;
}
В продолжение предыдущего комментария взгляните на документацию MDN по правилу @scope . Кроме того, если вы чувствуете, что это может помочь, на YouTube есть видео Кевина Пауэлла, в котором рассказывается об этом: youtu.be/PkFuytYVqI8?si=swzLcWUwSbAqLeSe.
К сожалению, похоже, что вы столкнулись с одной из проблем, которая в будущем будет решена с помощью @scope
at-правила.
Тем не менее, хотя селекторы не учитывают близость ближайшего предка, наследование учитывает. Таким образом, вы можете использовать пользовательские свойства CSS, чтобы решить эту проблему.
div {
padding: 4px;
}
.dark-box, .light-box {
color: var(--text-color);
background-color: var(--background-color);
}
.dark-box {
--text-color: white;
--background-color: midnightblue;
}
.light-box {
--text-color: black;
--background-color: lemonchiffon;
}
<div class = "dark-box"> <!-- backgrund-color:$dark-box-bg-color -->
<div>
<div>
<div>
<p>This should have color:$dark-box-text-color</p>
</div>
</div>
</div>
<div>
<div class = "light-box"> <!-- backgrund-color:$light-box-bg-color -->
<div>
<div>
<div>
<p>This should have color:$light-box-text-color</p>
</div>
<div>
<p>This should have color:$light-box-text-color</p>
</div>
<div>
<div class = "dark-box"> <!-- backgrund-color:$dark-box-bg-color -->
<div>
<div class = "light-box"> <!-- backgrund-color:$light-box-bg-color -->
<div>
<div class = "dark-box"> <!-- backgrund-color:$dark-box-bg-color -->
<div>
<div>
<p>This should have color:$dark-box-text-color</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Кроме того, я должен отметить, что имена классов не имеют точки .
в разметке html; это только для создания селектора CSS.
Ха! Хороший улов в точку. В следующий раз сначала кофе, потом код. ;-)
Я никогда не рассматривал возможность использования пользовательских свойств таким образом, но это просто великолепно и полностью меняет мою структуру CSS. Так что спасибо тебе!
К сожалению, похоже, что вы столкнулись с одной из проблем, которая в будущем будет решена с помощью
@scope
at-правила.