Управление загрузкой CSS с помощью пользовательских свойств

Перевод статьи Control CSS loading with custom properties с сайта jakearchibald.com, опубликовано на css-live.ru, автор — Джейк Арчибальд.

На прошлой неделе я писал о простом методе постепенной загрузки CSS, и в этот же день учёные заставили гравитацию поволноваться. Совпадение? Не иначе.

Паттерн из предыдущей статьи охватывал 90% случаев многоэтапной загрузки CSS, и его простота вполне очевидна. Но не угодно ли вам послушать про паттерн, который подходит к ~100% случаев и при этом до нелепого сложен? Тогда приглашаю вас пройти вместе со мной в следующий абзац…

Недостающие 10%

Пока загружается CSS, <link> в <body> блокирует парсер, а значит отрисовка блокируется и для всего последующего содержания. Согласно демо-странице из вышеупомянутой статьи, отрисовка делится на следующие этапы.

Мобильники

2016-02-21_2001

Компьютеры

2016-02-21_2002

Это здорово для мобильных, где каждый CSS для раздела блокирует себя и все последующие разделы, но на десктопе CSS для main и comments в левой колонке блокирует отрисовку about-me в правой колонке, даже если CSS для about-me загружается первым. Это потому, что очередность блокировки определяется порядком в исходном коде, но для этого дизайна было бы здорово, чтобы правая колонка отобразилась раньше левой.

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

Это можно сделать с помощью пользовательских свойств CSS…

Пользовательские свойства CSS

На MDN есть отличная статья про пользовательские свойства CSS, но для нашей сегодняшней беседы достаточно знать вот что…

html {
  background: var(--gloop, red);
}

Здесь мы задаём фону страницы значение из пользовательского свойства --gloop, а если его нет — red в качестве запасного варианта. В результате фон будет красным. Но если добавить:

:root {
  --gloop: green;
}

…мы устанавили пользовательскому свойству --gloop значение green, так что теперь страница зелёная. Но если добавить:

:root {
  --gloop: initial;
}

Значение initial здесь обрабатывается особым образом. Оно фактически отменяет --gloop, так что теперь фон страницы снова красный.

Построение дерева зависимостей отрисовки с помощью пользовательских свойств CSS

Дописывая этот заголовок, я аж сам порадовался, какой я умный.

The HTML

<head>
  <link rel="stylesheet" href="/initial.css">
  <script>
    [
      '/main.css',
      '/comments.css',
      '/about-me.css',
      '/footer.css'
    ].map(url => {
      const link = document.createElement('link');
      link.rel = 'stylesheet';
      link.href = url;
      document.head.appendChild(link);
    });
  </script>
</head>

Так что можно загрузить /initial.css с помощью <link> или встроить его, раз уж всё равно он блокирует отрисовку. Но мы загружаем все остальные таблицы стилей асинхронно.

initial.css

main,
.comments,
.about-me,
footer {
  display: none;
}

:root {
  --main-blocker: none;
  --comments-blocker: none;
  --about-me-blocker: none;
  --footer-blocker: none;
}

/* Остальные начальные стили... */

Скрываем разделы, которые мы ещё не готовы отобразить, а затем для каждого раздела создаём пользовательское свойство-«блокировщик».

main.css

:root {
  --main-blocker: initial;
}

main {
  display: var(--main-blocker, block);
}

/* Остальные стили основного содержимого... */

У основного содержания нет никаких зависимостей отображения. Как только CSS загрузится, его блокировщик отменяется (с помощью initial) и отображает его.

comments.css

:root {
  --comments-blocker: var(--main-blocker);
}

.comments {
  display: var(--comments-blocker, block);
}

/* Остальные стили комментариев... */

Комментарии не должны отображаться до основного содержимого, поэтому блокировщик комментариев связывается с --main-blocker. Блок .comments становится видимым, как только этот CSS загружается и --main-blocker отменяется

about-me.css

:root {
  --about-me-blocker: var(--comments-blocker);
}

.about-me {
  display: var(--about-me-blocker, block);
}

Аналогично приведённому выше коду, .about-me зависит от своего CSS и комментариев. Но когда страница шире, она отображается в двух колонках, поэтому нам больше не нужно, чтобы .about-me зависел от комментариев в плане отображения:

@media (min-width: 600px) {
  :root {
    --about-me-blocker: initial;
  }
}

/* Остальные стили для about-me… */

Готово! Когда ширина области просмотра свыше 600px, .about-me отображается сразу после загрузки его CSS.

footer.css

:root {
  --footer-blocker: var(--main-blocker, var(--about-me-blocker));
}

footer {
  display: var(--footer-blocker, block);
}

/* Остальные стили… */

Подвал должен отобразиться после появления главных разделов content и about-me. Для этого --footer-blocker берёт своё значение из --main-blocker, но сразу после отмены --main-blocker --footer-blocker откатывается к значению, взятому из --about-me-blocker.

Демо

Посмотреть демо — требуется Chrome Canary или Firefox.

В этом демо CSS загружается асинхронно, затрачивая на загрузку каждого файла примерно 0-5 секунд. Несмотря на это, страница никогда не отобразится не в том порядке, а каждый раздел отобразится при первой возможности в зависимости от ширины браузера.

Но… практично ли это?

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

Если и правда есть желание делать что-то подобное уже сегодня, то можете взвалить основную часть работы на плечи асинхронной загрузки CSS с помощью loadCSS, и добавлять классы к <html>, как только определенные стили загрузятся (смотрите демо), хотя это приведёт к множеству специфических проблем, решаемых через хаки.

Думаю, эту статью можно расценивать, как «забавный пример», но мы едва начали открывать мощь пользовательских свойств CSS.

Благодарю Реми Шарпа за исправления. Будет ли когда-нибудь у меня статья без орфографических ошибок? Нидокга.

P.S. Это тоже может быть интересно:

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

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