Подтвердить что ты не робот

Как выбрать элемент на основе состояния другого элемента на странице с помощью CSS?

У меня есть элементы, которые могут отражать разные состояния, вызванные пользователем (:hover, :focus и т.д.) или управляемые сервером (data-status="finished", disabled и т.д.).

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

Пример:

<section>
    <div>Element 1</div>
    <div data-status="finished">Element 2</div>
    <div>Element 3</div>
</section>
<section>
    <div>Element 4</div>
    <div class="blink">Element 5</div>
    <div>Element 4</div>
    <div>Element 4</div>
    <div class="spin">Element 4</div>
    ...
</section>

или просто визуализировать элементы с соответствующими стилями на стороне сервера.

Есть ли селектор CSS, который позволит мне указать, какие элементы должны быть выбраны на основе состояния целевого элемента?

Что-то вроде:

div[data-status~=finished]:affect(.blink, .spin)

что позволило бы мне также целевым элементам, которые не имеют одного и того же родительского только с CSS?

4b9b3361

Ответ 1

Общий ответ на канонический вопрос

Как выбрать элемент на основе состояния другого элемента на странице с помощью CSS?

состоит в том, что он зависит только от трех условий:

  • можно ли представить состояние этих элементов с помощью простых селекторов,
  • может быть выражено структурное соотношение между этими двумя элементами с использованием комбинаторов для формирования единого комплексного селектора и
  • может ли элемент, который вы хотите настроить, стать объектом сложного селектора.

В то время как текущий селекторный стандарт имеет некоторые интересные, а иногда и потенциально мощные функции, то, как он разработан, делает его крайне ограниченным в области №2 (при этом # 3 является прямым следствием). Некоторые из этих ограниченных возможностей перечислены в других ответах, например. через самое основное использование комбинаторов для детей и братьев, умное использование динамических псевдоклассов (что фактически относится к условию № 1) или комбинация обоих.

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

  • Да, состояние этих элементов может быть представлено с помощью простых селекторов: div и [data-status~=finished] для первого и .blink и .spin для последних двух.

  • Первый элемент может быть представлен section > div[data-status~=finished], и два субъекта могут быть представлены section + section > .blink и section + section > .spin соответственно. Проблема в том, что невозможно написать сложный селектор, включающий все эти структуры, потому что комбинаторы однонаправлены, и нет родительского аналога дочернего комбинатора, чтобы объединить их в первом элементе section.

  • Предполагая, что ответ на первые два вопроса также "да", каждый из .blink и .spin может стать предметом своего сложного селектора. (Но больше об этом в следующем разделе.)

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

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

Состояние элементов и структурные отношения между элементами

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

Селектор представляет собой структуру. Эта структура может использоваться как условие (например, в правиле CSS), которое определяет, какие элементы селектор соответствует в дереве документов, или как плоское описание HTML или XML-фрагмента, соответствующего этой структуре.

Селекторы могут варьироваться от простых имен элементов до богатых контекстуальных представлений.

Каждый элемент представлен последовательностью одного или нескольких простых селекторов. Эта последовательность известна как составной селектор (я использую терминологию от Selectors 4 здесь, поскольку она намного яснее, чем то, что используется в Selectors 3 - см. этот ответ для неисчерпывающий список терминов).

Каждый простой селектор представляет определенное состояние элемента. Существуют простые селекторы для сопоставления типа (или имени тега) элемента, имени класса, идентификатора или произвольного атрибута. Существуют также псевдоклассы, которые представляют абстракции и другие особые состояния, не представленные непосредственно в дереве документов, такие как порядок и положение элемента в его иерархии (:nth-child(), :nth-of-type()), пользовательские взаимодействия (:hover, :active, :focus, :checked), посещаемость гиперссылки (:link, :visited) и многое другое.

В данном примере элемент div с атрибутом data-status, чье значение с разделителем по пространству содержит finished, может быть представлено селектором типов и селектором атрибутов:

div[data-status~=finished]

Если вы хотите, чтобы селектор применялся только тогда, когда указатель над этим элементом, просто введите псевдокласс :hover:

div[data-status~=finished]:hover

Сложные селекторы связаны с помощью комбинаторов для формирования сложных селекторов. Эти комбинаторы, символы >, + и ~, которые вы можете знать, выражают связь между элементами, представленными каждым составным селектором. С помощью этих двух инструментов вы уже можете создать очень интересные результаты, как показано в других ответах здесь. Я объясню эти основы еще глубже в этом ответе.

В данном примере могут быть установлены следующие структурные зависимости:

  • Первый элемент section является родительским элементом div[data-status~=finished]. Это представлено с помощью детского комбинатора >:

    section > div[data-status~=finished]
    
  • Второй section сразу же следует за первым своим родным братом. Это представлено с помощью смежного сиблингового комбинатора +:

    section + section
    
  • Кроме того, второй section является родителем как .blink, так и .spin. Это может быть представлено с использованием двух селекторов, по одному для каждого дочернего элемента:

    section + section > .blink, 
    section + section > .spin
    

    Почему нужны два селектора? В этом случае это главным образом потому, что в настоящее время нет синтаксиса для подгруппы двух составных селекторов в один, поэтому вам придется представлять каждый дочерний элемент отдельно. Предстоящий стандарт Selectors 4 представляет собой псевдокласс класса :matches(), который обеспечит эту самую подгруппу:

    section + section > :matches(.blink, .spin)
    

Теперь, поскольку каждый составной селектор в сложном селекторе представляет один элемент и, следовательно, section + section представляет два элемента, которые являются братьями и сестрами, section > div представляет родительский и дочерний элементы, а section + section > div представляет дочерний элемент следующего типа, братец, вы могли бы подумать, что родительский комбинатор и комбинатор предыдущего соседа довольно избыточны. Итак, почему мы обычно получаем следующие вопросы:

И, что более важно, почему ответ на оба этих вопроса нет? Причина рассматривается в следующем пункте:

Объект селектора

subject селектора всегда представлен самым правым составным селектором. Например, селектор section + section > div представляет три элемента, из которых div является объектом. Вы можете сказать, что div выбран или целенаправлен, как в вопросе, но если вы когда-либо задавались вопросом, существует ли подходящий термин, он известен как предмет селектора.

В правиле CSS стили применяются к элементу, представленному субъектом селектора. Любые дочерние блоки и псевдоэлементные ящики наследуют стили из этого элемента, где это необходимо. (Исключением является то, что объект селектора включает псевдоэлемент, и в этом случае стили применяются непосредственно к псевдоэлементу.)

Взяв селектора из предыдущего раздела, мы имеем следующее:

  • Объектом section > div[data-status~=finished] является div[data-status~=finished].
  • Объектом section + section является второй селектор section.
  • Субъекты section + section > .blink, section + section > .spin равны .blink и .spin соответственно.
  • Используя :matches(), объектом section + section > :matches(.blink, .spin) является :matches(.blink, .spin).

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

Это приводит нас к следующему из первоначального вопроса:

Есть ли селектор CSS, который позволит мне указать, какие элементы должны быть выбраны на основе состояния целевого элемента?

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

Потенциальное решение

Тем не менее, объектный индикатор был недавно удален в пользу псевдокласса :has() (который, в свою очередь, принятый из jQuery), Я размышляю по вероятной причине здесь:

Причина :has() более универсальна в том, что с селектором субъекта в любом проекте никогда не было ясно, если в одном сложном селекторе может быть более одного селектора объектов (так как у одного сложного селектора может быть только один субъект) и/или если функциональные псевдоклассы, такие как :matches(), приняли селектор объектов. Но поскольку псевдокласс является простым селектором, вы знаете, что :has() может быть принят везде, где будет принят псевдокласс.

Итак, пока вы не можете изменить тему селектора, :has() полностью списает необходимость сделать это из-за его псевдоклассовой природы. И самое главное, что он делает это, а затем и некоторые - все без принципиально изменяющегося синтаксиса селектора.

На самом деле проблема примера может быть решена с помощью Selectors 4 :has():

/* Combined with the :matches() example from above */
section:has(> div[data-status~=finished]) + section > div:matches(.blink, .spin)

Обратите внимание на использование детского комбинатора: это позволяет относительный аргумент селектора только детям первого section. Да, это неуловимый "родительский селектор", который веб-разработчики во всем мире желали в течение многих лет.

И поскольку :has() поступает из jQuery, вы можете использовать его сегодня, хотя :matches() еще не существует, поэтому вам придется заменить его вызовом .filter() тем временем:

$('section:has(> div[data-status~=finished]) + section > div')
    .filter('.blink, .spin')
    .css('color', 'red');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section>
    <div>Element 1</div>
    <div data-status="finished">Element 2</div>
    <div>Element 3</div>
</section>
<section>
    <div>Element 4</div>
    <div class="blink">Element 5</div>
    <div>Element 4</div>
    <div>Element 4</div>
    <div class="spin">Element 4</div>
    ...
</section>

Ответ 2

Вы очень ограничены тем, что вы можете достичь с текущим состоянием CSS.

Вкратце - вы можете заставить элементы CSS реагировать на изменение состояния элемента, если они имеют один и тот же родительский элемент И являются родными братьями или родительскими дочерними элементами.


Состояние элемента в CSS обрабатывается pseudo-classes, которое охватывает большинство типичных взаимодействий, которые браузер обрабатывает на основе пользователя вход.

Хотя это позволяет обрабатывать визуальный внешний вид текущего состояния элемента и его дочерних элементов в дереве DOM, вы по-прежнему не можете реагировать на другие не-дочерние элементы (с визуальным изменением стиля) на текущий состояние вашего элемента, поскольку CSS не предлагает определенный тип селектора, чтобы сделать это гибким способом.

Вы можете, однако, объединить псевдоклассы с другими типами селекторов CSS и сделать эту работу в определенных ситуациях (я буду использовать состояние зависания, поскольку это наиболее очевидно):

псевдокласс + соседний селектор для сиблинга

Смежный селектор совпадений соответствует, если element1 и element2 совместно использовать один и тот же родительский элемент в дереве документов, а element1 сразу предшествует element2. (Спецификация W3C для смежных селекторов)

div:hover + div {
    background:red;
}
Hover on elements:
<div>Element 1</div>
<div>Element 2</div>
<div>Element 3</div>
<div>Element 4</div>
<div>Element 5</div>

Ответ 3

Поскольку @easwee уже опубликовал хороший ответ, я бы не стал повторять какие-либо псевдосекторные селектора, обсуждаемые им,


Новый псевдокласс, который мы имеем сейчас, в css3: : target.

Псевдополе :target в CSS соответствует, когда хэш в URL и идентификатор элемента совпадают.

(Конкретное использование: target - это элемент стиля, который является целевым и точечно видимым поверх окна просмотра)

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

Например: целевой дочерний элемент родительского родителя.

:target section div[data-status=finished] {
  color: red;
}
a,
a:visited {
  text-decoration: none;
  color: #000;
}
section {
  border: 1px solid grey;
}
<nav id='nav'>
  <h4>This is Navigation section</h4>
  <section>
    sibling
    <div><a href='#nav'>(child)click me to target child  of sibling of parent</a>
    </div>
  </section>
  <section>
    sibling
    <div data-status="finished">(child)I am child of parent of sibling</div>
  </section>

</nav>