Фото Джантин Дурнбос на Unsplash

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

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

Чтобы исправить это, я провела некоторые исследования и составила небольшой список понятий, которые считаю интересными и полезными для лучшего понимания и написания CSS.

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

Терминология


Как и в любом языке программирования, для описания понятий используются определённые термины. Будучи языком программирования, CSS ничем не отличается, поэтому важно изучение некоторой терминологии, чтобы упростить общение и просто для личного развития.

Комбинатор потомков


Видели пробел между селекторами в вашем стиле? На самом деле у него есть название, это комбинатор потомков (descendant combinator).


Комбинатор потомков

Макет, отрисовка и композиция


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

1. Макет (layout)


Шаг макетирования — это расчёт, сколько места элемент занимает на экране. Изменение свойства 'layout' в CSS (например, ширина, высота) означает, что браузеру придётся проверить все остальные элементы и перерисовать страницу, то есть перекрасить затронутые области и наложить их друг на друга.

2. Отрисовка (paint)


Этот процесс заполняет пикселями все визуальные части элементов (цвета, границы и т. д.). Отрисовка элементов обычно выполняется на нескольких слоях.

Изменение свойства 'paint' не влияет на макет, поэтому браузер пропускает шаг макетирования, но всё равно делает отрисовку.

На отрисовку зачастую уходит больше всего времени при рендеринге.

3. Композиция (composite)


Композиция — это шаг, на котором браузер должен отрисовать слои в правильном порядке. Поскольку некоторые элементы могут перекрывать друг друга, на этом этапе браузер проверяет, что элементы отображаются в указанном порядке.

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

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

Производительность CSS


Селектор потомков может дорого обойтись


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

Например:


Пример селектора потомков

Браузеру придётся оценить все ссылки на странице, прежде чем перейти к тем, которые находятся внутри нашего раздела #nav.

Более эффективный способ — добавить конкретный селектор .navigation-link на каждую ссылку <a> внутри раздела #nav.

Браузер считывает селекторы справа налево


Кажется, я должна была раньше узнать эту важную вещь, но я не знала… При парсинге CSS браузер разбирает селекторы справа налево.

Рассмотрим следующий пример:


Браузер читает справа налево

Шаги:

  • сопоставить все <a> на странице;
  • найти все <a>, содержащиеся в <li>;
  • взять совпадения и сузить их до тех, которые содержатся в <ul>;
  • наконец, отфильтровать вышеупомянутый выбор до тех, которые содержатся в элементе с классом .container.

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

Чтобы улучшить производительность приведённого примера, мы могли бы заменить .container ul li a, добавив что-то вроде .container-link-style на самом теге <a>.

По возможности не изменяйте макет


Изменения некоторых свойств CSS требуют обновления всего макета.

Например, геометрические свойства width, height, top, left требуют заново рассчитать макет и обновить дерево рендеринга.

Если вы измените эти свойства на многих элементах, потребуется много времени для вычисления и обновления их положения/размера.

Будьте осторожны со сложностью отрисовки


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

Дорогие свойства CSS


Некоторые свойства CSS дороже других. Это означает, что отрисовка происходит дольше.

Некоторые из дорогих свойств:

  • border-radius
  • box-shadow
  • filter
  • :nth-child
  • position: fixed

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

Порядок (ordering)


Порядок имеет значение


Посмотрим на такой CSS:



А затем посмотрим на HTML-код:



Порядок селекторов в HTML не имеет значения, а в CSS — имеет.



Хороший способ оценить производительность CSS — использовать инструменты разработчика в браузере.

В Chrome или Firefox можете открыть инструменты разработчика, перейти на вкладку «Производительность» и записать, что происходит при загрузке или взаимодействии с вашей страницей.


Скриншот вкладки «Производительность» в Chrome

Ресурсы


Исследуя тему для этой статьи, я наткнулась на некоторые действительно интересные инструменты, перечисленные ниже:

CSS Triggers — веб-сайт, перечисляющий некоторые свойства CSS и как они влияют на производительность.

Uncss — инструмент для удаления неиспользуемых стилей из CSS.

Css-explain — небольшой инструмент, объясняющий селекторы CSS.

Fastdom — инструмент пакетных операций чтения/записи DOM для ускорения производительности макета.

Пока всё! Надеюсь, это имеет смысл!

Комментарии (27)


  1. Utopia
    26.03.2019 00:51

    С какого перепугу css язык программирования?


    1. azmar
      26.03.2019 01:26

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

      Но статья, конечно, заставила задуматься что это немного сложнее, чем кажется.


    1. wtpltd
      26.03.2019 02:40

      Неожиданно, CSS является тьюринг-полным.
      Другой вопрос, что неизвестно что лучше: кодить задачи на брейнфаке или на css.
      Другой-другой вопрос, что CSS воспринимается и используется как декларативная шестеренка, поэтому обзывание его «языком программирования», это как называть микроскоп молотком.


      1. pallada92
        26.03.2019 18:00
        +1

        Если речь идет об этой реализации правила 110, то она требует действий пользователя: постоянного нажатия Tab + space (сначала нужно накликать желаемое начальное состояние в первой строке, потом следовать инструкции). С таким же успехом Тьюринг-полными можно назвать комментарии на Хабре и камни на берегу моря. Мне кажется, это не совсем честная Тьюринг-полнота, т.к. требует активного участия человека в вычислениях, по крайней мере для меня как любителя портировать трехмерные движки на все подряд.


        1. 0xd34df00d
          27.03.2019 03:53

          Оно не требует осмысленного участия человека и не требует принятия решений. Норм, ИМХО.


    1. vasyapivo
      26.03.2019 07:48

      Какой лучший перевод, для computer language?


      1. jt3k
        27.03.2019 00:34

        "Как и в любом компьютерном языке, для описания понятий...."


        "Как и в любом языке компьютера, для описания понятий...."


        я за второй вариант



  1. kashey
    26.03.2019 04:02

    > Он содержит только новое, что я узнала за последние несколько дней и чем хочу поделиться, вдруг это поможет кому-то ещё.

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


    1. Matisumi
      26.03.2019 11:58

      Совершенно не удивительно, что с такими google developer expert новый gmail теперь две и более минут сохраняет статус «прочитано» у прочитанного письма.


      1. Vadem
        26.03.2019 22:22

        Google developer expert — это не должность в гугл. Автор оригинальной статьи работает в ThoughtWorks.


    1. SergeiMinaev
      26.03.2019 21:37

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

      и иногда я понимаю, что о некоторых важных нюансах CSS мне никто не рассказал, потому что люди просто не тратят время на изучение этой темы.

      Чтобы исправить это, я провела некоторые исследования и составила небольшой список


      Странная логика. Почему кто-то ей должен был об этом говорить?


  1. spmbt
    26.03.2019 09:41

    > Селектор потомков может дорого обойтись

    Хорошо бы показывать доказательную ссылку на исследования, а не просто «мне так сказали». По логике селекторов, ничто не мешает анализировать теги «a» только внутри области старшего селектора и этим могут различаться различные движки.


    1. Aingis
      26.03.2019 11:39

      Есть классическое описание процесса авторства Дэвида Бэрона: «How browser rendering works».
      tl;dr: браузер во время применения стилей обрабатывает DOM-ноды и проверяет каждую ноду на соответствие селектору. Поэтому логично проверять сначала на соответствие правой части селектора, а зачем по необходимости проверить предыдущие и родительские.

      Именно поэтому нет селектора, зависящего от следующего соседа, или :has() (в селекторах 4 уровня работает только в querySelector(All)) — слишком усложнит и замедлит процесс. Это особенно важно для анимаций, где желательно быстро обновлять необходимые значение. Вот, например, доклад Дэвида про анимации: vimeo.com/103108124


    1. kashey
      26.03.2019 12:07

      В Яндексе проводили много исследований по этому делу, и расказывали много раз на Субботниках, и было это 6-8 лет назад (в общем давно).
      С тех пор многое что изменилось, в том числе в Firefox(а вот это было уже недавно) прилетел новый CSS парсер, который парсит по-человечески.

      Век учись, век переучивайся.


      1. movl
        26.03.2019 13:00

        Не совсем понятно что значит «по-человечески» с алгоритмической точки зрения. Я думаю можно завести какие-то эвристики, которые на достаточно ранних этапах будут отсекать некоторые селекторы, для некоторых веток DOM. Но как в целом поменять механизм проверки селектора от потомка к родителю совершенно не представляю. Единственный вариант, это поменять местами DOM и CSS, то есть не для каждого элемента DOM искать селекторы CSS, а для каждого селектора CSS искать DOM элементы, что частично соответсвует человеческой логики, но я не понимаю как это может эффективно работать с точки зрения машины.


        1. kashey
          26.03.2019 14:45

          O! Про «как» отличная статья вышла еще год назад — hacks.mozilla.org/2017/08/inside-a-super-fast-css-engine-quantum-css-aka-stylo


          1. movl
            26.03.2019 14:58

            Да, я глянул статью "Внутри супер-быстрого CSS-движка: Quantum CSS (aka Stylo)" и даже исходный код посмотрел, так как сам когда-то свой велосипед писал и мне интересно как эту логику реализуют другие. Оптимизации и распараллеливание заслуживают отдельного внимания, отсюда и может идти разговор о стоимости, особенно если стоимость определять в контексте усредненного приложения, тут даже есть предмет для исследований. Но общая логика алгоритма такая, что проверка селектора происходит рекурсивно, от потомка к родителю, а следовательно совет в статье логичный и является всего лишь следствием из алгоритма, никаких исследований для этого следствия не нужно.


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


      1. Punk_UnDeaD
        26.03.2019 14:07

        Сейчас даже часы могут ракету на Луну отправить, а всё то же, медленные цсс селекторы.


        1. SergeiMinaev
          26.03.2019 21:52

          Не могут.


  1. sumanai
    26.03.2019 21:38
    +2

    Не ожидал прочитать в 2019 баяны из 2010.


  1. Vahman
    26.03.2019 22:36

    И правда, об этих вещах не пишут в starter tutorial. И многие о них так и не узнают, так как на большинстве проектов производительность css находится где-то в пределах погрешности. Сам я этой темой заинтересовался, когда начал пилить enterprise с чрезвычайно перегруженным dom. Теперь на собеседованиях фронтов и верстальщиков часто задаю вопросы о производительности css, как минимум на уровне приоритета селекторов и примеров «дорогих» css свойств. Как показывает практика — знание не очень распространенное


    1. knotri
      26.03.2019 23:37
      +1

      Сам я этой темой заинтересовался, когда начал пилить enterprise с чрезвычайно перегруженным dom

      на большинстве проектов производительность css находится где-то в пределах погрешности.

      Теперь на собеседованиях фронтов и верстальщиков часто задаю вопросы о производительности css

      Это что, такая форма доминирования? Унижения? Издевательства? Вещь редкая, нужна мало где, так давайте как я буду её спрашивать у верстальщиков (которые зачастую новички) либо фронтов (которые мало касаются верстки)


      1. Vahman
        27.03.2019 10:44

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

        Вещь редкая, нужна мало где

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

        Может быть я не прав, но если фронт не умеет толково верстать — это у меня вызывает непонимание


  1. botyaslonim
    26.03.2019 23:48

    Шаг 0: некоторым не говорили, что это «си эс эс», а не «ка эс эс»


    1. Raftko
      27.03.2019 14:08

      Мы сейчас говорим о «цэ эс эс»?


  1. WanSpi
    27.03.2019 13:36
    -1

    Как я люблю описание на манер «Так надо делать, и не задавайте лишних вопросов»

    Некоторые из дорогих свойств:
    border-radius
    box-shadow
    filter
    :nth-child
    position: fixed

    Почему свойства border-radius / box-shadow / filter являються ресурсо затратными это понятно, но вот почему к этому списку припадает :nth-child? Не думаю что он настолько же тяжелый как тот же box-shadow, а так же насколько сильно отличаеться :nth-child(2n) от :nth-child(2) по производительности.
    Так же можно было немного сказать про position: fixed / absolute, что они отрисовываються вообще отдельно, и так же просчитываються отдельно.