Выбрать всех потомков одного класса, кроме тех, которые находятся внутри другого класса (и наоборот) - PullRequest
5 голосов
/ 08 марта 2020

Я хочу настроить таргетинг на все абзацы-потомки определенного class, игнорируя все абзацев-потомков другого class внутри первого (это должно работать независимо от того, какой класс внутри какого). Для этого мне пришлось использовать 4 селектора, например:

* {
  margin: 0.2em 0;
  width: fit-content;
}

div {
  margin-left: 1em
}

/* == 4 selectors to achieve desired effect = */

.orange p {
  background: orange;
}

.cyan .orange p {
  background: orange;
}

.cyan p {
  background: cyan;
}

.orange .cyan p {
  background: cyan;
}
<div class="orange">
        <p>Orange</p>
        <div>
          <p>Orange</p>
          <div>
            <p>Orange</p>
            <div class="cyan">
              <p>Cyan</p>
              <div>
                <p>Cyan</p>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="cyan">
        <p>Cyan</p>
        <div>
          <p>Cyan</p>
          <div>
            <p>Cyan</p>
            <div class="orange">
              <p>Orange</p>
              <div>
                <p>Orange</p>
              </div>
            </div>
          </div>
        </div>
      </div>

Вопрос: можно ли это сделать, используя только два селектора? [Порядок этих двух селекторов должен быть в состоянии изменить без изменения эффекта.]

Я пробовал такие селекторы, как:

.orange:not(.cyan) p {
  background: orange;
}

.cyan:not(.orange) p {
  background: cyan;
}

, но он не нацелен на последний, ибо это наследование стиля первого. Я ищу два селектора, которые соответствуют этим случаям без какого-либо определенного порядка в таблице стилей.

Ответы [ 2 ]

2 голосов
/ 08 марта 2020

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

* {
  margin: 0.2em 0;
  width: fit-content;
}

div {
  margin-left: 1em
}

p {
  background: var(--c);
}
.cyan {
  --c:cyan;
}
.orange {
  --c:orange;
}
<div class="orange">
  <p>Orange</p>
  <div>
    <p>Orange</p>
    <div>
      <p>Orange</p>
      <div class="cyan">
        <p>Cyan</p>
        <div>
          <p>Cyan</p>
        </div>
      </div>
    </div>
  </div>
</div>
<div class="cyan">
  <p>Cyan</p>
  <div>
    <p>Cyan</p>
    <div>
      <p>Cyan</p>
      <div class="orange">
        <p>Orange</p>
        <div>
          <p>Orange</p>
        </div>
      </div>
    </div>
  </div>
</div>

Вы можете масштабировать его до любого количества окраски, поскольку вам нужен только один селектор на цвет, и порядок не имеет значения:

* {
  margin: 0.2em 0;
  width: fit-content;
}

div {
  margin-left: 1em
}

p {
  background: var(--c);
}
.cyan {
  --c:cyan;
}
.orange {
  --c:orange;
}
.blue {
  --c:lightblue;
}
<div class="orange">
  <p>Orange</p>
  <div>
    <p>Orange</p>
    <div>
      <p>Orange</p>
      <div class="cyan">
        <p>Cyan</p>
        <div class="blue">
          <p>Blue</p>
        </div>
      </div>
    </div>
  </div>
</div>
<div class="cyan">
  <p>Cyan</p>
  <div class="blue">
    <p>Blue</p>
    <div>
      <p>Blue</p>
      <div class="orange">
        <p>Orange</p>
        <div>
          <p>Orange</p>
        </div>
      </div>
    </div>
  </div>
</div>
0 голосов
/ 08 марта 2020

Вы не можете достичь того, чего хотите, потому что это не так, как работает CSS. Оба ваших утверждения будут иметь одинаковую специфику, поэтому CSS определяет, какое правило выиграет в соответствии с порядком в файле CSS. Для внутренних стилей вам понадобится утверждение, которое имеет большую специфику. Это может быть достигнуто либо путем перечисления всех комбинаций классов, либо, например, с помощью селектора дочерних элементов (>).

Я подумал, что поделюсь улучшением вашего решения. Он по-прежнему использует 4 CSS операторов (для 2 цветов), но не требует, чтобы вы записывали все возможные комбинации (в случае более чем 2 классов, это требует меньше усилий; см. Пример ниже).

Сначала вы раскрашиваете любой дочерний элемент <p> голубого элемента в цвет cyan. Затем вы перезаписываете это поведение дочерним селектором, который нацелен только на прямые дочерние элементы вашего элемента. .orange > p затем перезаписывает .cyan p. То же самое касается оранжевого / голубого.

* { font-family: sans-serif; }

.cyan p {
  background: cyan;
}
.orange p {
  background: orange;
}
.red p {
  background: red;
}

.cyan > p {
  background: cyan;
}
.orange > p {
  background: orange;
}
.red > p {
  background: red;
}
<ul>
  <li class="orange">
    <ul>
      <li class="cyan"><p>.orange >> .cyan</p></li>
      <li class="red"><p>.orange >> red</p></li>
      <li><p>.orange >> &ndash;</p></li>
    </ul>
  </li>
  <li class="cyan">
    <ul>
      <li class="orange"><p>.cyan >> .orange</p></li>
      <li class="red"><p>.cyan >> .red</p></li>
      <li><p>.cyan >> &ndash;</p></li>
    </ul>
  </li>
  <li class="red">
    <ul>
      <li class="orange"><p>red >> orange</p></li>
      <li class="cyan"><p>red >> cyan</p></li>
      <li><p>.red >> &ndash;</p></li>
    </ul>
  </li>
</ul>
...