Блог экспериментатора инженера-разработчика: Infanty.
Я пишу how-to статьи на редкие темы или статьи обзоры - для себя и тех кто со мной работает.
Блог существует при поддержке: "Оккупационных сил Марса".

Интеграция PostCSS в React.js приложение

PostCSS – это модульный препроцессор, предназначенный для увеличения уровня абстракции CSS кода и упрощения файлов стилей. PostCSS немного отличается от препроцессоров Sass, Less и Stylus. Самая сильная его сторона - это наличие плагинов, которые анализируют, манипулируют, добавляют или изменяют свойства и значения в CSS коде еще до того, как конечный CSS файл будет сформирован и сохранён.

Установим PostCSS и необходимые библиотеки в CRA (Create React App), перейдя в папку проекта и набрав в консоли:

 npm install autoprefixer postcss-nested postcss-preset-env postcss-cli npm-run-all postcss-import postcss-extend --save-dev  

Где первые три библиотеки - нужны для обработки правил в CSS, подробнее по ссылкам: https://github.com/postcss/autoprefixer, https://github.com/postcss/postcss-nested, https://github.com/csstools/postcss-preset-env.

А остальные:

  • postcss-cli и npm-run-all - нужны для интеграции в CRA.
  • postcss-import - необходим для использования: "@import" (пример будет ниже).
  • postcss-extend - необходим для использования: "@extend" (пример будет ниже).

Для настройки плагинов PostCSS, создадим файл "postcss.config.js" в корне проекта:

module.exports = {
  plugins: [
    require('postcss-import'),
    require('postcss-preset-env')({
      stage: 1,
    }),
    require('postcss-nested'),
    require('autoprefixer'),
    require('postcss-extend'),
  ],
} 

Изменяем способ запуска приложения в файле - "package.json", заменяя:

  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "precommit": "lint-staged",
    "eslint": "node_modules/.bin/eslint src/"
  }, 

на:

  "scripts": {
    "build:css": "postcss src/styles/main.css -o src/index.css",
    "watch:css": "postcss src/styles/main.css -o src/index.css -w",
    "start": "npm-run-all -p watch:css start-js",
    "start-js": "react-scripts start",
    "build-js": "react-scripts build",
    "build": "npm-run-all build:css build-js",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "precommit": "lint-staged",
    "eslint": "node_modules/.bin/eslint src/"
  }, 

Создадим в папке: src, подпапку: styles, а в ней файл - main.css, следующего содержания:

.App {
  text-align: center;

  &-logo {
    animation: App-logo-spin infinite 20s linear;
    height: 80px;
  }

  &-header {
    background-color: #222;
    height: 150px;
    padding: 20px;
    color: white;
  }

  &-title {
    font-size: 1.5em;
  }

  &-intro {
    font-size: large; 
  }
}
@keyframes App-logo-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
} 

После обработки данного CSS кода, PostCSS сформирует CSS следующего содержания (этот код аналогичен App.css из CRA):

.App {
  text-align: center;
  display: flex;
  flex-direction: column;
}

.App-logo {
  -webkit-animation: App-logo-spin infinite 20s linear;
  animation: App-logo-spin infinite 20s linear;
  height: 80px;
}

.App-header {
  background-color: #222;
  height: 150px;
  padding: 20px;
  color: white;
}

.App-title {
  font-size: 1.5em;
}

.App-intro {
  font-size: large;
}

@-webkit-keyframes App-logo-spin {
  from {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  to {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}

@keyframes App-logo-spin {
  from {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  to {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
} 

Остаётся только подключить в файле index.js (который находится в папке: src), файл CSS стилей:

import './index.css' 

вместо:

import './App.css' 

И запустить приложение командой: "npm start".

Примечания по PostCSS

Первое важное примечание: согласно настройкам в файле "package.json", при запуске приложения (и в дальнейшем при его редактировании) - PostCSS обрабатывает файл: "src/styles/main.css" и результат обработки сохраняет в "src/index.css". Поэтому в приложении всегда будет подключаться: "src/index.css".

В примере выше - производится подключение вида "import './index.css'", так как файл в котором производится подключение - расположен в той же директории: src.

Второе важное примечание: если Вам необходимо подключить несколько CSS файлов в проект, то вынесите все стили из main.css (например: в другой CSS файл). После чего подключите все необходимые CSS в main.css как в примере ниже:

@import 'styles-header.css';
@import 'styles-footer.css';
@import 'styles-article.css';
@import 'styles-meny.css'; 

И при запуске приложения (используя "npm start") - PostCSS обработает файл: "src/styles/main.css", в результате чего объединит все указанные в нём файлы CSS в один и результат обработки сохраняет в "src/index.css".

Примеры PostCSS

1) Rule Nesting

.article {
  color: #333;

  &.popular {
    background: #DDD;
  }

  & .title {
    font-weight: bold;
  }
  
  &-header {
    background-color: #222;
  }
} 

После обработки, PostCSS сформирует CSS следующего содержания:

.article {
  color: #333
}
.article.popular {
  background: #DDD
}
.article .title {
  font-weight: bold
}
.article-header {
  background-color: #222;
} 

2) Custom Selectors

@custom-selector :--heading h1, h2, h3, h4, h5, h6;

.article :--heading .author {
  color: blue;
} 

После обработки, PostCSS сформирует CSS следующего содержания:

.article h1 .author,
.article h2 .author,
.article h3 .author,
.article h4 .author,
.article h5 .author,
.article h6 .author {
  color: blue;
} 

3) :matches() / :not() / :any-link

 button:matches(:hover, :focus) {
  color: red;
}
section:not(:first-child, :last-child) {
  background: white;
}
a:any-link {
  color: blueviolet;
} 

После обработки, PostCSS сформирует CSS следующего содержания:

button:hover, button:focus {
  color: red;
}
section:not(:first-child):not(:last-child) {
  background: white;
}
a:link,a:visited {
  color: blueviolet;
} 

4) Custom Media

@custom-media --medium-viewport (min-width: 768px) and (max-width: 992px);
@custom-media --landscape (orientation: landscape);
@media (--medium-viewport) and (--landscape) {
  /* your styles here */
} 

После обработки, PostCSS сформирует CSS следующего содержания:

@media (min-width: 768px) and (max-width: 992px) and (orientation: landscape) {
  /* your styles here */
} 

5) Initial

.article {
  font-size: initial;
  color: initial;
  padding: initial;
  margin: initial;
}
.container {
  all: initial;
} 

После обработки, PostCSS сформирует CSS следующего содержания:

.article {
  font-size: medium;
  font-size: initial;
  color: #000;
  color: initial;
  padding: 0;
  padding: initial;
  margin: 0;
  margin: initial;
}
.container {
  ...
  visibility: visible;
  white-space: normal;
  widows: 2;
  width: auto;
  ...
} 

6) Properties in the :root

:root {
  --text-color: red;
  --background: blue;
}

h1 {
  color: var(--text-color);
  font-size: var(--font-size, 20px);
}
button {
  background-color: var(--background);
}

После обработки, PostCSS сформирует CSS следующего содержания:

 h1 {
  color: red;
  font-size: 20px;
}
button {
  background-color: blue;
} 

7) Color

body {
  color: color(red green(50));
  color: color(red blue(50) a(50%));
  color: color(red tint(50%));
  color: color(red shade(50%));
  
  color: hwb(0, 0%, 0%);
  color: hwb(120, 40%, 20%);
  color: hwb(240, 0%, 100%, 0.5);
  
  color: gray(0);
  color: gray(25);
  color: gray(50%);
  color: gray(128, 20%);
} 

После обработки, PostCSS сформирует CSS следующего содержания:

body {
  color: rgb(255, 50, 0);
  color: rgba(255, 0, 50, 0.5);
  color: rgb(255, 128, 128);
  color: rgb(128, 0, 0);
  
  color: rgb(255, 0, 0);
  color: rgb(102, 204, 102);
  color: rgba(0, 0, 0, 0.5);
  
  color: rgb(0, 0, 0);
  color: rgb(25, 25, 25);
  color: rgb(127, 127, 127);
  color: rgba(128, 128, 128, 0.2);
}