Что нового в CSS селекторах 4-го уровня?

Это перевод поста "What's new in CSS selectors 4". Он показался мне интересным, и я решил перенести его на хабрахабр. P.S. Это мой первый перевод, не судите строго, и если увидите какие-то недочёты и ошибки — напишите пожалуйста в личку, я постараюсь исправить ошибки. Далее, со слов автора.

Пожалуйста, имейте ввиду, что данная статья описывает черновой вариант спецификации на январь 2015 года, что значит, что информация, изложенная в статье, без предупреждения может быть изменена.

CSS-селекторы четвёртого уровня — это следующее поколение спецификации CSS, последняя версия которой была выпущена в 2011 году, пробыв в течении нескольких лет в состоянии черновика.

Так что же нас ожидает нового?


ПРОФИЛИ СЕЛЕКТОРОВ

CSS-селекторы отныне разделены на две группы: быстрая и полная. Быстрые селекторы — это те селекторы, которые подходят для динамического CSS-движка. Полная группа селекторов подходит для использования в тех ситуациях, в которых быстрая выборка данных не настолько важна, например, при использовании их через document.querySelector.

Селекторы используются в множестве разнообразных контекстов, которые сильно отличаются по скоростным характеристикам. К сожалению, некоторые мощные селекторы слишком медленны для того, чтобы использовать их в чувствительных к производительности контекстах. Чтобы решить данную проблему, были созданы два профиля спецификаций селекторов. [источник]


:HAS

:has — это одна из самых интересных частей спецификации CSS-селекторов четвёртого уровня, но она сопровождается важным предупреждением, о котором речь пойдёт ниже. Данный селектор позволяет указать, какие объекты должны присутствовать внутри указанного элемента, для того, чтобы это правило сработало по отношению к нему.

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

// Любая секция, в которой есть заголовок
section:has(h1, h2, h3, h4, h5, h6)


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

// Выберем параграфы, которые не имеют чего-либо, не являющегося изображением
p
  :has(img)             // имеет изображение
  :not(:has(:not(img))) // не имеет внутри чего-либо, не являющегося изображением


Можно даже выбрать те элементы, которые имеют определённое количество потомков (в данном примере, пять):

// Сайдбар с пятью элементами внутри
div.sidebar
    :has(*:nth-child(5))       // Имеет пять потомков
    :not(:has(*:nth-child(6))) // Но не шестого


Предостережение: на данный момент, селектор :has не считается быстрым, что означает, что он может оказаться недоступен для использования в файлах стилей. Но, так как еще никто не реализовал на практике данный селектор, вопрос его производительности остаётся открытым. Если разработчики браузеров смогут сделать его реализацию быстрой, вполне возможно, что он будет доступен для использования как один из основных инструментов.

В предыдущей версии спецификации этот раздел был помечен восклицательным знаком и назывался «выбором субъекта селектора» — он имел другой синтаксис, который в настоящее время упразднён.

:MATCHES

:matches — это стандартизация :moz-any и :webkit-any, которая какое-то время присутствовала в браузерских префиксах. Это позволяет автору стиля объединить похожие правила. Например, это может быть полезно для объединения сгенерированного посредством SCSS/SASS вывода, вроде такого:

  body > .layout > .body > .content .post p a.image.standard:first-child:nth-last-child(4) ~ a.image.standard, 
  body > .layout > .body > .content .post p a.image.standard:first-child:nth-last-child(4), 
  body > .layout > .body > .content .post li a.image.standard:first-child:nth-last-child(4) ~ a.image.standard, 
  body > .layout > .body > .content .post li a.image.standard:first-child:nth-last-child(4), 
  body > .layout > .body > .content .page p a.image.standard:first-child:nth-last-child(4) ~ a.image.standard, 
  body > .layout > .body > .content .page p a.image.standard:first-child:nth-last-child(4), 
  body > .layout > .body > .content .page li a.image.standard:first-child:nth-last-child(4) ~ a.image.standard, 
  body > .layout > .body > .content .page li a.image.standard:first-child:nth-last-child(4) {
       ....
}

в несколько более поддающийся контролю вариант:
body > .layout > .body > .content 
    :matches(.post, .page) 
    :matches(p, li) 
    :matches(a.image.standard:first-child:nth-last-child(4), 
             a.image.standard:first-child:nth-last-child(4) ~ a.image.standard), 
       ....
}

На приведённых выше страницах документации Mozilla присутствуют предостережения о его производительности. Так как этот селектор отныне станет стандартом, мы надеемся, что увидим результаты работы над его производительностью, которые помогут сделать его лёгким.

:NTH-CHILD(AN+B [OF S])

В то время как :nth-of-type существует с начала тысячелетия, CSS-селекторы четвёртого уровня добавляют возможность произвести фильтрацию, основанную на селекторе:
div :nth-child(2 of .widget)

Селектор S используется для определения индекса, и он не зависит от селектора, находящегося слева от псевдо-класса. Как написано в спецификации, если вы заранее знаете тип элемента, селектор :nth-of-type может быть преобразован в :nth-child(… of S), подобно этому:
img:nth-of-type(2) => :nth-child(2 of img)

Разница между этим селектором и :nth-of-type небольшая, но она важна. Для :nth-of-type, каждый элемент — указали ли вы для него селектор, или же нет — имеет неявный индекс для себя среди своих собратьев с тем же именем тэга. Выражение :nth-child(n of S) создает новый счётчик каждый раз, когда вы используете новый селектор.

Это создаёт потенциал для возможных багов в новых селекторах. Так как селектор внутри псевдо-класса :nth-child не зависит от селектора слева от него, вы можете случайно пропустить часть вашего запроса, если укажете в левом селекторе всё как следует, но забудете указать всё необходимое внутри :nth-child. Например:
tr:nth-child(2n of [disabled])

Данное правило может не работать так, как вы ожидаете от него, если другие не-tr элементы будут иметь атрибут «disabled».

В прошлой версии спецификации данная возможность называлась как селектор :nth-match.

:NOT()

В то время, когда вы использовали какое-то время :not, теперь вы можете перечислить внутри него несколько аргументов, чтобы сохранить несколько байт и ввести:
// Эквивалентно следующему:
//    :not(h1):not(h2):not(h3)...
:not(h1, h2, h3, h4, h5, h6)


КОМБИНАТОР ПОТОМКОВ (>>)

Комбинатор потомков присутствует в CSS с самого начала в виде пробела ( ), но теперь он имеет явную версию:
// Эквивалентно следующему:
//    p img { ... }
p >> img { ... }

Причина добавления данного правила заключается в организации моста между прямым потомком (>) и оператором для прозрачного DOM (>>>).

КОМБИНАТОР СТОЛБЦА (||) И :NTH-COLUMN

CSS-селекторы четвёртого уровня добавляют операции со столбцами, которые позволяют разработчикам стилей более простым способом изменять дизайн определённых столбцов в таблице. Текущий подход в задании стилей для таблиц требует использования :nth-child, который не всегда совпадает со столбцами таблиц при использовании атрибутов colspan.

При использовании нового комбинатора столбца, вы можете задать стиль ячейкам таблицы, которые находятся в том же столбце, что и заданный элемент col:

// Следующий пример делает ячейки C, E и G жёлтыми
// (пример взят из спецификации CSS-селекторов 4-й версии)
col.selected || td {
  background: yellow;
  color: white;
  font-weight: bold;
}

<table>
  <col span="2">
  <col class="selected">
  <tr><td>A <td>B <td>C
  <tr><td colspan="2">D <td>E
  <tr><td>F <td colspan="2">G
</table>

Как альтернативный вариант, автор может использовать :nth-column и :nth-last-column для задания стилей ячейкам. В любом случае, если ячейка охватывает несколько столбцов, этот селектор затронет любой из них.

:PLACEHOLDER-SHOWN

Одно небольшое дополнение к языку селектора — это :placeholder-shown. Он соответствует input-элементу, если и только если он отображает текст из своего placeholder-атрибута.

:ANY-LINK

:any-link — это еще одно маленькое дополнение. Оно объявлено для соответствия любому из свойств :link или :visited.
// Эквивалентно следующему:
//    a:link, a:visited { ... } 
a:any-link { ... }


ВЫВОДЫ

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

Если у вас возникло желание поиграться с данными селекторами, вы должны дождаться, пока разработчики браузеров догонят спецификацию, или использовать некоторые ранние реализации. :matches доступна как :moz-any и :webkit-any, а ночные сборки WebKit'а имеют раннюю поддержку :nth-child селекторов через активацию по флагу.

Поскольку это черновой вариант, наименования псевдоклассов могут измениться без предупреждения. Следите за спецификациями для получения более подробной информации.

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 33

    –11
    Тухловато… Но пусть делают, посмотрим, что выйдет.
      +4
      К моему возмущению, в прошлом году выкинули idref combinator. В результате как отсутствует напрашивающаяся возможность стилизовать label, относящийся к input[type=«check»], в зависимости от состояния последнего, так её и не предвидится.
        +7
        «:has» — очень интересный селектор. Долгожданная реализация «parent-селектора», о необходимости которого было столько дискуссий. Далеко не худшим способом реализовали, надо сказать, другие варианты были тухлее.
          +1
          Только вот неспроста говорят, что медленно.
          До этого все селекторы были регулярным языком; добавление этого селектора эту регулярность ломает.
          • UFO just landed and posted this here
        • UFO just landed and posted this here
            +1
            Большое спасибо за ссылку. Я пару секунд не мог понять, что ещё за уровни, а потом решил забить на это при переводе и назвать их версиями. Чуть позже исправлю статью.
            +4
            Не, не впечатлили.
            Куча вещей, которые можно сделать препроцессорами, пара сомнительных мелких нововведений и :has, который, конечно, всем хотелось (да и мне тоже), но который стооолько геммороя принесет. И с быстродействием, и с починкой кривой верстки.
              0
              Нормальный родительский селектор решили не делать значит
                0
                А в чём разница?
                  0
                  На мой взгляд это тот, который первым приходит в голову при словосочетании «родительский селектор» и работает от элемента, например a ^ div. С производительностью не было никаких проблем.

                  Плюс, весь код (стили состояния элемента и зависимые стили родителя от этих состояний) был бы собран в одном месте. Хотя это вопрос сложный. При большом количестве зависимостей от потомков, удобнее их было бы собирать на родительском элементе
                    +1
                    Не думаю, что по скорости это отличается от :has, по сути — это две формы указания того, что применять селектор надо не к конечному элементу, а к элементу, который находится в середине.
                      0
                      В случае с прямым селектором нам надо просто подняться на Х уровней вверх.
                      В случае с :has нужно проанализировать поддерево, которое может быть достаточно большим.
                      +1
                      Так а чем это отличается от div:has(a), кроме формы написания?
                  +1
                  <table>
                    <col span="2">
                    <col class="selected">
                    <tr><td>A <td>B <td>C
                    <tr><td colspan="2">D <td>E
                    <tr><td>F <td colspan="2">G
                  </table>
                  

                  Как понимаю, это аналог такого?
                  <table>
                    <col span="2"></col>
                    <col class="selected"></col>
                    <tr>
                      <td>A</td>
                      <td>B</td>
                      <td>C</td>
                    </tr>
                    <tr>
                      <td colspan="2">D</td>
                      <td>E</td>
                    </tr>
                    <tr>
                      <td>F</td>
                      <td colspan="2">G</td>
                    </tr>
                  </table>
                  

                  Я имею в виду отсутствие закрывающих тегов.
                    0
                    Закрывающий не обязателен в некоторых случаях: www.w3.org/TR/html/tabular-data.html#the-td-element
                    • UFO just landed and posted this here
                        0
                        Да, помню это ещё с книг по html 4, но всё же очень давно не сталкивался.
                        0
                        Кстати, в таком стиле (без закрывающих тэгов), если я не путаю, уже давно можно писать код) хотя я до сих пор не заимел такой привычки. Я сейчас проверил, да, браузер нормально воспринимает подобные махинации) Интересно, есть где-нибудь статья на эту тему?
                        • UFO just landed and posted this here
                          • UFO just landed and posted this here
                        +1
                        Интересно, а прокатит ли что-то типа этого в JS?
                        node.querySelectorAll('.parent:has(::scope)');
                        

                        Вместо небогоугодного, но безальтернативного (кроме кучи кода)
                        jQuery(node).parents('.parent');
                        
                        • UFO just landed and posted this here
                            0
                            Киньте ссылочку, пожалуйста, гугл не помог.
                            • UFO just landed and posted this here
                                0
                                Я бы оценил ваш юмор по достоинству, если бы было очевидно, что вы имеете в виду в предыдущем комметарии. Вы, наверно, поспешили ответить мне, не прочтя моего комментария. Цитирую: «Гугл не помог».
                                • UFO just landed and posted this here
                          +1
                          Вот что мне не понятно, так это то, почему до сих пор блуждание по тегам невозможно унифицировать на единой платформе?! Есть XPath, jQuery, нативные JS getElementById, выбор элементов в CSS, добавим ещё всякие библиотечные решения да ещё основу — регулярные выражения. При этом, в сущности, ищут все по одному и тому же дереву документа, но каждый норовит изобрести что-то своё. Понятно, что CCSникам сложно, наверное, оперировать XPath, но этот зоопарк — ещё больше запутывает ситуацию. Уж лучше избрать какую-то, пусть сложную, но единую основу поиска по дереву документа.
                          • UFO just landed and posted this here
                            • UFO just landed and posted this here
                              • UFO just landed and posted this here
                                • UFO just landed and posted this here
                            0
                            В старенькой статье тоже неплохо описаны плюшки: habrahabr.ru/post/167333/
                            Тест css4 селекторов в браузере: css4-selectors.com/browser-selector-test/

                            Only users with full accounts can post comments. Log in, please.