Main css: Тег | htmlbook.ru

Содержание

Почему не найден main.css? — CodeRoad



Примечание: Я использую Jekyll

Я пытался связать внешнюю таблицу стилей, но она не находит файл (это main.css)so), я снова попытался проверить его путь и имя, и это все равно не сработало. Вы не могли бы мне помочь?

Здесь вы можете увидеть изображение моей папки и мой код:

html css external
Поделиться Источник Pier     30 декабря 2017 в 23:26

2 ответа




1

Попробуйте добавить type="text/css" к вашему <link> :

<link href="_layouts/main.css" type="text/css" rel="stylesheet">

Поделиться Chesswithsean     31 декабря 2017 в 00:01



0

Ваши структуры папок, похоже, используют jekyll , если да! тогда нужно менять название папке

_layouts вспять папку для макета в jekyll

Поделиться PratapRockerss     31 декабря 2017 в 00:26


Похожие вопросы:


`play dist», » main. css » возвращает 404

Создайте новый образец приложения play2: play new test Затем: cd test play run Посетите http://localhost:9000 , мы увидим, что домашняя страница по умолчанию отображается правильно. Но когда я его…


Symfony 3 — {{asset(‘assets/css/main.css’)}} не работает

привязка файла CSS должна быть простой в symfony 3 в соответствии с каждым учебником и документацией. Но в моем случае это просто не работает. В моем base.html.twig году у меня есть <link…


yeoman, SCSS, bower server, styles/main.css не найден

Я хотел сегодня попробовать scss поддержку yeoman. Я следовал процедуре : $ йо angular включить Twitter Bootstrap? Да , используйте SCSS-ю версию Twitter Bootstrap с Compass CSS Authoring Framework?…


Ссылка на файл main.css в index.html указывает на файл main.scss

В моем файле index.html у меня есть вот это: <link rel=stylesheet href=styles/main.css> Когда я смотрю на путь styles/, я вижу там файл main. scss. Почему вышеприведенная ссылка на main.css…


Играй! 2.3.1 — main.css 404 (государственные активы не маршрутизируются?)

Я только что загрузил семя Play Java из UI, чтобы создать новое приложение. Я написал некоторый код CSS в public/stylesheets/main.css , и это единственное изменение, которое я внес в этот проект….


CSS код в HTML и main.css

Есть идеи, почему этот код CSS не работает, когда я помещаю его в файл main.css? Я пытаюсь сделать полноэкранный фон. <html> <head> <link rel=stylesheet type=text/css…


Webpack css-loader: «модуль не найден: ошибка: не удается разрешить ‘main.css’ in …»

Я пытаюсь включить свой css в сервер, размещенный webpack-dev-server. Чтобы это произошло, я, по-видимому,должен использовать style-loader и css-loader вместе, чтобы bundle css в JavaScript. Я не…


<link rel=»stylesheet» type=»text/css» href=»main.css»/> не получилось

Я понятия не имею, почему это не работает. <!DOCTYPE html> <html lang=en> <head> <meta charset=UTF-8> <title>Title</title> <link rel=stylesheet type=text/css…


main.css файл не загружается

Вступление У меня есть два домена, http://mauricevandorst.com/ и http://tacticalmotion.nl/ . Чего я хочу Я хочу, чтобы сайт https://mauricevandorst.com/personal-page/index.html был таким же сайтом,…


Jekyll блог-сайт на git хабе — правки, внесенные в main.css, не будут применяться к файлам markdown

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

Изоляция CSS в ASP.NET Core Blazor

  • Чтение занимает 2 мин

В этой статье

Автор: Дейв Брок (Dave Brock)

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

Включение изоляции CSS

Чтобы определить стили, относящиеся к компоненту, создайте файл .razor.css, соответствующий имени файла .razor для компонента в той же папке. Этот файл .razor.css будет файлом CSS с назначенной областью.

Для компонента Example в файле Example.razor создайте файл рядом с компонентом с именем Example.razor.css. Файл Example.razor.css должен находиться в той же папке, что и компонент Example (Example.razor). В базовом имени Example файла регистр не учитывается.

Pages/Example.razor:

@page "/example"

<h2>Scoped CSS Example</h2>

Pages/Example.razor.css:

h2 { 
    color: brown;
    font-family: Tahoma, Geneva, Verdana, sans-serif;
}

Стили, определенные в файле Example.razor. css, применяются только к отображаемым выходным данным компонента Example. Изоляция CSS применяется к элементам HTML в соответствующем файле Razor. Все объявления CSS h2, определенные в других областях приложения, не будут конфликтовать со стилями компонента Example.

Примечание

Чтобы обеспечить изоляцию стиля при выполнении объединения, импорт CSS в блоки кода Razor не поддерживается.

Объединение изоляций CSS

Изоляция CSS выполняется во время сборки. Blazor переписывает селекторы CSS в соответствии с разметкой, отображаемой компонентом. Переписанные стили CSS объединяются и создаются как статический ресурс. Ссылка на таблицу стилей содержится в теге <head> wwwroot/index.html (Blazor WebAssembly) или

Pages/_Host.cshtml (Blazor Server). Следующий элемент <link> добавляется по умолчанию в приложение, созданное из шаблонов проектов Blazor, где заполнитель {ASSEMBLY NAME} является именем сборки проекта:

<link href="{ASSEMBLY NAME}. styles.css" rel="stylesheet">

Следующий пример взят из размещенного приложения Blazor WebAssembly Client . Имя сборки приложения — BlazorSample.Client. <link> добавляется шаблоном проекта Blazor WebAssembly при создании проекта с вариантом размещения (параметр -ho|--hosted в .NET CLI или параметр ASP.NET Core hosted (С размещением в ASP.NET Core) в Visual Studio):

<link href="BlazorSample.Client.styles.css" rel="stylesheet">

В объединенном файле каждый компонент связан с идентификатором области. Для каждого компонента, имеющего стиль, атрибут HTML добавляется в формате

b-<10-character-string>. Идентификатор уникален и отличается для каждого приложения. В отображаемом компоненте Counter Blazor добавляет идентификатор области к элементу h2:

<h2 b-3xxtam6d07>

Файл {ASSEMBLY NAME}. styles.css использует идентификатор области для группирования объявления стиля с его компонентом. В следующем примере представлен стиль для предыдущего элемента <h2>:

/* /Pages/Counter.razor.rz.scp.css */
h2[b-3xxtam6d07] {
    color: brown;
}

Во время сборки создается пакет проектов с использованием соглашения {STATIC WEB ASSETS BASE PATH}/Project.lib.scp.css, где заполнитель

{STATIC WEB ASSETS BASE PATH} является базовым путем к статическим веб-ресурсам.

Если используются другие проекты, такие как пакеты NuGet или библиотеки классов Razor, то объединенный файл:

  • ссылается на стили с помощью импорта CSS;
  • не публикуется как статический веб-ресурс приложения, использующего стили.

Поддержка дочерних компонентов

По умолчанию изоляция CSS применяется только к компоненту, привязанному с помощью формата {COMPONENT NAME}.razor.css, где заполнитель {COMPONENT NAME} обычно является именем компонента. Чтобы применить изменения к дочернему компоненту, используйте объединение ::deep для всех элементов-потомков в файле .razor.css родительского компонента. Объединение ::deep выбирает элементы, которые являются потомками идентификатора области, созданного элементом.

В следующем примере показан родительский компонент с именем Parent и дочерний компонент с именем Child.

Pages/Parent.razor:

@page "/parent"

<div>
    <h2>Parent component</h2>

    <Child />
</div>

Shared/Child.razor:

<h2>Child Component</h2>

Измените объявление h2 в Parent.razor.css, добавив объединение ::deep для указания того, что объявление стиля h2 должно применяться к родительскому компоненту и его дочерним элементам.

Pages/Parent.razor.css:

::deep h2 { 
    color: red;
}

Стиль h2 теперь применяется к компонентам Parent и Child без необходимости создания отдельного CSS-файла с областью действия для дочернего компонента.

Объединение ::deep работает только с элементами-потомками. Следующая разметка должным образом применяет стили h2 к компонентам. Идентификатор области родительского компонента применяется к элементу div, поэтому браузеру известно, что нужно наследовать стили от родительского компонента.

Pages/Parent.razor:

<div>
    <h2>Parent</h2>

    <Child />
</div>

При этом исключение элемента div удаляет отношение потомков. В следующем примере стиль не применяется к дочернему компоненту.

Pages/Parent.razor:

<h2>Parent</h2>

<Child />

Поддержка препроцессоров CSS

Препроцессоры CSS полезны для улучшения разработки CSS с помощью таких функций, как переменные, вложенность, модули, примеси и наследование. Хотя изоляция CSS изначально не поддерживает препроцессоры CSS, такие как Sass и Less, интеграция препроцессоров CSS происходит прозрачно, поскольку компиляция препроцессора выполняется до того, как Blazor перезаписывает селекторы CSS в процессе сборки. С помощью Visual Studio, например, настройте существующую компиляцию препроцессора в качестве задачи перед сборкой в диспетчере выполнения задач Visual Studio.

Многие сторонние пакеты NuGet, такие как Delegate.SassBuilder, могут компилировать файлы SASS и SCSS в начале процесса сборки перед выполнением изоляции CSS, и дополнительная настройка не требуется.

Конфигурация изоляции CSS

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

Настройка формата идентификатора области

По умолчанию для идентификаторов областей используется формат b-<10-character-string>. Чтобы настроить формат идентификатора области, измените шаблон в файле проекта:

<ItemGroup>
  <None Update="Pages/Example.razor.css" CssScope="my-custom-scope-identifier" />
</ItemGroup>

В предыдущем примере CSS, сформированный для Example. razor.css, изменяет свой идентификатор области с b-<10-character-string> на my-custom-scope-identifier.

Используйте идентификаторы областей, чтобы обеспечить наследование файлов CSS с назначенной областью. В следующем примере файла проекта файл BaseComponent.razor.css содержит общие стили для компонентов. Файл DerivedComponent.razor.css наследует эти стили.

<ItemGroup>
  <None Update="Pages/BaseComponent.razor.css" CssScope="my-custom-scope-identifier" />
  <None Update="Pages/DerivedComponent.razor.css" CssScope="my-custom-scope-identifier" />
</ItemGroup>

Используйте оператор подстановочного знака (*), чтобы предоставить идентификаторы областей для нескольких файлов:

<ItemGroup>
  <None Update="Pages/*.razor.css" CssScope="my-custom-scope-identifier" />
</ItemGroup>

Изменение базового пути для статических веб-ресурсов

Файл scoped. styles.css создается в корне приложения. Чтобы изменить путь по умолчанию, используйте свойство StaticWebAssetBasePath в файле проекта. В следующем примере файл scoped.styles.css и остальные ресурсы приложения размещаются по пути _content:

<PropertyGroup>
  <StaticWebAssetBasePath>_content/$(PackageId)</StaticWebAssetBasePath>
</PropertyGroup>

Отключение автоматического объединения

Чтобы отказаться от того, как Blazor публикует и загружает файлы с заданной областью во время выполнения, используйте свойство DisableScopedCssBundling. При использовании этого свойства за получение изолированных файлов CSS из каталога obj и их публикацию и загрузку во время выполнения отвечают другие средства или процессы:

<PropertyGroup>
  <DisableScopedCssBundling>true</DisableScopedCssBundling>
</PropertyGroup>

Поддержка библиотеки классов Razor (RCL)

Когда библиотека классов Razor (RCL) предоставляет изолированные стили, атрибут href тега <link> указывает на {STATIC WEB ASSET BASE PATH}/{ASSEMBLY NAME}. bundle.scp.css со следующими заполнителями:

  • {STATIC WEB ASSET BASE PATH}: базовый путь к статическому веб-ресурсу.
  • {ASSEMBLY NAME}: имя сборки библиотеки классов.

В следующем примере:

  • Базовый путь к статическому веб-ресурсу — _content/ClassLib.
  • Имя сборки библиотеки классов — ClassLib.

wwwroot/index.html (Blazor WebAssembly) или Pages_Host.cshtml (Blazor Server):

<link href="_content/ClassLib/ClassLib.bundle.scp.css" rel="stylesheet">

Дополнительные сведения о RCL и библиотеках классов Razor см. в следующих статьях:

Как на самом деле работает position: sticky в CSS — Веб-стандарты

У position: sticky уже очень неплохая браузерная поддержка, но большинство разработчиков так и не используют это свойство.

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

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

Я полагаю, что вы хорошо знакомы с позиционированием в CSS, но давайте кратко повторим основные моменты:

Ещё три года назад существовало четыре типа позиционирования: static, relative, absolute и fixed.

Основное различие между static и relative, absolute и fixed в том, какое место они занимают в потоке документа (DOM). Элементы с позицией static и relative сохраняют своё естественное положение в потоке документа, в то время как absolute и fixed «вырываются» из потока документа и становятся плавающими.

Новое значение sticky похоже на все предыдущие значения сразу. Я проиллюстрирую это чуть позже.

Моё первое знакомство с «липким» позиционированиемСкопировать ссылку

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

При первом знакомстве с position: sticky все быстро понимают, что элемент залипает, когда область просмотра достигает определённой позиции.

Пример:

.some-component {
    position: sticky;
    top: 0;
}

Проблема в том, что иногда это работает, а иногда нет. Когда всё работает, то элемент и правда залипает. Но когда не работает, то при прокрутке элемент перестаёт залипать. Как человеку, который живёт одним только CSS, мне было важно разобраться в сути проблемы. Именно поэтому я решил тщательно изучить «липкое» позиционирование.

«Липкая» разведкаСкопировать ссылку

Во время своих экспериментов я заметил, что если элемент с position: sticky является единственным ребёнком своего родителя-обёртки, то этот «липкий» элемент не залипает.

<!-- НЕ РАБОТАЕТ!!! -->
<style>
    . sticky {
        position: sticky;
        top: 0;
    }
</style>

<div>
    <div>
        Некий контент
    </div>
</div>

Когда я добавлял больше элементов внутрь родителя-обёртки всё начинало работать как ожидалось.

Почему так происходит?

Причина кроется в том, что элемент с position: sticky может перемещаться только в пределах контейнера, в котором находится. А поскольку в моём случае он был единственным ребёнком, у него не было элементов-братьев, поверх которых он мог перемещаться.

Как на самом деле работает position: sticky в CSSСкопировать ссылку

«Липкое» позиционирование состоит из двух основных частей: «липкого» элемента и «липкого» контейнера.

«Липкий» элемент — это элемент, которому мы задали position: sticky. Элемент будет становиться плавающим, как только область видимости достигнет определённой позиции, например top: 0px.

Пример:

.some-component {
    position: sticky;
    top: 0px;
}

«Липкий» контейнер — это HTML-элемент, который оборачивает «липкий» элемент. Это максимальная область, в которой может перемещаться наш элемент.

Когда вы задаёте элементу position: sticky, его родитель автоматически становится «липким» контейнером! Очень важно это запомнить! Контейнер будет являться областью видимости для элемента. «Липкий» элемент не может выйти за пределы своего «липкого» контейнера.

В этом причина, почему в предыдущем примере «липкий» элемент не залипал: он был единственным дочерним элементом контейнера.

Наглядный пример:

Пример на CodePen.

Понимание «липкого» поведенияСкопировать ссылку

Как я и говорил, position: sticky ведёт себя не так, как другие типы позиционирования. Но, с другой стороны, у них есть определённые сходства. Позвольте мне пояснить:

Относительное (или статичное) — «липкий» элемент похож на элемент со статическим или относительным позиционированием поскольку сохраняет свою естественную позицию в DOM (остаётся в потоке). Фиксированное — когда элемент залипает, то ведёт себя как будто у него заданы стили position: fixed, остаётся на той же позиции в области видимости и вырывается из потока документа. Абсолютное — в конце доступной для перемещений области элемент останавливается и остаётся поверх другого элемента. Точно также, как ведёт себя абсолютно спозиционированный элемент в контейнере с position: relative.

Залипает внизу?!Скопировать ссылку

В большинстве случаев вы будете использовать position: sticky чтобы прикрепить элемент к верхнему краю страницы. Что-то вроде этого:

.component {
    position: sticky;
    top: 0;
}

Именно для таких сценариев и был создан этот тип позиционирования. До его появления такой трюк приходилось проворачивать с помощью JavaScript.

Но вы с тем же успехом можете использовать это свойство для того, чтобы прилепить элемент к нижней границе. Это значит, что футеру можно задать «липкое» позиционирование и при скролле он всегда будет залипать у нижнего края. И когда мы дойдём до конца «липкого» контейнера наш элемент остановится на своей естественной позиции. Лучше использовать эту особенность для элементов, находящихся в самом конце контейнера.

Полный пример:

HTML

<main>
    <header>HEADER</header>
    <div>MAIN CONTENT</div>
    <footer>FOOTER</footer>
</main>

CSS

.main-footer {
    position: sticky;
    bottom: 0;
}
Пример на CodePen.

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

Браузерная поддержкаСкопировать ссылку

  • «Липкое» позиционирование поддерживается всеми основными современными браузерами. Исключение: старый-добрый IE.
  • Для Safari потребуется префикс -webkit
position: -webkit-sticky; /* Safari */
position: sticky;
Более 86% браузеров поддерживает sticky по данным Can I Use.

В заключенииСкопировать ссылку

Вот и всё. Я надеюсь, что вам понравилась эта статья и мне удалось поделиться своим опытом. Я буду признателен, если вы поделитесь этим постом и поаплодируйте.

Другие мои посты о CSSСкопировать ссылку

Учебник CSS — Урок 1 — подключаем CSS-стили

Я не буду объяснять зачем нужен CSS. Если вы открыли этот учебник значит вы желаете его выучить. От себя лишь скажу, что возможности CSS очень широки и позволяют верстать макеты любой сложности. В свою очередь использование css означает, что вам придется отказаться от использования различных атрибутов тегов size, color, bgcolor, align и других, которые будут «мешать» CSS.

Существует по крайней мере три способа подключения CSS к вашему HTML файлу. Давайте рассмотрим самый простой, потом второй и правильный способ.

CSS внутри тега

CSS можно подключить c помощью атрибута style:

<div>
  Блок
</div>

Так мы задаем блок размером 200 на 100 пикселей. Давайте рассмотрим как пишется CSS. Сначала мы пишем атрибут. И потом уже в ковычках пишем css-стили.

style="параметр:значение;параметр:значение;параметр:значение"

Пишем стили мы так сначала идет параметр (widht, height и другие), потом идет двоеточие и значение параметра. Разделяем каждый параметр точкой с запятой.

Теперь ко второму способу написания CSS.

CSS в начале HTML-документа

Для этого мы используем тег <style></style> в котором мы пишем CSS-код.

<html>
 <head>
  <title>Учебник CSS</title>
  <style type="text/css">
  здесь мы будем писать css-код
  </style>
 </head>
 <body>
  <p>Учите CSS вместе с drupalbook.org</p>
 </body>
</html>

Тег style мы пишем в теге <head></head> после тега <title>. Давайте напишем какой-нибудь CSS-код:

<html>
 <head>
  <title>Учебник CSS</title>
  <style type="text/css">
   body{
     background: #eeeeee; /* фон страницы */     font-size: 14px;            /* размер шрифта */
   }
   p{
     color: #ff0000; /* цвет текста */
   }
  </style>
 </head>
 <body>
  <p>Учите CSS вместе с drupalbook.org</p>
  <p>2 строка учите CSS вместе с drupalbook.org</p>
 </body>
</html>

Давайте посмотрим как пишется css для тегов. Если мы пишем название тега в css, то для всех этих тегов будут применены параметры CSS. Так например если мы пишем p то значит для всех параграфов будет выбраны следующие параметры.

Когда мы пишем CSS-код, то сначала мы указываем тег для которого применяем css-стили, дальше мы в фигурных скобках пишем css-стили. CSS-стили пишутся также как и в атрибуте:

параметр:значение;параметр:значение;параметр:значение

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

Мы вставили двумя способами css-стили, а теперь давайте используем третий способ, самый оптимальный.

CSS в отдельном файле

Это самый лучший способ, который позволяет отделить полностью CSS от HTML-кода. Конечно иногда хочется вставить CSS прямо в HTML-код, но надо бить себя по рукам в этом случае и выносить CSS в отдельный файл. Зачем?

Это основная идея CSS размежевать текст и оформление текста. HMTL нам нужен чтобы разметить текст, а вот CSS нужен для того чтобы этот текст гармонично выглядел. С помощью HTML выводиться только текст, а с помощью CSS размеры, цвета, формы, границы, отступы.

Это было во-первых, теперь во-вторых когда код HTML и CSS в одном файле, то это становится нечитабельно и грамоздко. А теперь в-третьих, css сохраняются в браузере, поэтому если вынести весь CSS отдельно, то страница будет загружаться быстрее, потому что загружать css нужно только один раз. Я думаю вам уже стало понятным к чему я клоню?

CSS нужно стараться выносить в отдельный файл! Вот к этому я и клоню. А теперь давайте создавать отдельный css файл. Для этого есть тег <link>:

 

<html>
 <head>
  <title>Учебник CSS</title>
  <link type="text/css" rel="stylesheet" media="all" href="styles.css" />
 </head>
 <body>
  <p>Учите CSS вместе с drupalbook.org</p>
  <p>2 строка учите CSS вместе с drupalbook.org</p>
 </body>
</html>

У тега <link> есть следующие атрибуты:

type=»text/css» — так мы указываем то что это css,

rel=»stylesheet» — это указывает на то что этот файл является css-файлом,

media=»all» — этот css файл будет отображаться для всех устройств, через которые просматривают сайт,

href=»styles.css» — путь к css файлу, в нашем случае путь относительный.

Кажется разобрались с тем как подключать css файл, теперь создавайте этот файл styles.css в той же папке где и html-файл.

Теперь открывайте файл styles.css и вставьте него css-стили:

body{
  background: #eeeeee; /* фон страницы */
  font-size: 14px;            /* размер шрифта */
}
p{
  color: #ff0000; /* цвет текста */
}

Сохраните этот файл и откройте через браузер ваш html-файл. Теперь css подключен к вашему файлу как полагается, через отдельный файл. В следующем уроке мы подробно начнем разбирать, как писать стили в отдельном файле.

Работа с CSS | Vue CLI

Проекты Vue CLI предоставляют поддержку для PostCSS, CSS-модулей, а также пре-процессоров, включая Sass, Less и Stylus.

Указание ссылок на ресурсы

Весь скомпилированный CSS обрабатывается css-loader, который будет парсить url() и разрешать их как зависимостями модуля. Это означает, что вы можете ссылаться на ресурсы, используя относительные пути на основе локальной файловой структуры. Обратите внимание, что если вы хотите ссылаться на файл внутри npm-зависимости или через псевдоним webpack, путь должен начинаться с префикса ~ для избежания двусмысленности. Подробнее в разделе Обработка статических ресурсов.

Пре-процессоры

Вы можете выбрать пре-процессоры (Sass/Less/Stylus) при создании проекта. Если вы этого не сделали, то внутренняя конфигурация webpack всё равно настроена для их использования. Вам лишь требуется вручную доустановить соответствующие загрузчики для webpack:

Примечание при использовании webpack 4

При использовании webpack версии 4, по умолчанию во Vue CLI 4, следует убедиться в совместимости используемых загрузчиков. В противном случае будут появляться ошибки о конфликтующих зависимостях. В таких случаях можно использовать более старую версию загрузчика, которая всё ещё совместима с webpack 4.

Теперь вы можете импортировать соответствующие типы файлов, или использовать их синтаксис внутри файлов *.vue с помощью:

Совет по производительности Sass

Обратите внимание, при использовании Dart Sass синхронная компиляция вдвое быстрее асинхронной по умолчанию, из-за накладных расходов на асинхронные коллбэки. Чтобы избежать их можно воспользоваться пакетом fibers для вызова асинхронных импортёров по пути синхронного кода. Для этого просто установите fibers в качестве зависимости проекта:

Также имейте в виду, поскольку это нативный модуль, то могут возникнуть различные проблемы совместимости, в зависимости от ОС и окружения сборки. В таких случаях выполните npm uninstall -D fibers для устранения проблемы.

Автоматические импорты

Если вы хотите автоматически импортировать файлы (для цветов, переменных, примесей…), можно использовать style-resources-loader. Вот пример для stylus, который импортирует ./src/styles/imports.styl в каждый однофайловый компонент и в каждый файл stylus:

Вы также можете использовать vue-cli-plugin-style-resources-loader.

PostCSS

Vue CLI использует PostCSS внутри себя.

Вы можете настроить PostCSS через .postcssrc или любую другую конфигурацию, которая поддерживается postcss-load-config, а также настраивать postcss-loader через опцию css.loaderOptions.postcss в файле vue.config.js.

Плагин autoprefixer включён по умолчанию. Чтобы определить целевые браузеры используйте поле browserslist в файле package.json.

Примечание о префиксных CSS правилах

В сборке для production Vue CLI оптимизирует ваш CSS и удаляет ненужные префиксные правила CSS, основываясь на целевых браузерах. С autoprefixer включённым по умолчанию, вы должны всегда использовать только CSS-правила без префиксов.

CSS-модули

CSS-модули в файлах *.vue доступны из коробки с помощью <style module>.

Для импорта CSS или других файлов пре-процессоров в качестве CSS-модулей в JavaScript, необходимо чтобы имя файла заканчивалось на .module.(css|less|sass|scss|styl):

Если вы не хотите указывать .module в именах файлов, установите css.requireModuleExtension в false внутри файла vue.config.js:

Если вы хотите настроить генерируемые имена классов для CSS-модулей, вы можете сделать это с помощью опции css.loaderOptions.css в vue.config.js. Все настройки css-loader поддерживаются, например localIdentName и camelCase:

Передача настроек в загрузчики пре-процессоров

Иногда может возникнуть необходимость передать настройки в загрузчик пре-процессора для webpack. Вы можете сделать это с помощью опции css.loaderOptions в vue.config.js. Например, для передачи глобальных переменных во все стили Sass/Less:

Загрузчики которые можно настраивать с помощью опции loaderOptions:

Совет

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

Создание и настройка проекта React + Webpack с нуля до SSR — Разработка на vc.ru

10 100 просмотров

Хочу вам показать наглядный пример и инструкцию того, как можно самому с «чистого листа» сконфигурировать Webpack для React и Server Side Render’а без каких-либо бойлерплейтов, вроде create-react-app.

Некоторое время назад я начал заниматься созданием сайтов на сей чудесном view-фреймворке и по ходу дела сталкивался со многими проблемами, начиная от того, как правильно и практично реализовать конфиг Webpack’а и как готовить SSR совместно с TypeScript. Было прочитано кучу мануалов, пользовательских решений в гитхабе и прочего, что новичка (да даже иногда и опытных разработчиков) может ввести в ступор. Конечно, можно использовать create-react-app и потом «костылить» eject‘ы (расширение базовой конфигурации), обмазывая все готовыми плагинами, но ведь мы хотим держать весь проект под своим видением, не так ли? Да и просто будет полезно понять весь принцип «приготовления» приложения «от» и «до».

Маленькое предисловие:

1) На клиенте используем Node JS 13й версии. К сожалению, на момент написания статьи (сентябрь 2020 г.) на >=14 версии не работает Webpack Dev Server (далее WDS) (никак не обновят в нем Chokidar).

2) В проекте будем использовать: Webpack, TypeScript (далее TS), React, React Router, Stylus, ExpressJS.

3) Постараюсь описать каждый установленный npm-пакет и мало мальски важные, на мой взгляд, параметры в Webpack’е.

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

Проект основан почти на «голом» React’е, без всяких Redux’ов, MobX’ов, Helmet’ов и тэдэ. Я хочу продемонстрировать принцип работы сборки и запуска проекта на сервере. Все остальное, надеюсь, сможете отредактировать в дальнейшем под себя.

Итак, начнем с инита npm:

Можете и без ключа yes, чтобы предварительно занести нужную информацию в package.json.

Установим все необходимое для Webpack’a и чтобы он мог собирать TS:

npm i webpack webpack-cli webpack-dev-server webpack-notifier typescript ts-loader clean-webpack-plugin uglifyjs-webpack-plugin —save-dev

  • webpack — сборщик собственной персоной
  • webpack-cli — позволяет работать с Webpack’ом из консоли
  • webpack-dev-server — небольшой сервер для разработки
  • webpack-notifier — будет показывать нам уведомления, если вдруг что-то где-то сломаем
  • typescript — компилятор TS-кода
  • ts-loader — инжектор TS’а в Webpack
  • clean-webpack-plugin — при каждой сборке автоматически очищает папку для итоговых файлов
  • uglifyjs-webpack-plugin — для продовой версии будет сжимать и минифицировать JS-файлы

Для тех, кто не так давно работает с npm: с параметром —save-dev устанавливаем пакеты, которые нам нужны именно для разработки (webpack, typescript, например), с —save пакеты которые пойдут в сборку (react, react-dom, fontawesome).

Установим React с роутером:

npm i react react-dom react-router-dom —save

  • react — view-фреймворк
  • react-dom — плагин, который будет конвертировать React DOM в html-структуру
  • react-router-dom — роутер, который интегрируется через React DOM

Для TS нам надо установить типизацию React, чтобы компилятор понимал с какими данными работает и было удобнее писать код в редакторе:

npm i @types/react @types/react-dom @types/react-router-dom —save-dev

Устанавливаем CSS-препроцессор (я использую Stylus), с которым будем взаимодействовать и пара плагинов, которые наши стили «доведут до ума» перед продом:

npm i stylus stylus-loader css-loader style-loader [email protected] postcss-csso postcss-loader —save-dev

  • stylus — препроцессор
  • stylus-loader — инжектор Stylus’а в Webpack
  • css-loader — позволит нам работать в стилях с @import как import/require в JS
  • style-loader — встраивает наши стили в DOM
  • [email protected] — в релизной сборке будет добавлять префиксы к некоторым стилям (например, -webkit-transition). 10я версия в данном кейсе пока что не работает.
  • postcss-csso — очень крутой плагин, который минифицирует CSS
  • postcss-loader — инжектор PostCSS’а в Webpack

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

Создадим в корне проекта папку src со всеми исходниками:

|—src |—App // Энтрипоинт нашего приложения >—index.styl >—index.tsx |—Common // Директория для вспомогательных элементов, сюда же можно в дальнейшем и изображения класть, например |—Styles >—reset.styl // Сброс дефолтных стилей браузера >—variables.styl // Переменные для стилей |—Html >—Browser.html // Html-шаблон для разработки, в который будут подключаться наши итоговые JS-файлы |—Pages // Страницы нашего приложения |—Content >—index.styl >—index.tsx |—Home >—index.styl >—index.tsx >—Routes.ts // Конфигурация роутинга >—Client.tsx // Рендерим энтрипоинт в HTML-документ

Настраиваем TS. Особо сильно в конфигурацию упарываться не будем, пока просто укажем стоковые параметры для компиляции React со строгими правилами. За всей документацией можно сходить на официальный сайт: https://www.typescriptlang.org/docs

В корне проекта создаем файл tsconfig.json:

{ «compilerOptions»: { «target»: «es5», «jsx»: «react», «noEmitOnError»: true, «noUnusedLocals»: true, «removeComments»: true, «noImplicitAny»: true, «esModuleInterop»: true, «baseUrl»: «./», «paths»: { // Указываем ссылки до директорий в проекте, чтобы каждый раз в импортах не писать относительные пути «App»: [«src/App»], «Pages/*»: [«src/Pages/*»], } }, «exclude»: [ «node_modules» ] }

Сделаем внешний конфиг-файл с модулями и правилами для Webpack. Внешний нужен для того, что мы будем использовать его для 2х конфиг-файлов Webpack’a: клиент и сервер, но это чуть позднее. Документация https://webpack.js.org/concepts/

В корне проекта создаем webpack.config.js:

const path = require(«path») module.exports = (env) => { const modules = { js: { test: /\.ts(x?)$/, exclude: /node_modules/, use: [ { loader: «ts-loader», }, ], }, stylus: { test: /\.styl$/, use: [ { loader: «style-loader», }, { loader: «css-loader», }, { loader: «stylus-loader», options: { import: [ // Тут для Stylus’а можем объявить глобальные переменные или функции, чтобы каждый раз их не импортировать path.resolve(__dirname, ‘src/Common/Styles/variables.styl’), ], } }, ], }, } if (env === ‘production’) { modules.stylus.use.splice(2, 0, { loader: «postcss-loader» }) } const resolve = { extensions: [«.ts», «.tsx», «.js», «.jsx»], alias: { // Тут тот же момент, что и в tsconfig.json, чтобы Webpack смог понять ссылки на директории App: path.resolve(__dirname, ‘src/App/’), Pages: path.resolve(__dirname, ‘src/Pages/’), }, } return { modules, resolve, } }

Создаем в корне проекта файл клиентской конфигурации для Webpack’а webpack.client.js:

const path = require(«path») const HtmlWebpackPlugin = require(‘html-webpack-plugin’) const WebpackNotifierPlugin = require(‘webpack-notifier’) const UglifyJsPlugin = require(‘uglifyjs-webpack-plugin’) const { CleanWebpackPlugin } = require(‘clean-webpack-plugin’) const webpackConfig = require(‘./webpack.config’) module.exports = (env, argv) => { const watchMode = argv.liveReload || false const modeEnv = argv.mode || ‘development’ const isProd = modeEnv === ‘production’ const config = webpackConfig(modeEnv) const optimizations = { splitChunks: { // Чанки для нашего приложения. Все наши npm-пакеты вынесем в отдельный файл с определенным хешем, чтобы клиент каждый раз при изменениях не выкачивал все по-новой cacheGroups: { vendors: { name: ‘vendors’, test: /node_modules/, chunks: ‘all’, enforce: true, }, }, }, minimizer: [], } if (isProd) { optimizations.minimizer.push(new UglifyJsPlugin()) } return { devServer: { contentBase: path.join(__dirname, «dist»), compress: true, port: 4200, watchContentBase: true, progress: true, hot: true, open: true, historyApiFallback: true, // Не забудьте про этот параметр, ибо со значением false WDS будет «прямолинейно» обрабатывать ссылки для React Router’а. Т.е. он будет по путь->директория искать index.html, а он у нас один и в корне. }, resolve: config.resolve, module: { rules: [ config.modules.js, config.modules.stylus, ], }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ template: ‘./src/Html/Browser.html’, // Скармливаем наш HTML-темплейт }), new WebpackNotifierPlugin({ alwaysNotify: false }), ], entry: { main: ‘./src/Client.tsx’, // Энтрипоинт-файл, с которого и начнется наша сборка }, output: { filename: watchMode ? ‘assets/[name].[hash].js’ : ‘assets/[name].[chunkhash].js’, // небольшое условие, т.к. WDS не будет работать с chunkhash path: path.resolve(__dirname, ‘dist’), // Весь наш результат складываем в папку dist publicPath: ‘/’, }, performance: { hints: false, }, optimization: optimizations, } }

Осталось немного. Добавим в корень проекта конфиг PostCSS postcss.config.js:

module.exports = { plugins: [ require(‘autoprefixer’), require(‘postcss-csso’), ] }

И добавим скрипты для сборки в package.json с донастройкой PostCSS.

В секцию scripts добавляем команды:

«watch»: «webpack-dev-server —config webpack.client.js —mode development» // Запуск нашего дев-сервера и пересборка при изменении файлов «build»: «webpack —config webpack.client.js —mode production» // Билд проекта для продовой версии «dev»: «webpack —config webpack.client.js —mode development» // Билд версия с возможностью отладки

Для Autoprefixer’а в корень json’а добавим параметр, для каких браузеров добавлять префиксы:

«browserslist»: [ «last 2 versions» ]

Супер! Наш сборщик полностью готов собирать проект. Наполним src/Client.tsx тестовым контентом:

import React from ‘react’ import ReactDOM from ‘react-dom’ ReactDOM.render(<h2>Woohoo!</h2>, document.getElementById(‘root’))

Не забываем, что у нас еще есть index.html для WDS src/Html/Browser.html

<!DOCTYPE html> <html lang=»en»> <head> <meta charset=»UTF-8″> <meta name=»viewport» content=»width=device-width, minimum-scale=1.0, maximum-scale=1.0, initial-scale=1.0″> <meta http-equiv=»X-UA-Compatible» content=»ie=edge»> <title>React Starter Pack</title> </head> <body> <div></div> </body> </html>

Выполняем в консолях npm run watch и видим результат

Берем тестовый React-контент с GitHub’а, где я сделал страницы с роутингом и стили. Кстати, заметьте, стили я подключаю через require в самом компоненте (в методе render для классовых компонентов). Это позволяет в head добавлять стили только отображаемых компонентов, что снижает нагрузку на парсинг и рендер.

Представим, что наше приложение полностью написано и готово к релизу. Приступим к Server Side Render части.

Для работы SSR нам нужны следующие npm-пакеты:

  • express — Node JS сервер
  • @types/express — TS тип для ExpressJS
  • mini-css-extract-plugin — плагин, который выгрузит стили не в JS-файлы, а отдельный CSS. Если понадобится, вы можете вывести его в серверную часть.
  • webpack-node-externals — плагин, позволяющий исключать из сборки node_modules по дефолту

npm i express @types/express mini-css-extract-plugin webpack-node-externals —save-dev

В webpack.config.js добавим:

const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)

В массив модулей добавляем новый объект для компиляции отдельного изоморфного CSS-файла:

stylusIsomorph: { test: /\.styl$/, use: [ { loader: MiniCssExtractPlugin.loader, }, { loader: «css-loader», }, { loader: «stylus-loader», options: { import: [ path.resolve(__dirname, ‘./src/Common/Styles/variables.styl’), ], } }, ], }

И также добавим для него PostCSS для production-режима:

if (env === ‘production’) { … modules.stylusIsomorph.use.splice(2, 0, { loader: «postcss-loader» }) }

Казалось, мы могли бы все это запустить напрямую в ExpressJS, но нам надо все приложение прогнать через TS.

Создадим в корне проекта отдельный Webpack-конфиг для компиляции серверной части webpack.server.js:

const path = require(«path») const UglifyJsPlugin = require(‘uglifyjs-webpack-plugin’) const nodeExternals = require(‘webpack-node-externals’) const { CleanWebpackPlugin } = require(‘clean-webpack-plugin’) const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’) const webpackConfig = require(‘./webpack.config’) module.exports = (env, argv) => { const modeEnv = argv.mode || ‘development’ const config = webpackConfig(modeEnv) const optimizations = { minimizer: [ new UglifyJsPlugin(), ], } return { plugins: [ new CleanWebpackPlugin(), new MiniCssExtractPlugin(), // Подключаем плагин для CSS ], resolve: config.resolve, module: { rules: [ config.modules.js, config.modules.stylusIsomorph, ], }, entry: { main: ‘./src/Server.tsx’, // Тут уже энтрипоинт сервера, который сделаем далее }, output: { filename: ‘[name].js’, path: path.resolve(__dirname, ‘server’), // Все компилируем в папку server }, performance: { hints: false, }, optimization: optimizations, target: ‘node’, // обязательно указываем режим сборки для node js, а не браузера externals: [nodeExternals()], // исключаем node_modules } }

Создадим наш энтрипоинт для сборки сервера src/Server.tsx:

import fs from ‘fs’ import express from ‘express’ import React from ‘react’ import ReactDOMServer from ‘react-dom/server’ import { StaticRouter } from ‘react-router’ import { App } from ‘App’ import { Html } from ‘./Html/Server’ const port = 3000 const server = express() const jsFiles: Array<string> = [] fs.readdirSync(‘./dist/assets’).forEach(file => { if (file.split(‘.’).pop() === ‘js’) jsFiles.push(‘/assets/’ + file) }) server.use(‘/assets’, express.static(‘./dist/assets’)) server.get(‘*’, async (req, res) => { ReactDOMServer.renderToNodeStream(<Html scripts={jsFiles}> <StaticRouter location={req.url} context={{}}> <App /> </StaticRouter> </Html>).pipe(res) }) server.listen(port, () => console.log(`Listening on port ${port}`))

1) «Обертку» HTML’а теперь генерируем динамически.

2) Обратите внимание на StaticRouter. ExpressJS будет автоматически генерировать роутер для отдачи статичного HTML с сервера.

3) В тело документа напрямую «опрокидываем» наш энтрипоинт приложения.

4) GET-метод реализуем через Node JS Streams.

Создадим для начала HTML в src/Html/Server.tsx:

import React from ‘react’ interface Html { scripts: Array<string> } export function Html({ children, scripts }: React.PropsWithChildren<Html>) { return ( <html> <head> <meta charSet=»UTF-8″ /> <meta name=»viewport» content=»width=device-width,minimum-scale=1,maximum-scale=1,initial-scale=1″ /> <meta httpEquiv=»X-UA-Compatible» content=»ie=edge» /> <title>React Starter Pack</title> </head> <body> <div>{children}</div> {scripts.map((script, index) => <script src={script} key={index} />)} </body> </html> ) }

У компонента есть аргумент scripts. ExpressJS собирает из /dist/assets все JS-файлы и явно указывает на них.

Кстати, все ваши meta-теги, ссылки на фавиконки надо указывать в этом файле. Browser.html нужен только для WDS’а.

import React from ‘react’ import ReactDOM from ‘react-dom’ import { BrowserRouter } from ‘react-router-dom’ import { App } from ‘App’ const entryBlock = document.getElementById(‘root’) const renderFunction: ReactDOM.Renderer = entryBlock.hasChildNodes() ? ReactDOM.hydrate : ReactDOM.render renderFunction(<BrowserRouter> <App /> </BrowserRouter>, entryBlock)

Вот тут могут быть «запуточки». Пояснение: когда запускаем наше приложение через WDS, сначала входим в src/Html/Browser.html, потом подгружаем JS и отрабатывает метод render, т.к. в div#root ничего нет. Инитим BrowserRouter и далее App. Когда же запускается React c ExpressJS сервера, в div#root уже присутствует контент: определенная страница или 404я — отрабатывает метод hydrate.

С ExpressJS алгоритм такой:
Строим основное тело HTML-документа из файла src/Html/Server.tsx ->
Определяем StaticRouter с нужными параметрами и контекстом ->
Рендерим главный компонент App ->
Отдаем страницу

Когда запускаем React на клиентской стороне с ExpressJS сервера:
Тело HTML уже получили ->
Рендерим динамический контент через метод hydrate

Добавим в package.json команду для сборки и запуска сервера:

«start»: «webpack —config webpack.server.js —mode production && node ./server/main.js»

Все, теперь наше приложение готово к запуску. Предварительно поставьте нужный порт для сервера в src/Server.tsx (в примере 3000).

npm run build npm run start

Сервер стартовал и можем протестировать работу по адресу http://localhost:3000

Также вместо node вы можете использовать nodemon.

Надеюсь, данная статья помогла вам понять, как правильно и удобно сплитовать конфиги Webpack и как работает SSR в связке с React’ом, в какой последовательности и принципе.

Методология CSS-модулей

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

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

Сейчас у нас появилась очередная интересная новинка — CSS-модули. В этой статье я представлю эту новую технику, расскажу о ее сильных сторонах и о том, как начать с ней работать.

Что такое CSS-модуль ?

Начнем с определения из официального репозитория проекта:

CSS-модуль это файл CSS, в котором названия классов и анимаций по умолчанию заданы локально.

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

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

Как это работает

CSS-модули надо подключать в сборочный процесс, это значит, что они не работают сами по себе. Плагины есть для webpack или Browserify. На базовом уровне это работает так: при импорте файла в модуль JavaScript (например, в компонент React), CSS-модули переопределят объект с названиями классов из файла в динамически задаваемые пространства имен классов, которые можно использовать как строки в JavaScript. Проиллюстрируем это на примере:

Ниже показан очень простой файл CSS. Класс .base не является уникальным в проекте и это не то название класса, которое будет присвоено элементу. Это своего рода псевдоним внутри таблицы стилей, который будет использован в модуле JavaScript.

.base {
  color: deeppink;
  max-width: 42em;
  margin: 0 auto;
}

И вот его использование в тестовом компоненте JavaScript:

import styles from './styles.css';

element.innerHTML = `<div>
  CSS Modules are fun.
</div>`;

В итоге у нас будет сгенирировано что-то вроде следующего кода (это пример использования CSS-модулей в Webpack с дефолтными настройками):

<div>CSS Modules are fun.</div>
._20WEds96_Ee1ra54-24ePy {
  color: deeppink;
  max-width: 42em;
  margin: 0 auto;
}

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

Возможные возражения

Итак, мы разобрались, как это работает. И теперь вы думаете: “Что же с этим делать? Ведь это…”. ОК, я вас понимаю. Сейчас мы разберем все возражения по отдельности.

Это выглядит ужасно!

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

Их трудно отлаживать!

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

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

Это препятствует многократному использованию стилей

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

С другой стороны, мы можем создавать глобальные классы (с помощью :global()), например, вспомогательные классы, которые сохраняются в том же виде после сборки и позволяют абстрагировать стили также просто как и в обычных условиях. Эти классы можно использовать в ваших компонентах JavaScript.

:global(.clearfix::after) {
  content: '';
  clear: both;
  display: table;
}

В CSS-модулях также есть способ расширения стилей из другого модуля, работающий аналогично директиве @extend в Sass. Он не копирует стили, а складывает селекторы для расширения стилей.

.base {
  composes: appearance from '../AnoherModule/styles.css';
}

Они требуют webpack, Browserify или другие инструменты?

Точно также как требуется Sass для компиляции .scss в обычный CSS, PostCSS необходим для обработки стилей, чтобы сделать их понятными браузеру. От этапа сборки никуда не деться.

Почему мы вообще это обсуждаем?

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

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

Начало работы с CSS-модулями

Как уже было сказано, нам нужен webpack или Browserify для работы CSS-модулей.

Webpack

Начнем с версии для webpack. В файл webpack.config.js добавьте следующую конфигурацию, чтобы webpack обрабатывал файлы CSS с помощью CSS-модулей:

{
  test: /\.css$/,
  loader: 'style-loader!css-loader?modules'
}

С такой настройкой полученные стили будут размещаться внутри элемента <style> на странице. Это не самое лучшее решение, поэтому мы сконфигурируем вывод итоговых стилей в отдельный файл благодаря плагину извлечения текста для webpack:

{
  test: /\.css$/,
  loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules')
}

Этого достаточно для работы с webpack.

Browserify

Я всегда использовал Browserify только через командную строку, так что это оказалось немного сложнее. Я добавил скрипт npm в файл package.json:

{
  "scripts": {
    "build": "browserify -p [ css-modulesify -o dist/main.css ] -o dist/index.js src/index.js"
  }
}

Эта строчка сообщает Browserify, что надо трансформировать src/index.js, в dist/index.js и скомпилировать файл dist/main.css с помощью плагина css-modulesify. Если вы хотите добавить автопрефиксер, то вы можете завершить команду так:

{
  "scripts": {
    "build": "browserify -p [ css-modulesify --after autoprefixer -o dist/main.css ] -o dist/index.js src/index.js"
  }
}

Как видите, вы можете использовать опцию --after для обработки стилей после их компиляции.

Заключение

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

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

В качестве дальнейшего чтения по теме я рекомендую введение в CSS-модули от Глена Мэддерна, автора этого проекта.

main.css · GitHub

/ * Модифицированная тема Jekyll по умолчанию
/ *
/ * Улучшения включают:
/ *
/ * 1. Адаптивный шаблон: добавлены медиа-запросы, чтобы он работал хорошо
/ * на большом количестве экранов.
/ *
Лицензия MIT (MIT)
Авторские права (c) 2013 Кашьяп
Разрешение предоставляется бесплатно любому лицу, получившему копию
этого программного обеспечения и связанных файлов документации («Программное обеспечение») для работы с
в Программном обеспечении без ограничений, включая без ограничений права
для использования, копирования, изменения, объединения, публикации, распространения, сублицензирования и / или продажи
копий Программного обеспечения, и разрешить лицам, которым Программное обеспечение принадлежит
предоставлено для этого при соблюдении следующих условий:
Вышеупомянутое уведомление об авторских правах и это уведомление о разрешении должны быть включены в
всех копий или существенных частей Программного обеспечения.
ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНЫХ ИЛИ
ПОДРАЗУМЕВАЕТСЯ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИИ КОММЕРЧЕСКОЙ ЦЕННОСТИ,
ПРИГОДНОСТЬ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ И НЕЗАЩИТА ОТ ПРАВ. НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ
АВТОРЫ ИЛИ ДЕРЖАТЕЛИ АВТОРСКИХ ПРАВ НЕСУТ ОТВЕТСТВЕННОСТЬ ЗА ЛЮБЫЕ ПРЕТЕНЗИИ, УБЫТКИ ИЛИ ДРУГИЕ
ОТВЕТСТВЕННОСТЬ, ВЫЯВЛЯЮЩАЯСЯ В РЕЗУЛЬТАТЕ ДОГОВОРА, ИЛИ ИНОСТРАННОЙ ДЕЯТЕЛЬНОСТИ, ВОЗНИКНУЮ ИЗ,
НЕ ИЛИ В СВЯЗИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ИЛИ ДРУГИМИ ДЕЛАМИ НА
ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ.
/ ********************************************** ***************************** /
/ *
/ * Обычный
/ *
/ *********************************************** ***************************** /
/ * Общий сброс * /
* {
маржа: 0;
отступ: 0;
}
HTML, body {height: 100%; }
кузов {
цвет фона: #FFF;
размер шрифта: 130%;
семейство шрифтов: calluna, Calluna, Джорджия;
font-weight: 300;
line-height: 1.55em;
отступ: 0 2em;
рендеринг текста: optimizeLegibility;
цвет: # 555;
}
h2, h3, h4, h5, h5, h6 {
цвет: # 333;
семейство шрифтов: adelle, Адель, Джорджия;
font-weight: 800;
рендеринг текста: optimizeLegibility;
}
h2 {
размер шрифта: 170%;
margin-top: 1em;
нижнее поле: 0.5em;
line-height: 1.4em;
}
h3 {
размер шрифта: 150%;
margin-top: 1em;
нижнее поле: 0,5em;
line-height: 1.4em;
}
h4 {
размер шрифта: 130%;
верхняя маржа: 3,25em;
нижнее поле: 0,5em;
line-height: 1.4em;
}
h5 {
размер шрифта: 110%;
margin-top: 2em;
нижнее поле: 0.5em;
line-height: 1.4em;
}
h5 {
размер шрифта: 100%;
margin-top: 1,5em;
нижнее поле: 0,5em;
line-height: 1.4em;
}
п {
маржа: 0.5em 0 2.5em;
}
а {цвет: # 00а; }
a: hover {color: # 000; }
a: посетил {color: # a0a; }
цитата {
отступ: 0.1em 1.3em;
фон: #fafafa;
border-left: 5px # 81E26D solid;
цвет: # 666;
}
/ *********************************************** ***************************** /
/ *
/ * Дом
/ *
/ *********************************************** ***************************** /
ул.столбы {
list-style-type: нет;
нижнее поле: 2em;
}
ul.posts li {
высота строки: 1,75 мкм;
нижнее поле: 1em;
}
ул.пролет столбов {
цвет: #aaa;
семейство шрифтов: «Inconsolata», Consolas, «Courier New», моноширинный;
размер шрифта: 80%;
дисплей: элемент списка;
}
/ *********************************************** ***************************** /
/ *
/ * Зона
/ *
/ *********************************************** ***************************** /
.сайт {
маржа: авто;
max-width: 34em;
отступ: 0 1em;
цвет: # 333;
}
. Сайт. Заголовок а {
font-weight: жирный;
оформление текста: нет;
}
.site .header h2.title {
дисплей: строчно-блочный;
размер шрифта: 180%;
}
.site .header h2.title a {
цвет: # a00;
}
.site .header h2.title a: hover {
цвет: # 000;
}
.site .header a.extra {
цвет: #aaa;
левое поле: 1em;
}
.site .header a.extra: hover {
цвет: # 000;
}
. Сайт. Мета {
цвет: #aaa;
}
. Сайт. Нижний колонтитул {
размер шрифта: 80%;
цвет: # 666;
border-top: сплошной 4px #eee;
margin-top: 2em;
переполнение: скрыто;
}
.сайт .footer .contact {
поплавок: левый;
поле справа: 3em;
}
. Сайт. Нижний колонтитул. Связаться с {
цвет: # 8085C1;
}
.сайт .footer .rss {
margin-top: 1.1em;
margin-right: -.2em;
поплавок: правый;
}
.site .footer .rss img {
граница: 0;
}
до {
семейство шрифтов: ‘PT Mono’, Consolas, «Inconsolata», «Courier New», моноширинный;
переполнение: авто;
маржа: 1em авто;
}
код {
семейство шрифтов: ‘PT Mono’, Consolas, «Inconsolata», «Courier New», моноширинный;
}
/ *********************************************** ***************************** /
/ *
/ * Посты
/ *
/ *********************************************** ***************************** /
/ * стандарт * /
.пост до {
граница: сплошная 1px #ddd;
цвет фона: #eef;
высота строки: 1em;
заполнение: 0,2 мкм 0,5 мкм;
}
.post ul, .post ol {
левое поле: 1.5em;
нижнее поле: 1.5em;
}
.почтовый индекс {
граница: сплошная 1px #ddd;
цвет фона: #eef;
font-size: 0.7em;
}
.предварительный почтовый индекс {
граница: отсутствует;
}
/ * терминал * /
. Пост. Предтерминал {
граница: сплошной 1px # 000;
цвет фона: # 333;
цвет: #FFF;
}
.почтовый предтерминальный код {
цвет фона: # 333;
}
.post {
выравнивание текста: выравнивание;
}
/ ********************************************** ************************ /
/ * Медиа-запросы
/ *
/ *********************************************** ************************ /
@media screen и (макс. Ширина: 1000 пикселей) {
кузов {
размер шрифта: 130%;
отступ: 0 4em;
}
.почтовый индекс {
размер шрифта: 85%;
}
предварительный код {
line-height: 1.6em;
}
}
@media screen и (макс. Ширина: 800 пикселей) {
кузов {
размер шрифта: 125%;
отступ: 0 1.5em;
}
.почтовый индекс {
размер шрифта: 80%;
}
предварительный код {
размер шрифта: 80%;
}
}
@media screen и (макс. Ширина: 500 пикселей) {
кузов {
размер шрифта: 120%;
отступ: 0 0.5em;
}
. Нижний колонтитул {
выравнивание текста: по центру;
отступ: 1em;
}
.контакт {
ширина: 100%;
}
.почтовый индекс {
размер шрифта: 85%;
}
}
@media screen и (макс. Ширина: 320 пикселей) {
кузов {
отступ: 0;
}
}

— HTML: язык разметки гипертекста

HTML

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

В документе не должно быть более одного элемента

, для которого не указан атрибут hidden .

Содержимое элемента

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

не влияет на структуру документа; то есть, в отличие от таких элементов, как , такие заголовки, как

и т. д.,
не влияют на концепцию DOM структуры страницы. Это строго информативно.

 

<основной>
   

Яблоки

Яблоко - это семечковые плоды яблони.

<статья>

Ред Делишес

Эти ярко-красные яблоки чаще всего встречаются во многих супермаркеты.

...

...

<статья>

Бабушка Смит

Эти сочные зеленые яблоки отлично подходят для яблочные пироги.

...

...