Generic First CSS: новое мышление в первую очередь для мобильных устройств

Опубликовано: 2022-03-10
Краткое резюме ↬ С ​​появлением адаптивного веб-дизайна и подхода, ориентированного на мобильные устройства, прошло семь замечательных лет с тех пор, как любые новые концепции заставляли нас адаптировать способ написания CSS на базовом уровне. Ну, я не могу предложить вам ничего особенного, но у меня есть небольшой сюрприз. Вот: универсальный первый CSS.

Я думаю, можно с уверенностью сказать, что «Отзывчивый веб-дизайн» Итана Маркотта стал долгожданным открытием для веб-разработчиков во всем мире. Это вызвало совершенно новую волну дизайнерского мышления и замечательных новых методов интерфейса. Господство часто презираемых веб-сайтов m-dot также закончилось. В ту же эпоху и почти столь же влиятельную методологию Mobile First Люка Вроблевски — существенное усовершенствование, основанное на впечатляющем фундаменте Маркотта.

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

Путешествие к дженерику

Я не могу точно определить, что заставило меня изменить то, как я пишу свой CSS, потому что это был действительно естественный прогресс для меня, который произошел почти бессознательно. Оглядываясь назад, я думаю, что это был скорее побочный продукт среды разработки, в которой я работал. У команды, с которой я работал, был хороший рабочий процесс SCSS с отличным небольшим миксином для простого добавления точек останова в наши объявления CSS. Вы, вероятно, используете подобную технику.

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

 .bio { display: block; width: 100%; background-color: #ece9e9; padding: 20px; margin: 20px 0; @include media('>=small') { max-width: 400px; background-color: white; margin: 20px auto; } @include media('>=medium') { max-width: 600px; padding: 30px; margin: 30px auto; } @include media('>=large') { max-width: 800px; padding: 40px; margin: 40px auto; } @include media('>=huge') { max-width: 1000px; padding: 50px; margin: 50px auto; } }

Рисунок 1. Типичный мобильный сначала с каскадными медиа-запросами

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

Еще после прыжка! Продолжить чтение ниже ↓

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

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

 .bio { display: block; width: 100%; padding: 20px; margin: 20px 0; @include media('>=small', ' < medium') { max-width: 400px; margin: 20px auto; } @include media('>=medium', ' < large') { max-width: 600px; padding: 30px; margin: 30px auto; } @include media('>=large', ' < huge') { max-width: 800px; padding: 40px; margin: 40px auto; } @include media('>=huge') { max-width: 1000px; padding: 50px; margin: 50px auto; } }

Рис.2. Пример разделенных медиа-запросов

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

Я все еще не был на 100% доволен вышеизложенным, хотя казалось, что еще предстоит решить серьезную проблему.

Проблема с Mobile First

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

Итак, для меня ответ был очевиден: давайте доведем идею разделения медиа-запросов до логического завершения — мы также разделим стили, специфичные для мобильных устройств, на их собственные медиа-запросы. Я знаю, я знаю, это противоречит общему правилу, которое мы усвоили за эти годы. «Сначала мобильные» настолько распространены, что обычно это один из вопросов о «навыках», который задает менеджер по найму. Так что, конечно, любая альтернатива должна быть неправильной, не так ли? Обычно это та часть, когда люди качают головами, повторяя сначала мобильный снова и снова.

Итак, мы собираемся разрушить догму mobile first и разделить все наши стили на соответствующие медиа-запросы. Теперь у нас остались чистые общие стили, объявленные в селекторе CSS, со всеми остальными специфическими для устройства стилями, инкапсулированными в медиа-запросы, которые применяются только к соответствующим размерам экрана. Теперь у нас есть Generic First CSS :

 .bio { display: block; width: 100%; @include media('>=0', ' < small') { padding: 20px; margin: 20px 0; } @include media('>=small', ' < medium') { max-width: 400px; margin: 20px auto; } @include media('>=medium', ' < large') { max-width: 600px; padding: 30px; margin: 30px auto; } @include media('>=large', ' < huge') { max-width: 800px; padding: 40px; margin: 40px auto; } @include media('>=huge') { max-width: 1000px; padding: 50px; margin: 50px auto; } }

Рис.3. Пример универсального первого CSS

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

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

Когда не следует разделять

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

Блаженство инструмента разработки

Одним из основных непреднамеренных последствий написания разделенного на части Generic First CSS является опыт, который вы получите от панели стилей инструментов разработчика. Без каскада медиа-запросов у вас теперь будет более четкое представление о том, какие стили применяются — У вас не будет панели стилей, полной вычеркнутых объявлений из перезаписанных правил медиа-запросов — Шума больше нет! Для меня это одно из самых больших преимуществ метода Generic First CSS. Это вносит немного больше здравого смысла в отладку CSS, и это на вес золота. Отблагодаришь позже.

Снимок экрана до и после того, как общий первый подход CSS влияет на панель стилей chrome dev tools.
Рис.4. Как общий, разделенный на части css может помочь принести радость и здравомыслие вашей консоли разработчика. (Большой превью)

Влияние на производительность

Итак, все эти преимущества Generic First CSS начинают звучать довольно хорошо, но я думаю, что есть еще один ключевой вопрос, который, как мне кажется, необходимо решить. Речь идет об оптимизации производительности. Теперь я еще не знаю наверняка, но у меня есть подозрение, что полностью разделенные медиа-запросы могут иметь небольшое преимущество в производительности.

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

Итак, вернемся к общему первому CSS: есть ли какие-либо проблемы с производительностью, связанные с тем, что браузеру приходится обрабатывать CSS-специфику множества каскадных медиа-запросов?

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

Тестовый случай

Тестовый пример состоит из базовой HTML-страницы, которая выводит блок «био» 5000 раз, разметка одинакова для каждого блока, но классы немного отличаются (числовой дифференциатор), CSS для этого блока также выводится 5000 раз. , единственное, что различается, это имена классов. Выводимый CSS передается через инструмент под названием CSS MQPacker, который помогает значительно уменьшить размер файла CSS, который использует множество встроенных медиа-запросов, путем объединения всех отдельных экземпляров определенного медиа-запроса в один — это отличный инструмент, который, вероятно, принесет пользу. большинство современных кодовых баз CSS — я использовал его как отдельный инструмент cli через задачу npm в тестовых проектах package.json, вы также можете использовать его как плагин postcss, что приятно и удобно!

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

Тест выполнялся 20 раз для каждой вариации CSS в десктопном Google Chrome v70. Небольшой набор данных, но достаточный, чтобы дать мне приблизительное представление о приросте/падении производительности.

Метрики тестирования, которые я выбрал для использования, следующие:

  • Общее время загрузки страницы
    Базовая метрика для проверки времени загрузки страницы с использованием маркеров Performance API в начале <head> и самом конце <body>.
  • Стиль пересчета
    Время на панели производительности инструментов разработчика.
  • Общий рендеринг страницы
    Время на панели производительности инструментов разработчика.
Таблица результатов профилировщика производительности Google Chrome
Рис.5. Основной измеряемой метрикой является «Пересчет стиля». (Большой превью)

Таблица результатов (все время в миллисекундах)

Мобильный прежде всего Общий Первый
Время загрузки Рассчитать стили Общее время рендеринга Время загрузки Рассчитать стили Общее время рендеринга
1135 565,7 1953 г. 1196 536,9 2012
1176 563,5 1936 г. 1116 506,9 1929 г.
1118 563,1 1863 г. 1148 514,4 1853 г.
1174 568,3 1929 г. 1124 507.1 1868 г.
1204 577,2 1924 г. 1115 518,4 1854 г.
1155 554,7 1991 г. 1177 540,8 1905 г.
1112 554,5 1912 г. 1111 504,3 1886 г.
1110 557,9 1854 г. 1104 505,3 1954 г.
1106 544,5 1895 г. 1148 525,4 1881 г.
1162 559,8 1920 г. 1095 508,9 1941 г.
1146 545,9 1897 г. 1115 504,4 1968 г.
1168 566,3 1882 г. 1112 519,8 1861 г.
1105 542,7 1978 г. 1121 515,7 1905 г.
1123 566,6 1970 г. 1090 510,7 1820 г.
1106 514,5 1956 г. 1127 515,2 1986 г.
1135 575,7 1869 г. 1130 504.2 1882 г.
1164 545,6 2450 1169 525,6 1934 г.
1144 565 1894 г. 1092 516 1822 г.
1115 554,5 1955 г. 1091 508,9 1986 г.
1133 554,8 2572 1001 504,5 1812 г.
СРЕДНИЙ 1139,55 557.04 1980 г. 1119.1 514,67 1903.15

Рис.6. 20 тестовых прогонов для измерения ключевых показателей загрузки/рендеринга мобильных устройств в сравнении с обычными первыми CSS.

Судя по моему, по общему признанию, небольшому набору данных, мое первоначальное подозрение может быть верным. В среднем, я вижу, что задача Style Recalculation занимает на 42 мс меньше времени, что означает увеличение скорости на 7,6%, и, следовательно, общее время рендеринга также уменьшается. Разница не сногсшибательная, но это улучшение. Я не думаю, что набор данных достаточно велик, чтобы быть на 100% убедительным, а тестовый пример немного нереалистичен, но я очень рад, что не вижу снижения производительности.

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

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

Заключение

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

  • CSS, который работает именно так, как задумано, без лишних догадок;
  • Самодокументирующиеся медиа-запросы;
  • Улучшенный опыт работы с инструментами разработки;
  • Страницы, которые отображаются быстрее.

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

Заключительное слово

Как и все методологии разработки, это может быть не для всех, но я вполне естественно попал в Generic First CSS, теперь я вижу в нем ценный способ работы, который дает мне все преимущества mobile first с некоторыми положительными новыми дополнениями, которые делают тяжелая работа по фронтенд-разработке стала немного проще.

Ресурсы

Репозиторий тестовых случаев

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

Инструменты

  • CSS MQPacker
  • Включить медиа