CSS-in-JS — мифы и реальность (на примере styled-components) / Хабр
CSS-in-JS, будучи не совсем новой технологией и реализованной во множестве библиотек, до сих пор вызывает сомнения и споры в целесообразности ее использования. Свои точки над «i» в спорах о CSS-in-JS в общем, и о styled-components в частности, расставил еще год назад, ( 27 Apr 2017 ), и Gajus Kuizinas, автор react-css-modules и babel-plugin-react-css-modules, во все еще, на мой взгляд, актуальной публикации «Прекратите использовать CSS-in-JavaScript в веб-разработках».
Ниже предлагается слегка сокращенный ее перевод с некоторыми добавлениями и выводами:
CSS никуда не уходит. Во множестве проектов выбор в пользу стилизации в JavaScript делается ошибочно. Мы приведем перечень распространенных заблуждений(мифов) и соответствующих им решений посредством CSS.
История Css и JavaScript
CSS был создан для описания представления документа, написанного на языке разметки. JavaScript был создан, как «язык-клей» для сборки компонентов, таких, как изображения и плагины. Спустя годы, JS рос и изменялся, приспосабливаясь ко все новым сферам применения. И, как результат, мы сегодня живем в эру одностраничных приложений (SPA), приложений собранных из компонентов.
А что же с CSS?
Приведем цитату из документации styled-components:
Проблема обычного CSS состоит в том, что он был создан в эру, когда веб состояла из документов. Web была создана для обмена по преимуществу научными документами в 1993 году и CSS был введен, как решение для стилизации этих документов. Однако, сегодня мы разрабатываем развитые, интерактивные, ориентированные на пользователя приложения, а CSS просто не предназначен для этого.
Это не так.
CSS уже учитывает все требования современных пользовательских интерфейсов. Количество новых функций, реализованных в последнее десятилетие таково, что их все невозможно здесь даже перечислить (pseudo-classes, pseudo-elements, CSS variables, media queries, keyframes, combinators, columns, flex, grid, computed values, …).
С точки зрения пользовательского интерфейса, «component» — это изолированный фрагмент документа (<button />- это «component»). CSS создан для стилизации документов, а документ охватывает все компоненты. В чем же проблема?
Как говорится: «Используйте правильный инструмент для работы».
Styled-components
styled-components
дает возможность написания CSS в JavaScript используя т.н. тегированные шаблонные строки. Библиотека удаляет сопоставление между компонентами и стилями — компонент превращается в конструкцию с низкоуровневой стилизацией, например:// Create a <Title> react component that renders an <h2> which is
// centered, palevioletred and sized at 1.5em
const Title = styled.h2`
font-size: 1.5em;
text-align: center;
color: palevioletred;
`;
styled-components сегодня пользуется популярностью и известна, как новый способ стилизации компонентов в React, хотя иногда ее представляют даже, как «вершину развития CSS»:
CSS Evolution: From CSS, SASS, BEM, CSS Modules to Styled Components.
Но давайте уясним следующее: styled-components — это всего лишь надстройка над CSS. Эта библиотека разбирает стили CSS, определенные вами в JavaScript и создает соответствующие JSX элементы.
Популярность styled-components сопряжена со множеством заблуждений. Обзор ответов программистов (найденных на IRC, Reddit и Discord) на вопрос о причинах, побудивших их применить эту библиотеку, позволил составить список наиболее упоминаемых. Назовем их мифами.
Миф #1: styled-components решает проблемы глобального пространства имен и конфликтов стилей
Это миф, потому что звучит так, якобы упомянутая проблема еще никак не решалась. Однако CSS Modules, Shadow DOM и бесчисленные соглашения по именованиям ( такие как BEM) предложили решения проблемы давным давно.
styled-components (точно так же, как и CSS modules) снимает с человека проблему ответственности за наименования. Человеку свойственно ошибаться, компьютеры ошибаются не столь часто.
Сам по себе, это еще недостаточно веский довод для использования styled-components.
Миф 2: Использование styled-components дает возможность получать более компактный код
В подтверждение часто приводят пример:
<TicketName></TicketName>
<div className={styles.ticketName}></div>
Прежде всего — это не имеет значения. Разница незначительна.
<TinyBitLongerStyleName></TinyBitLongerStyleName>
<div className={styles.longerStyleName}></div>
То же самое применимо и к созданию стилей, что мы увидим позже в этой статье
(Миф5: styled-components облегчает условную стилизацию компонентов). styled-components выигрывает в краткости только в случаях самых базовых компонентов.
Миф 3. Использование styled components вынуждает больше думать о семантике
Сам первоначальный посыл ошибочен. Стилизация и семантика представляют собой разные проблемы и требуют различных решений. Прочтите, например, это Adam Morse (mrmrs).
Тем не менее, рассмотрим:
<PersonList>
<PersonListItem>
<PersonFirstName>Foo</PersonFirstName>
<PersonLastName>Bar</PersonLastName>
</PersonListItem>
</PersonList>
Семантика занимается применением правильных тегов для разметки. А вы знаете, какие HTML теги будут использованы для рендеринга такого компонента? Нет, не знаете.
<ol>
<li>
<span className={styles.firstName}>Foo</span>
<span className={styles.lastName}>Bar</span>
</li>
</ol>
Миф 4: Проще расширять стили
Сравните:
const Button = styled.button`
padding: 10px;
`;
const TomatoButton = Button.extend`
color: #f00;
`;
Замечательно! Но то же самое вы можете сделать и в CSS (или использовать CSS module composition, а также SASS inheritance mixin @extend).
button {
padding: 10px;
}
button.tomato-button {
color: #f00;
}
И чем проще первый вариант?
Миф 5: Облегчается условная стилизация компонентов
Идея состоит в том, что вы можете стилизовать элементы используя props, например:
<Button primary />
<Button secondary />
<Button primary active={true} />
Это имеет смысл в React. В конце концов, поведение компонента контролируется через props. Есть ли смысл в прямой привязке prop значений к стилям? Может быть. Но давайте рассмотрим имплементацию такого компонента:
styled.Button`
background: ${props => props.primary ? '#f00' : props.secondary ? '#0f0' : '#00f'};
color: ${props => props.primary ? '#fff' : props.secondary ? '#fff' : '#000'};
opacity: ${props => props.active ? 1 : 0};
`;
Создание условных стилей при помощи JavaScript дает массу возможностей. Однако, это также означает, что стили будет намного сложнее интерпретировать. Сравните с CSS:
button {
background: #00f;
opacity: 0;
color: #000;
}
button.primary,
button.seconary {
color: #fff;
}
button.primary {
background: #f00;
}
button.secondary {
background: #0f0;
}
button.active {
opacity: 1;
}
В этом случае, CSS короче (229 символов против 222) и проще для понимания (субъективно). Более того, в CSS вы могли бы использовать препроцессор, чтобы получить еще более короткий и сгрупированный результат:
button {
background: #00f;
opacity: 0;
color: #000;
&.primary,
&.seconary {
color: #fff;
}
&.primary {
background: #f00;
}
&.secondary {
background: #0f0;
}
&.active {
opacity: 1;
}
}
Миф 6: Улучшается организация кода
Некоторые говорят о том, что им нравится styled-components, потому что появляется возможность размещать стили и скрипты в одном файле. Можно понять, что наличие множества файлов для одного компонента может показаться утомительным, но впихивание стилей и разметки в единый файл — это ужасно. Это не только системе контроля версий усложнит отслеживание изменений, но и приведет к бесконечному «скроллингу» на любом элементе посложнее простой кнопки.
Если же вам непременно нужно разместить CSS и JavaScript в одном и том же файле, попробуйте css-literal-loader. Последнее позволит вам собирать стили во время «build» посредством extract-text-webpack-plugin и использовать стандартную конфигурацию лоадера для обработки CSS.
Миф 7: «Developer Experience (DX) » становится прекрасным. Инструмент потрясающий!
Очевидно, что вы не использовали styled-components.
- Если что-то пошло не так со стилями, все приложение «падает» с длинной стековой трассировкой ошибки. Противоположность этому — CSS, где ошибка в стилях приведет просто к неправильному отображению элемента.
- У элементов отсутствуют различаемые className, поэтому при отладке придется бесконечно переключаться между React element tree и DevTools DOM tree.
- И хотя плагины для линтинга, подсветки кода, автозавершения кода, и другие подобные «прелести» уже существуют и для styled-components, они все еще могут быть недоступны для вашего IDE. Если вы работаете с финансами в правительственном агенстве, есть шансы, что Atom IDE будет недоступна.
Миф 8: Все становится «шустрее», все становится «легче»
- Как выяснилось, styled-components стили не могут быть экстрагированы в статический
CSS файл (например используя extract-text-webpack-plugin). Это значит, что браузер не сможет начать интерпретацию стилей до тех пор, пока styled-components не «распарсит» их и не добавит в DOM. - Совмещение стилей и скриптов в одном файле означает, что раздельное их кеширование невозможно.
- Природа styled-components такова, что все они обернуты в дополнительный HOС. А это ненужное понижение производительности. Такой же недостаток привел к прекращению поддержки react-css-modules и появлению babel-plugin-react-css-modules.
- Из-за того же HOC, серверный рендеринг приводит к значительно большему размеру разметки документа.
- Даже и не пробуйте анимировать компоненты используя динамические стили, а не keyframes.
Миф 9: Появляется возможность разработки «responsive» компонентов
Речь идет о способности стилизовать компонент на основе окружающей среды, например, размеров родительского контейнера, количества наследников и т. д.
Прежде всего, styled-components не имеют ничего общего с этим.
Минуточку, однако!
Большинство, если не все из этих проблем, могут быть решены в перспективе то ли сообществом, изменениями в React или в самой styled-components. Только зачем? CSS уже широко поддерживается, имеется солидное сообщество и… просто работает.
Но не нужно всегда избегать применения CSS-in-JavaScript или styled-components.
Есть кое-что, что делает styled-components хорошей библиотекой — это лучшая кросс-платформенная поддержка.
Просто не используйте styled-components исходя из ошибочных представлений.
Пара мнений от заинтересованных лиц
Talia Marcassa: Что мы нашли разочаровывающим в styled-components?
Применяя styled-components в нашем проекте мы обнаружили, что имеются некоторые стилевые правила, которые трудно внедрять в styled-components; например, правила, которые управляют размещением элементов на странице ( margins или display свойство). Это трудно поддавалось стандартизации, так что мы по-прежнему были вынуждены в значительной степени опереться на простой CSS для размещения компонентов в потоке элементов.
… хотя и были сложности в применении styled-components, библиотека помогла нам уменьшить кодовую базу.
Prometheus: В итоге что?
(комментарий к «Эволюция CSS: от CSS, SASS, BEM и CSS–модулей до styled-components»)
… Никакая эволюция CSS тут не значится, эволюционируют инструменты.
На мой взгляд, проблемы никакой нету, когда версткой занимается верстальщик, а программист — программированием.
А вот когда программисты занимаются версткой — вот тогда начинается весь этот зоопарк, который вместо ПРОСТОТЫ с дальнейшей поддержкой, дает лишнюю головную боль.
…
Пишите на чистом CSS, а инструментам отведите роль пространства имен и сборщика — тогда будет всем счастье…
И в заключение, слово автору:
Gajus Kuizinas: — Так что, все-таки, использовать?
- Еще слишком рано говорить о Shadow DOM, ввиду недостаточно глобальной поддержки.
- Используйте CSS с каким-либо соглашением об именовании (например BEM).
- Если вас волнует проблема коллизий имен классов или вы слишком ленивы, чтобы использовать BEM, используйте CSS Modules.
- Если вы работаете с React — рассмотрите возможность использования babel-plugin-react-css-modules.
- Если же вы работаете с React native, styled-components — это то, что надо.
HTML, CSS, JavaScript и PHP: что это такое и для чего?
Каждая из этих технологий имеет различное предназначение, цели и функции. Но бо́льшую ценность они представляют, когда работают вместе, а не по отдельности. Давайте теперь отдельно разберем каждую из этих технологий.HTML
HTML (Hypertext Markup Language) — это язык гипертекстовой разметки. Эта разметка создается с помощью тегов (то есть с помощью «меток») — наборов символов, входящие в угловатые скобки. Например, основной тег страницы html пишется следующим образом — <html>. Любая страница в интернете состоит из множества тегов. Конечно, это не то, что мы привыкли видеть, когда заходим в интернет. Каждый из этих тегов играет определенную важную роль.
Чтобы упростить задачу понимания этой технологии, давайте представим себе обычный дом. Увидев дом, мы видим его экстерьер, то есть то, из чего сделан дом. Теги на странице можно рассматривать как небольшие кирпичики, с помощью которых построен дом. Важно, чтобы эти кирпичи аккуратно и красиво были разложены, иначе дом будет криво смотреться, а может и вообще он будет непригоден для использования. Также и на страницах, при составлении структуры страницы важно уделить особое внимание тегам.
Рассмотрим общую структуру любой страницы в интернете:
Любая веб страница начинается с <!DOCTYPE html>. Этот тег дает браузеру понять, что далее представлен код html последней [пятой] версии.
Затем пишется парный тег <html></html>. Это основной тег страницы, который обязательно должен присутствовать и содержать в себе других 2 основных тега, это head и body.
Внутри парного тега <head></head> необходимо написать заголовок страницы (тег title), который отображается во вкладке браузера. Так же в контейнере <head></head> обычно находятся различные мета-теги для поисковых систем, подключение различных файлов к странице (например, стили) и т.д. В этой секции находится информация, которая важна для страницы, но не отображается на ней.
Внутри тега <body></body> находится всё, что должно быть на странице. Это любые из существующих тегов, текст, картинки, элементы работы с данными и так далее. Всё, что вы видите на страницах в интернете, всегда находится в теге body.
В приведенном выше примере в теге body находятся 2 элемента — тег h2 и тег p. Тег h2 обозначает заголовок на странице, а тег p — абзац. У каждого html тега есть свое предназначение. К тому же все элементы имеют стандартное форматирование браузера, это значит, что размер текста в заголовке по умолчанию будет больше, чем в абзаце. Из таких тегов и составляется страница, которую вы видите в браузере. Однако без графического оформления эти элементы совсем не презентабельные, именно поэтому нужен CSS.
CSS
CSS — Cascading Style Sheets — это каскадные таблицы стилей. С помощью разметки мы создали структуру и наполнение документа, а теперь будем внешне оформлять. Вот для этого и служат каскадные таблицы стилей. Чтобы здесь тоже упросить задачу с понятием CSS, вернемся к нашему примеру с домом. После постройки дома он выглядит совсем не презентабельно, поэтому, чтобы придать красивый вид, его раскрашивают. Подъезд покрашен в один цвет, балконы в другой и так далее. Это и есть графическое оформление. Так же и со страницей: без стилей элементы имеют только стандартное оформление браузера. Но с помощью стилей вы меняете на странице размер текста, его цвет, шрифт и так далее.
Вернемся к нашему примеру кода страницы html. Для тега h2 можно задать красный цвет текста следующим образом:
Как видите, ничего сложного в такой записи нет. Сначала мы указываем к чему нужно применить блок стилей. Далее в фигурных скобках мы описываем стили для этого элемента h2. В этом блоке мы можем задать любые из имеющихся стилей и все они применятся к элементу h2.
Теперь, разобравшись со стилем текста, давайте постараемся это все оживить. Тут нам придется прибегнуть к помощи JavaScript.
JavaScript
JavaScript — это язык программирования, сокращенно «JS». Изначально его создали для того, чтобы «оживить» веб-приложения и веб-сайты, то есть, чтобы элементы интерфейса (всплывающие окна, анимации, кнопки и т.д.) реагировали на действия пользователей. Однако сейчас этот язык программирования применяют не только для оживления страниц, но и на стороне сервера, для создания мобильных приложений, веб-сервисов и так далее.
Если вернуться к примеру с домом — то JavaScript это лифт, который доставляет пользователей на нужный этаж. Пользователь заходит в дом, ему нужно попасть на конкретный этаж, он нажимает на кнопку этажа и далее лифт автоматически доставляет пользователя на нужный этаж. Так же и на странице, пользователь нажимает на кнопку, а JavaScript выполняет нужное действие. Конечно, человек всегда может подняться по лестнице, так же как и сайт может работать без JavaScript, но, согласитесь, именно лифт делает дом лучше, так же как и JavaScript делает лучше веб-страницу.
PHP
Ну и последняя технология в этой связке — PHP. PHP (от англ. Hypertext Preprocessor) — это серверный язык программирования. Как мы уже отметили, если JavaScript работает на стороне клиента (браузера пользователя), то PHP — на стороне сервера (компьютер, где располагается сайт). PHP не зависит от скорости компьютера пользователя или его браузера, он полностью работает на сервере. PHP позволяет соединить все страницы в единое целое и предоставить сайту функции, без которых эти страницы не будут работать как единое целое: авторизоваться на сайте, подать заявку на бронирование, добавить товары в корзину и сделать заказ. PHP работает с базой данных, которая хранит всю динамическую (изменяющуюся) информацию на сайте.
Если вернуться к нашему примеру с домом, то PHP можно представить как водопроводную систему, электричество и т.д. То есть это то, что работает «под капотом» дома. Чтобы лифт работал, в доме нужно электричество. И это более важная составляющая дома, нежели лифт. Когда жилец дома тратит электричество, то все эти показания записываются в «базу данных» дома. Так же и с сайтом, когда пользователь нажимает на кнопку отправки заявки на бронирование, JavaScript отправляет данные на сервер, где PHP обрабатывает эту информацию и записывает в базу данных.
Умея работать с этими технологиями в связке, можно создавать любые сайты, от простых лендингов до огромных интернет-магазинов либо же сложных веб-сервисов с большим количеством данных. Спрос на такие технологии не падает, а это значит, что в ближайшие годы вы точно сможете хорошо зарабатывать, используя эти технологии.
Если вы еще только планируете изучение этих технологий, то рекомендуем рассмотреть обучение на нашем курсе «Веб-верстальщик», в котором подробно изучаются такие технологии, как HTML, CSS и JavaScript. Этих трех технологий вполне достаточно, чтобы создавать сайты. А при необходимости можно заняться освоением языка PHP, чтобы делать более мощные и большие сайты.
как это остановить — Веб-стандарты
Резюмируя: множество людей любят и JS и UX, CSS и т.д. Если мы перестанем раздавать ярлыки типа «JS-разработчик» или «UX-разработчик», то сможем добиться перемирия в текущей войне «JS против CSS».
Война реальнаСкопировать ссылку
Некоторые называют её «Великим расколом»: линия фронта реальна; с приверженцами JavaScript с одной стороны и людьми из лагеря UX и CSS, которые пропагандируют подход «без-JS» к интерфейсам, с другой стороны.
Фронтенд-разработчики боятся, что потеряют работу если не будут следовать за хайпом вокруг JS. И это вполне логично: проводится значительно меньше конференций и митапов по CSS по сравнению с JS, React и иже с ними. Например, в Нью-Йорке существует больше шести JS-митапов и ноль регулярных CSS-митапов.
С другой стороны мы видим, что простые статические сайты слишком перегружены только из-за синдрома упущенной выгоды.
Мы каждый день наблюдаем, как видные деятели фронтенд сообщества обвиняют друг друга. И это, мягко говоря, расстраивает.
Выйти за рамкиСкопировать ссылку
Воюющих часто разделяют на коалиции:
- JS-JS-JS: разработчики, создающие SPA с клиентской частью на каком-нибудь JavaScript-фреймворке, типа React, Vue.js и Angular. Они являются активными пользователями всяческих инструментов для сборки (Babel, Webpack и т.д.) и JS-библиотек.
- UX-разработчики, CSS-разработчики, HTML-JS-CSS-разработчики: разработчики, создающие статичные сайты на ванильном JavaScript и чистом CSS. Доступность и быстродействие — главные темы обсуждений внутри комьюнити.
Но существует ли этот раскол? Может этот дуализм основан только лишь на наших предрассудках?
На мой взгляд, эта предвзятость во многом обусловлена двумя вещами.
Во-первых, существует тренд разделять конференции по CSS и JS. Думаю, что это началось с очень популярного семейства ивентов JSConf и CSSConf и тенденции организации митапов Впиши-Свой-Город-Сюда.js. Западные платформы публикации контента поддерживают этот разлад: некоторые публикуют в основном статьи о React и JS в то время, как другие сфокусированы на CSS и UX.
Во-вторых, соцсети хороши в поляризации сообщества. Мы помещаем себя в пузырь единомышленников путём подписки на их фиды и ухудшаем ситуацию, делая перепосты только самых агрессивных мнений, приходящих с той стороны.
Современный веб невероятно сложен. Крайне сложно освоить все необходимые для работы веба технологии и никто по-настоящему не может назвать себя на 100% фулстэк-разработчиком. Но из-за искусственно увеличенного разрыва между ветками обсуждения JS и CSS с UX люди с разными, но не обязательно противоположными увлечениями, сталкиваются с чёрно-белым взглядом на мир «JS против CSS». Разработчики на React, которые увлекаются CSS-анимацией и a11y, получают ярлык «фанат JS». И CSS-разработчик, который любит Babel и CSS-in-JS с без рантайма, всё ещё будет носить звание CSS-парня или девчонки.
Люди, любящие обоихСкопировать ссылку
Как создатель PostCSS, я никогда не мог выбрать сторону даже если очень хотел этого. С одной стороны PostCSS это инструмент для CSS (что отражено в названии). С другой стороны PostCSS это инструмент сборки, написанный на JavaScript, а сборщики не особо в чести в современном сообществе CSS.
И я не одинок, есть ещё куча таких же людей: к примеру, создатель великолепных инструментов для анимации в React или создатель CSS-линтера доступности.
По правде говоря, каждый из нас знает лишь небольшое подмножество технологий. И чьи-то увлечения не обязаны лежать в одной области. Это нормально — любить и React и CSS одновременно. Или использовать сложную систему сборки чтобы быть уверенным, что твой продукт является доступным. Или может погрузиться в распределённые системы, чтобы сделать действительно классный UX в условиях отсутствия интернета.
Даже сами технологии не могут быть чёрно-белыми.
Сторонники «лагеря CSS» часто упоминают БЭМ как решение тех проблем, для которых создавался CSS-in-JS. Но не многие знают, что он, БЭМ, был спроектирован в Яндексе не как чисто CSS-технология. В него также входят JavaScript-фреймворк и изначально строился на ряде принципов, которые были позже использованы в React (например, вложенность маленьких изолированных компонентов).
Конфиги для ESLint, популярные в React-сообществе (по типу конфига AirBnB), содержат множество правил обеспечения доступности.
РешениеСкопировать ссылку
Я считаю, что война реальна. Я думаю, что мы можем остановить эту войну, перестав разделять разработчиков на категории чёрного и белого.
- Если ты любишь технологии с обеих «сторон»: рассказывай об этом! Вытащи это на свет, дай людям возможность начать цивилизованное обсуждение. Тебе нравятся современные JS-фреймворки, но также тебе нравится создавать статические сайты, которые рендерятся на сервере? Скажи об этом миру. Независимые разработчики будут создавать больше фреймворков для статических сайтов, если будут видеть необходимость в них.
- Давайте устроим публичный форум для обсуждений между мирами JS и CSS. Если вы организуете JavaScript-митап, то пусть в программе будет один доклад о CSS или UX. Пусть будут фронтенд-конференции вместо JS-конференций и CSS-конференций, где люди из разных лагерей смогут рассказать своим оппонентам о своих ежедневных проблемах и предпочитаемых решениях.
- Давайте пробовать технологии, пришедшие с другой стороны:
- Если вы CSS- или UX-разработчик, то начните с линтеров. Stylelint отличный CSS-линтер для начала знакомства.Он будет предупреждать вам об ошибках и позволит делиться лучшими практиками внутри команды. И вы можете запустить его как плагин в вашем любимом текстовом редакторе, поэтому вам даже не нужен какой-либо сборщик.
- Если вы React-разработчик — попробуйте ванильный JS на следующем лендинге или блоге. Это поможет лучше понять внутренности вашего фреймворка. А ваши юзеры скажут вам спасибо за более быструю загрузку за счёт более лёгкого бандла.
Что ещё почитатьСкопировать ссылку
Моя статья о будущем PostCSS, линтеров и CSS-in-JS из Марсианских хроник.
Статические файлы форм (класс Media) — Документация Django 1.6
Для генерации отзывчивых и удобных форм недостаточно простого HTML. Как минимум, нужен CSS, а современные виджеты нуждаются ещё и в JavaScript. Точная комбинация CSS и JavaScript зависит от виджетов, используемых на этой странице.
Именно здесь используются статические файлы формы. Django позволяет привязать различные файлы к форме и виджетам, которым они нужны. Например, если вы желаете использовать календарь для полей с датами, вы можете определить собственный виджет календаря. Этот виджет может требовать для своей работы CSS и JavaScript. При использовании этого виджета на форме, Django может определить необходимые .css и .js файлы и предоставить список имён этих файлов для их включения в код страницы.
Assets and Django Admin
Поставляемое с Django приложение интерфейса администратора определяет ряд собственных виджетов для календарей, отфильтрованных выборок и так далее. Эти виджеты имеют свои требования к ресурсам. Шаблоны приложения подключают соответствующие файлы, которые необходимы для работы виджетов на странице.
Если вам понравились виджеты интерфейса администратора, то используйте их в своих приложениях. Они все расположены в django.contrib.admin.widgets.
Определение статических файлов
Декларативное определение является самым простым способом определения ресурсов. Этот способ предполагает описание ресурса во внутреннем классе Media. Свойства внутреннего класса определяют требования к ресурсам.
Рассмотрим простой пример:
from django import forms class CalendarWidget(forms.TextInput): class Media: css = { 'all': ('pretty.css',) } js = ('animations.js', 'actions.js')
Этот код определяет CalendarWidget, который унаследован от TextInput. Каждый раз, при использовании CalendarWidget на форме, эта форма будет подгружать CSS из файла pretty.css и JavaScript из файлов animations.js и actions.js.
Такое статическое определение преобразуется во время выполнения в свойство media виджета. Ресурсы для экземпляра CalendarWidget могут быть получены через это свойство:
>>> w = CalendarWidget() >>> print(w.media) <link href="http://static.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> <script type="text/javascript" src="http://static.example.com/animations.js"></script> <script type="text/javascript" src="http://static.example.com/actions.js"></script>
Ниже приведён список всех возможных вариантов для Media. Ни один из них не является обязательным.
css
Словарь, описывающий CSS файлы, необходимые для различных устройств.
Значения словаря должны быть кортежами или списками имён файлов. Обратитесь к соответствующему разделу для получения информации о том, как определять пути до файлов с ресурсами.
Ключами словаря являются названия типов устройств отображения. Они идентичны типам, с которыми работает CSS: ‘all’, ‘aural’, ‘braille’, ‘embossed’, ‘handheld’, ‘print’, ‘projection’, ‘screen’, ‘tty’ и ‘tv’. Если вам нужны различные стили для разных типов устройств отображения, то укажите список CSS файлов для каждого типа устройств. Следующий пример определяет CSS для вывода на экран и принтер:
class Media: css = { 'screen': ('pretty.css',), 'print': ('newspaper.css',) }
Если набор CSS файлов подходит для нескольких устройств отображения, то ключ словаря может быть списком типов нескольких устройств с запятой в качестве разделителя. В следующем примере, телевизор и проектор имеют одинаковые требования к ресурсам:
class Media: css = { 'screen': ('pretty.css',), 'tv,projector': ('lo_res.css',), 'print': ('newspaper.css',) }
Вышеприведённое определение стилей будет преобразовано в следующий код:
<link href="http://static.example.com/pretty.css" type="text/css" media="screen" rel="stylesheet" /> <link href="http://static.example.com/lo_res.css" type="text/css" media="tv,projector" rel="stylesheet" /> <link href="http://static.example.com/newspaper.css" type="text/css" media="print" rel="stylesheet" />
js
Кортеж, описывающий необходимые JavaScript файлы. Обратитесь к соответствующему разделу для получения информации о правилах определения путей до файлов ресурсов.
extend
Булево значение, определяющее производится ли наследование Media базового класса.
По умолчанию, любой объект, использующий Media, будет наследовать все ресурсы от базового класса. Это будет происходить вне зависимости от того, как базовый класс определяет свои зависимости от ресурсов. Пример, расширения функционала нашего простого календаря:
>>> class FancyCalendarWidget(CalendarWidget): ... class Media: ... css = { ... 'all': ('fancy.css',) ... } ... js = ('whizbang.js',) >>> w = FancyCalendarWidget() >>> print(w.media) <link href="http://static.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> <link href="http://static.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" /> <script type="text/javascript" src="http://static.example.com/animations.js"></script> <script type="text/javascript" src="http://static.example.com/actions.js"></script> <script type="text/javascript" src="http://static.example.com/whizbang.js"></script>
Виджет FancyCalendar наследует все ресурсы от базового виджета. Если такое поведение вам не подходит, то добавьте extend=False к Media:
>>> class FancyCalendarWidget(CalendarWidget): ... class Media: ... extend = False ... css = { ... 'all': ('fancy.css',) ... } ... js = ('whizbang.js',) >>> w = FancyCalendarWidget() >>> print(w.media) <link href="http://static.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" /> <script type="text/javascript" src="http://static.example.com/whizbang.js"></script>
Если вам требуется больше контроля над наследованием ресурсов, то ресурсы следует определять с помощью динамических свойств. Динамическое свойства обеспечивают полный контроль над процессом наследования ресурсов.
Определение путей до ресурсов
Пути, используемые для определения ресурсов, могут быть как относительными, так и абсолютными. Если путь начинается с ‘/’, ‘http://‘ или ‘https://‘, то он будет интерпретирован как абсолютный и оставлен в неизменном виде. Все остальные пути будут дополнены соответствующим префиксом.
Как часть приложения staticfiles добавлены два новых параметра конфигурации, которые относятся к «статическим файлам» (изображения, CSS, Javascript и т.д.), необходимым для отображения полной страницы: STATIC_URL и STATIC_ROOT.
Для того, чтобы найти правильный префикс, Django проверит параметр STATIC_URL на равенство с None и, если это так, то автоматически воспользуется параметром MEDIA_URL. Например, если параметр MEDIA_URL для сайта имеет значение ‘http://uploads.example.com/’, а параметр STATIC_URL равен None:
>>> from django import forms >>> class CalendarWidget(forms.TextInput): ... class Media: ... css = { ... 'all': ('/css/pretty.css',), ... } ... js = ('animations.js', 'http://othersite.com/actions.js') >>> w = CalendarWidget() >>> print(w.media) <link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" /> <script type="text/javascript" src="http://uploads.example.com/animations.js"></script> <script type="text/javascript" src="http://othersite.com/actions.js"></script>
Но если параметр STATIC_URL равен ‘http://static.example.com/’:
>>> w = CalendarWidget() >>> print(w.media) <link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" /> <script type="text/javascript" src="http://static.example.com/animations.js"></script> <script type="text/javascript" src="http://othersite.com/actions.js"></script>
Стилизация компонентов Next.js с помощью CSS
Как мы стилизуем компоненты React в Next.js?
У нас есть большая свобода, потому что мы можем использовать любую библиотеку, которую предпочитаем.
Но Next.js поставляется сstyled-jsx
встроенный, потому что это библиотека, созданная теми же людьми, которые работают над Next.js.
И это довольно классная библиотека, которая предоставляет нам CSS с ограниченным объемом, который отлично подходит для удобства сопровождения, потому что CSS влияет только на компонент, к которому он применяется.
Я думаю, что это отличный подход к написанию CSS, без необходимости применять дополнительные библиотеки или препроцессоры, которые добавляют сложности.
Чтобы добавить CSS в компонент React в Next.js, мы вставляем его во фрагмент в JSX, который начинается с
и заканчивается
Внутри этих странных блоков мы пишем простой CSS, как в.css
файл:
<style jsx>{`
h2 {
font-size: 3rem;
}
`}</style>
Вы пишете это внутри JSX, вот так:
const Index = () => (
<div>
<h2>Home page</h2>
<span><</span><span>style</span> <span>jsx</span><span>></span>{<span>`
h2 {
font-size: 3rem;
}
`}</style>
</div>
)
export default Index
Внутри блока мы можем использовать интерполяцию для динамического изменения значений. Например, здесь мы предполагаемsize
prop передается родительским компонентом, и мы используем его вstyled-jsx
блокировать:
const Index = props => (
<div>
<h2>Home page</h2>
<span><</span><span>style</span> <span>jsx</span><span>></span>{<span>`
h2 {
font-size: ${props.size}rem;
}
`}</style>
</div>
)
Если вы хотите применить некоторый CSS глобально, а не в области действия компонента, вы добавляетеglobal
ключевое слово вstyle
тег:
<style jsx global>{`
body {
margin: 0;
}
`}</style>
Если вы хотите импортировать внешний файл CSS в компонент Next.js, вам необходимо сначала установить@zeit/next-css
:
npm install @zeit/next-css
а затем создайте файл конфигурации в корне проекта с именемnext.config.js
, с этим содержанием:
const withCSS = require('@zeit/next-css')
module.exports = withCSS()
После перезапуска приложения Next вы можете импортировать CSS, как обычно, с библиотеками или компонентами JavaScript:
Вы также можете напрямую импортировать файл SASS, используя@zeit/next-sass
библиотека вместо этого.
Больше следующих руководств:
Как увеличить производительность CSS-in-JS в 175 раз
Мне нравится удобство CSS-in-JS, особенно возможность совместного расположения стилей, но в некоторых деталях я не уверен:
- В том, что обязательно нужно использовать хешированные классы вместо классов пространств имён. А представьте, как может раздражать их присутствие в сторонних компонентах!
- В том, что применение логики в CSS всегда лучше или более удобно для восприятия человеком. А также это даёт мощный рост производительности (подробнее об этом ниже).
- И наконец, в том, что добавлять 25–40 Кбайт минифицированного кода JavaScript к npm-компоненту размером в 10 Кбайт — это хорошая идея.
Поначалу всё хорошо и беззаботно и никаких проблем с производительностью этих CSS-решений с «невероятно быстрым» временем выполнения не замечается. Но это до тех пор, пока вы не поместите всех их на одной странице в Storybook.
Обратимся к вездесущему компоненту Button
, имеющему различные стили и параметры:
У нас там было множество простых и быстрых функций для создания стилей. Мы даже оптимизировали статический css, выделив его в самостоятельный фрагмент (sharedStaticButtonStyles
):
В компоненте Button
были самые динамические вызовы функций и наибольшее число элементов в Storybook
. Посмотрим, как он выполняет загрузку:
Около 36 секунд ушло у Emotion
на выполнение парсинга (см. подчёркнутое красным). Инструмент производительности Performance делает это примерно в 2–3 раза быстрее, но всё равно это слишком долго.
Дальше всё только медленнее
Сначала я думал, что проблема в компоненте Tooltip
(всплывающая подсказка): может быть, это он так медленно отображается? А затем понял, что это происходит, только когда он прикреплён к Button
. Стало быть, Emotion
при наведении курсора снова выполняет парсинг CSS (потому что Tooltip
вызывает повторное отображение) и приостанавливает основной поток примерно на 900 миллисекунд, прежде чем появится всплывающая подсказка!
Вы можете подумать: «Ну мои компоненты не такие сложные и медленные». Даже если они в два раза быстрее в крупном приложении с большим количеством компонентов на странице, тратить 1–2 лишних секунды на загрузку, пока выполняется парсинг CSS, недопустимо. Особенно в высокодинамичных приложениях, получающих большое количество обновлений в секунду. В них Emotion
выполняет повторный парсинг при каждом отображении (как это происходит при наведении курсора), что обусловлено динамической природой стилевого оформления с использованием пропсов.
Как же сделать всё быстрым?
Во-первых, если вы начинаете новый проект, стоит подумать о CSS-in-JS решениях времени компиляции: таком или таком.
Если речи о новом проекте не идёт, можно увеличить производительность уже имеющегося стилевого оформления до 175 раз, сделав CSS более статичным.
Уже написано несколько статей о том, как использование пропсов при тематическом оформлении засоряет приложение специальными обёртками.
Поэтому если бы я начинал новый проект, то для тематического оформления вместо пропсов использовал бы CSS-переменные.
Но узкое место производительности не в этом
А в тех вызовах вложенных функций в css, которые принимают вдобавок к теме ещё и пропсы:
Я не рассматривал подробно CSS-код во время выполнения, но мне кажется, что при вызове функция фактически заявляет: «Я не знаю, что она вернёт, так что буду пересчитывать её при каждом отображении».
На помощь приходят атрибуты данных и CSS-переменные
Давайте поменяем то, как мы делаем этот компонент Button
:
Нас здесь интересует использование CSS-переменных, позволяющее резко сократить объём статического CSS, который необходимо написать.
В ходе выполнения рефакторинга старые функции для получения цветов и размеров были сохранены и перемещены из Emotion
CSS в CSS-переменные почти 1 к 1:
Эта функция выполняется в первый раз примерно за 0,002 миллисекунды. Посмотрим, как теперь выглядит CSS компонента Button
:
Помните, на парсинг уходило 36 секунд? Посмотрим, что сейчас:
А теперь парсинг CSS выполняется чуть больше чем за 200 миллисекунд. В то время как Performance делал это всего в 2–3 раза быстрее (т. е. за 12–18 секунд).
Подведём итоги:
- В новых проектах используйте CSS времени компиляции.
- Для тематического оформления задействуйте в новых проектах CSS-переменные.
- Делайте CSS как можно более статичным для вариаций (это самая важная оптимизация).
Читайте также:
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Dominic Tobias: How to increase CSS-in-JS performance by 175x
Используйте js, HTML, css для реализации простых часов с указателем
Используйте js, HTML, css, чтобы реализовать простые часы-указатели, как показано на рисунке:
HTML-код:
<div>
<ul></ul>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
css код:
#box {
width: 200px;
height: 200px;
border: 1px solid #000000;
border-radius:50% ;
margin: 50px auto;
position: relative;
}
#list{
position: relative;
height: 100%;
margin: 0;
padding: 0;
list-style: none;
}
#list li{
width: 1px;
height: 5px;
background: #000000;
position: absolute;
top: 0;
left: 100px;
transform-origin:center 100px;
}
#list li:nth-of-type(5n+1){
width: 2px;
height: 10px;
}
#ico,#hour,#min,#sec{
position: absolute;
background: black;
}
#ico{
width: 10px;
height: 10px;
border-radius: 50%;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
#hour{
height: 50px;
width: 5px;
left: 98px;
top: 49px;
transform-origin:bottom ;
}
#min{
height: 60px;
width: 3px;
background: blue;
top: 39px;
left: 99px;
transform-origin: bottom;
}
#sec{
height: 80px;
width: 1px;
background: red;
top: 19px;
left: 100px;
transform-origin: bottom;
}
js код:
window.onload = function(){
let list = document.getElementById('list');
let hour = document.getElementById('hour');
let min = document.getElementById('min');
let sec = document.getElementById('sec');
let ico = document.getElementById('ico');
let css = document.getElementById('css');
let lis = '';
for(let i=0;i<60;i++){
lis += '<li><li>';
css.innerHTML += "#list li:nth-of-type("+(i+1)+"){transform:rotate("+i*6+"deg)}"
}
list.innerHTML = lis;
time();
setInterval(time,1000);
function time(){
let data = new Date();
let s = data.getSeconds();
let m = data.getMinutes()+s/60;
let h = data.getHours()+m/60;
hour.style.transform = "rotate("+h*30+"deg)";
min.style.transform = "rotate("+m*6+"deg)";
sec.style.transform = "rotate("+s*6+"deg)";
}
}
html — Как вы читаете значения правил CSS с помощью JavaScript?
На основе ответа @dude это должно возвращать соответствующие стили в объекте, например:
.recurly-input {
дисплей: блок;
радиус границы: 2 пикселя;
-webkit-border-radius: 2 пикселя;
наброски: 0;
тень коробки: нет;
граница: 1px solid # beb7b3;
отступ: 0.6em;
цвет фона: # f7f7f7;
ширина: 100%;
}
Это вернет:
фон Цвет:
"RGB (247, 247, 247)"
граница
:
"1px сплошной RGB (190, 183, 179)"
borderBottom
:
"1px сплошной RGB (190, 183, 179)"
borderBottomColor
:
"RGB (190, 183, 179)"
borderBottomLeftRadius
:
"2px"
borderBottomRightRadius
:
"2px"
borderBottomStyle
:
"твердый"
borderBottomWidth
:
«1px»
цвет границы
:
"RGB (190, 183, 179)"
borderLeft
:
"1px сплошной RGB (190, 183, 179)"
borderLeftColor
:
"RGB (190, 183, 179)"
borderLeftStyle
:
"твердый"
borderLeftWidth
:
"1px"
borderRadius
:
"2px"
граница
:
"1px сплошной RGB (190, 183, 179)"
borderRightColor
:
"RGB (190, 183, 179)"
borderRightStyle
:
"твердый"
borderRightWidth
:
"1px"
borderStyle
:
"твердый"
граница
:
"1px сплошной RGB (190, 183, 179)"
borderTopColor
:
"RGB (190, 183, 179)"
borderTopLeftRadius
:
"2px"
borderTopRightRadius
:
"2px"
borderTopStyle
:
"твердый"
borderTopWidth
:
«1px»
ширина рамки
:
«1px»
boxShadow
:
"никто"
отображать
:
"блокировать"
контур
:
"0px"
outlineWidth
:
"0px"
набивка
:
«0.6em "
paddingBottom
:
"0.6em"
paddingLeft
:
"0.6em"
paddingRight
:
"0.6em"
paddingTop
:
"0.6em"
ширина
:
«100%»
Код:
function getStyle (className_) {
var styleSheets = window.document.styleSheets;
var styleSheetsLength = styleSheets.length;
for (var i = 0; i
<стиль глобального jsx> {`
тело {
фон: черный;
}
`}