Селектор, чувствительный к предкам SCSS

Это похоже на то, что должно быть каким-то образом осуществимо, но я просто нигде не могу найти ответ.

Можно ли с помощью SCSS указать вариант стиля элемента на основе его принадлежности к определенному предку?

Пример:

Что я хочу в CSS:

.parent1 .element,
.parent2 .element {
    /* style for .element in both parents */
}
.parent1 .element {
    /* special style for .element only when in parent1 */
}

Что бы я хотел делать в SCSS:

.parent1,
.parent2 {
    .element {
        /* style for .element in both parents */

        [SOME SCSS MAGIC] {
            /* special style for .element only when in parent1 */        
        }
    }
}

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

Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
CSS: FlexBox
CSS: FlexBox
Ранее разработчики использовали макеты с помощью Position и Float. После появления flexbox сценарий полностью изменился.
0
0
607
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

.parent1,
.parent2 {
    .element {
        /* common styles */
    }
}

.parent1 .element {
    /* parent 1 element overrides */
}

который компилируется в:

.parent1 .element,
.parent2 .element {
  /* common styles */
}

.parent1 .element {
  /* parent 1 element overrides */
}

Редактировать

Или используйте миксин для размещения общих стилей

@mixin commonStyles {
  /* Common to both parent1 & parent 2 */
}

.parent1 {
  .element {
    @include commonStyles;
  }
}

.parent2 {
    .element {
    @include commonStyles;

    /* parent 2 specific styles */
  }
}

Что компилируется в:

.parent1 .element {
  /* Common to both parent1 & parent 2 */
}

.parent2 .element {
  /* Common to both parent1 & parent 2 */
  /* parent 2 specific styles */
}

Редактировать 2

Если вас мотивирует объединение двух наборов стилей, просто используйте два миксина.

@mixin baseStyles {
  /* Common to both parent1 & parent 2 */
}

@mixin modifiedStyles {
  /* parent 2 specific styles */
}

.parent1,
.parent2 {
  .element {
    @include baseStyles;
  }
}

.parent2 {
    .element {
      @include modifiedStyles;
  }
}

Это то, чего OP пытался избежать.

Remote 12.01.2019 17:44

Да, @MattFryer прав. Проблема в том, что родительский стиль действительно длинный, и поэтому стиль для .element будет разделен на 100 строк между ними. Это кажется неправильным.

Ian Pollak 12.01.2019 17:49

определите микс наверху со стилями, которые являются общими для обоих. Затем сделайте переопределения в .parent2 .element. См. Правки.

ksav 12.01.2019 17:58

Это не отличается от определения стилей для обоих по отдельности, @IanPollak спрашивает, есть ли способ определить стили для обоих, а затем более конкретно, в одном блоке. К сожалению, я не думаю, что это возможно, сэкономило бы много времени на прокрутку :)

Remote 12.01.2019 18:00

Другое дело, потому что рассматриваемые стили определяются только один раз.

ksav 12.01.2019 18:01

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

Remote 12.01.2019 18:01

Конечно, может. И без нахальства!

ksav 12.01.2019 18:02

Дело в том, что он хочет сохранить актуальные стили вместе.

Remote 12.01.2019 18:04

Я не буду обсуждать дальше, но это не так, потому что соответствующие стили теперь находятся в миксине (отдельно и вне блока). Проблема в ремонтопригодности, выгодно группировать стили как можно ближе друг к другу.

Remote 12.01.2019 18:09

Интересный вопрос / обсуждение :)

Remote 12.01.2019 18:09

Мне нравится миксин тем, что теперь у меня есть строка, в которой в основном говорится: «Посмотрите выше остальные стили этого элемента». Но в остальном у него такие же недостатки. Код разделен, и мне приходится повторять и поддерживать ту же структуру предков (.parentX .element), которая может быть намного сложнее в двух местах.

Ian Pollak 12.01.2019 18:10

Вы можете использовать директиву @at-root:

Обновлено: удален & и заменен на .element после того, как была указана ошибка.

.parent1,
.parent2
{
    .element 
    {
        /* styles for .element in both parents */
        @at-root .parent1 .element
        {
            /* styles for .element only when in parent1 */        
        }
    }
}

Этот второй селектор компилируется в .parent1 .parent1 .element, .parent1 .parent2 .element?

ksav 12.01.2019 17:51

Спасибо, я тоже это нашел, но повторяться кажется неправильным. Любые изменения в структуре предков придется вручную изменять везде, где используется @at-root. Но я думаю, это все же лучше, чем откладывать стиль в другое место. Надеюсь, что есть что-то получше.

Ian Pollak 12.01.2019 17:52

@ksav true, & компилируется в полный селектор, поэтому его нельзя использовать. Правильным решением здесь будет @at-root .parent1 .element, который тоже кажется далеким от идеала.

Ian Pollak 12.01.2019 17:58

Я думаю, это так близко, как вы собираетесь получить :)

Remote 12.01.2019 18:07

@MattFryer да, не очень СУХОЕ, но, пожалуй, единственное решение.

Ian Pollak 12.01.2019 18:12

@IanPollak По крайней мере, он сохраняет стили ближе друг к другу, поэтому вы добились некоторого улучшения (или, по крайней мере, еще один вариант, который следует рассмотреть). Однако использование этого метода может стать очень трудным для написания и сохранения специфичности в более крупных структурах, хотя простота сопровождения может перевесить это.

Remote 12.01.2019 18:19

используйте @ корневое тело .parent1 .element

  .parent1,
    .parent2 {
        .element {
            /* style for .element in both parents */
              background: yellow;
              color: green;
            @at-root body .parent1 .element {
              color: red;
                /* special style for .element only when in parent1 */
            }
        }
    }

Да, это уже предлагалось, и пока это кажется единственным решением. Не идеально из-за повторяющегося кода.

Ian Pollak 12.01.2019 18:15
Ответ принят как подходящий

Я бы посоветовал против этого * ... но вы можете использовать nth в списках селекторов - например:

* делает стиль менее читаемым

SCSS

.parent1,
.parent2 {
    .element {
        /* all items in selector list */

        @at-root #{nth(&, 1)} {
          /* first item in selector list */
        }
        @at-root #{nth(&, 2)} {
          /* second item in selector list */
        }
    }
}

Вывод CSS

.parent1 .element,
.parent2 .element {
  /* all items in selector list */
}

.parent1 .element {
  /* first item in selector list */
}

.parent2 .element {
  /* second item in selector list */
}

Обновлять

Чтобы сделать его более читабельным, вы можете создать вспомогательный миксин а-ля:

@mixin selector-contains($substring) {
    @each $part in & {
        @if str-index($part+'', $substring) { 
            @at-root #{$part}{ @content; } 
        }  
    }
}

.parent1,
.parent2 {
    .element {
        @include selector-contains('.parent1'){
            /* first item in selector list */
        }
        @include selector-contains('.parent2'){
            /* second item in selector list */
        }
        @include selector-contains('.parent'){
            /* all elements */
        }
    }
}

Другие вопросы по теме