Более эффективное решение CSS-IN-JS

JavaScript CSS

Мы посмотрим на нашу конечную цель, как мы можем описать код:

import React from "react";

export default () => (
  <button inlist="bg:#f00; @md:display:none; hover:radius:8px; radius:4px">
    我是一个按钮
  </button>
);

В этом файле мы «похоже, не вводим какую-либо библиотеку», точно так же, как написание встроенных стилей, реализация описаний стилей, медиа-запросов, псевдоклассов и настройка имен стилей, таких как bg, radius.

cssin

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

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

cssin отличается.

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

На каждое идентичное значение стиля, сгенерированное cssin, можно ссылаться повторно, а не создавать его заново.

идея

Мы много перепробовали, прежде чем использовать cssin, css\less\scss, tailwindCSS, styled-components и другие решения css-in-js. Из них tailwindCSS является наиболее удобным для продакшена, и мы почерпнули из него много вещей и идей, однако эти схемы стилей не особо решили проблему для автора:

Кратко и доходчиво опишу мои стили, не выходя из js; конечно, не отказываясь ни от каких возможностей css

css-in существует для решения таких проблем

предназначен для настройки

cssin Все стили являются пользовательскими, cssin позволяет настраивать их. Это включает в себя цвета, размеры границ, вес шрифта, утилиты интервалов, точки останова, тени и любые стили CSS.

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

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

cssin — это не просто фреймворк CSS-IN-JS, это движок для создания дизайн-систем.

легкий

  • Всего 2кб (gzip)
  • Каждый стиль будет кэшироваться для более высокой производительности обработки стилей.
  • Может использоваться в любой среде, такой как React, Vue, Stencil, которая вам нравится.

Установить

$ npm i cssin --save

Давайте посмотрим на формат отображения

example: navar.workos.top

Перед любой настройкой синтаксис cssin соответствует сдержанному стилю.

import React from "react";
import cssin from "cssin";

// 设置一个全局的 css-value
document.body.style.setProperty("--button-color", "#fff");

export default () => {
  return (
    <div
      className={cssin`background-color:#f66; hover:background-color:#f33; padding:8px; color:#000; border:2px solid #f33; @md:border-radius:4px;`}
    >
      Button
    </div>
  );
};

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

Хорошо, мы, наконец, сделаем так, чтобы описание стиля выглядело так с помощью простой конфигурации:

import React from "react";
import cssin from "cssin";

export default () => {
  return (
    <div className={cssin`btn:#f33, 8px; hover:bg:#f33; @md:radius:4px;`}>
      Button
    </div>
  );
};

Или для предельной краткости:

import React from "react";
import cssin from "cssin";

export default () => {
  return <div className={cssin`button`}>Button</div>;
};

Более экстремально и лаконично, даже пакет cssin опущен:

import React from "react";

export default () => {
  return <div inlist="button">Button</div>;
};

Мы будем идти шаг за шагом, чтобы достичь финального шага.

Может быть, абзац может четко описать cssin

Давайте рассмотрим блок кода в начале:

export default () => {
  return (
    <div
      className={cssin`background-color:#f66; hover:background-color:#f33; padding:8px; color:--button-color; border:2px solid #f33; @md:border-radius:4px;`}
    >
      Button
    </div>
  );
};

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

  • Напишите стили css так же, как встроенные стили, например:background-color: #f66; padding: 4px;
  • Используйте псевдокласс напрямую, псевдокласс находится перед именем атрибута, используйте:Разделить как:hover:background-color=#f33
  • Может напрямую описывать функцию медиа-запросов, используется объект медиа-запроса.@В начале, например:@md:border-radius=4px

Другие правила:

  • Если есть только имя свойства, то это будет компонент, напримерbutton;
  • если значение являетсяОдинпеременные css, такие какcolor:--button-color; равноcolor:var(--button-color);
  • использовать!выражать!important, Такие какcolor: #f00!; равноcolor: #f00 !important
  • Если есть только имя свойства и оно начинается с.В начале это ссылка на собственный стиль CSS, например.button;
  • если он содержит{}, указывая, что это чистый css, он будет вставлен в глобальный стиль, напримерbody { margin:0px; }

Выше приведены все правила cssin

Вот выражение для полного свойства: @[медиа-запрос]:[имя псевдокласса]:[имя атрибута]:[значение атрибута];

Вот полное описание синтаксиса:

// 当媒体查询大于 760px 时、鼠标移入时、描边等于 #f00;
cssin`@md:hover:border:1px solid #f00;`;

Почему бы просто не написать встроенный стиль стиля напрямую?

  1. Стиль стиля не может полностью описать функции css, такие как медиа-запросы, псевдоклассы и т. д. стиль;
  2. Стили не могут настраивать более короткие наборы стилей, комбинации наборов стилей и вложенность;
  3. Встроенный стиль не может ссылаться на классическое значение напрямую, чтобы мы обычно должны писать файлы CSS, установить классное значение и стиль;
  4. И приоритет по умолчанию выше, чем css, при смешанном использовании css и встроенных стилей необходимо обращать внимание на приоритет;

Окончательный сгенерированный cssin по-прежнему выполнен в стиле css, поэтому вышеперечисленных проблем не будет.

Если вы предпочитаете писать атрибут стиля

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

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

Однако следует отметить, что вес атрибутов, написанных в стиле, по умолчанию выше, чем стиль в className, поэтому необходимо добавить!important:

import React from "react";
import cssin from "cssin";

export default () => {
  return (
    <div
      className={cssin`hover:background:#f00 !important;`}
      style={{
        background: "#00f",
        fontSize: "20px"
      }}
    >
      Button
    </div>
  );
};

Так как этот паттерн очень распространен, в cssin его можно использовать!прямое представительство!important:

...
export default () => {
  return (
    <div
      className={cssin`hover:background:#f00!;`}
      style={{
        background: "#00f",
        fontSize: "20px"
      }}
    >
      Button
    </div>
  );
};Z

Настройка пользовательских стилей

Как и многие фреймворки css, cssin позволяет настраивать наборы стилей, чтобы стили можно было описать в более коротких объявлениях.

cssin имеет свойство addSheets для добавления карт стилей.

Мы только что достигли соглашения о следующем:

background-color:#f66; hover:background-color:#f33; padding:4px; color:--button-color; border:2px solid #f33; @md:border-radius:8px;

стали:

btn:#f33, 4px; hover:bg:#f33; @md:radius:8px;

import React from 'react';
import cssin, { addSheets } from 'cssin';

// 添加自定义样式集
addSheets({
  bg: (v) => `{ background-color: ${v}; }`,
  radius: (v) => `{ border-radius: ${v}; }`,
  btn: (v) => {
    const values = v.split(';');
    return {
      `{ background-color: ${values[0]}; padding:${values[1]}; color:var(--button-color); }`
    }
  },
});

// 使用自定义的样式
export default () => {
  return <div className={cssin`btn:#f33, 4px; hover:bg:#f33; @md:radius:8px;`}>Button</div>;
};

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

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

Индивидуальные запросы СМИ

cssin по умолчанию настроен на 4 медиа-запроса уровня размера, и на основе медиа-запросов устройства мы можем переопределить его или создать новые правила.

Обратите внимание, что мы согласны с тем, что только@В начале находится объект медиазапроса

// 默认的媒体查询
addSheets({
  "@sm": (v: string) => `@media (min-width: 640px) {${v}}`,
  "@md": (v: string) => `@media (min-width: 768px) {${v}}`,
  "@lg": (v: string) => `@media (min-width: 1024px) {${v}}`,
  "@xl": (v: string) => `@media (min-width: 1280px) {${v}}`,
  "@ios": (v: string) =>
    `@media (min-width: ${device.isIos ? "0px" : "9999px"}) {${v}}`,
  "@android": (v: string) =>
    `@media (min-width: ${device.isAndroid ? "0px" : "9999px"}) {${v}}`,
  "@native": (v: string) =>
    `@media (min-width: ${device.isNative ? "0px" : "9999px"}) {${v}}`,
  "@pc": (v: string) =>
    `@media (min-width: ${device.isPc ? "0px" : "9999px"}) {${v}}`
});
// 我们覆盖 @md 以及创建一个 @xxl
addSheets({
  "@md": v => `@media (min-width: 800px) {${v}}`,
  "@xxl": v => `@media (min-width: 1920px) {${v}}`
});

Используя медиа-запрос, следующий пример: ширина экрана больше 800 пикселей, ширина кнопки — 200 пикселей, и она скрыта на исходной стороне.

import React from "react";
// 最终只需要包裹一个单词的声明
export default () => {
  return (
    <div inlist="width:100px; height:50px; @md:width:200px; @native:display:none;">
      Button
    </div>
  );
};

пользовательские компоненты

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

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

Разница между ним и пользовательским стилем или медиа-запросом заключается в том, что его значение представляет собой простую строку:

import React from "react";
import cssin, { addSheets } from "cssin";

addSheets({
  // 区别于自定义样式,组件的值是一个字符串,它遵循 cssin 语法,可以调用其他组件和自定义样式
  button: "bgc:#f66; hover:bgc:#f22; padding:8px; color:--button-color;"
});

// 最终只需要包裹一个单词的声明
export default () => {
  return <div className={cssin`button;`}>Button</div>;
};

Обратите внимание, что компоненты нельзя комбинировать с псевдоклассами или медиа-запросами, поскольку компоненты уже содержат псевдоклассы или медиа-запросы.

Переопределить setAttribute

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

Автор не хочет каждый раз обращаться к cssin при написании кода, что слишком громоздко для автора.Если вам тоже так кажется, вы можете использовать cssin'ыcoverAttribute

index.js

import React from "react";
import { coverAttribute } from "cssin";

// 这里我们覆盖inlist对象,它会模拟 className={cssin`...`}
coverAttribute("inlist");

// 请确保 coverAttribute 在 ReactDOM.render 之前执行
ReactDOM.render(<App />, document.getElementById("root"));

App.js

import React from "react";

// 最终只需要一个单词的声明,就像原生声明一样
export const App = () => {
  return (
    <div inlist="full; m:20px;">
      <div inlist="button">Button</div>
    </div>
  );
};

inlint можно использовать с className при условии, что className должно быть объявлено перед inlist

import React from "react";

// 最终只需要一个单词的声明,就像原生声明一样
export const App = () => {
  return (
    <div>
      <div className="app-box" inlist="button">
        Button
      </div>
    </div>
  );
};

Мы должны отметить, что переопределение setAttribute — не очень правильный путь, потому что это вызывает недружелюбие по отношению к другим разработчикам, и другие люди будут очень сбиты с толку, если не узнают, что мы проделали эту черную магию.

Кроме того, не переопределяйте общие свойства, такие как className, которые сделают недействительными другие библиотеки компонентов.

Используйте нативные функции css в javascript

использовать{}Пишите простые сниппеты css

Иногда нам нужно написать простой фрагмент css, мы договариваемся, что если строка содержит{}

В настоящее время входящая строка будет введена в html только как простой стиль css.

import cssin from "cssin";

cssin`
  body {
    margin: 0px;
    background-color: #f5f5f5;
  }

  @media (min-width: 640px) {
    .box {
      background: #f00;
    }
  }
`;

использовать.ссылка на нативный css

Собственный css, определенный в другом месте, можно смешивать с cssin, просто добавьте его перед именем свойства..:

import React from "react";
import cssin from "cssin";

// 使用 .box 引用 css 样式
export default () => {
  return <div inlist="margin:4px; .box">Button</div>;
};

Используйте пресеты для настройки стилей, компонентов, css-значений

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

По умолчанию cssin его не настраивает, при необходимости его можно настроить следующим образом:

import "cssin/commonSheets"; // 引入 sheets集合
import "cssin/commonCSSValues"; // 引入 css-value 集合

Содержимое общих листов:

имя пользовательского стиля стиль карты использовать
dis display dis: flex;
items align-items items: 20px;
justify justify-content justify: start;
self align-self self: center;
content align-content content: end;
z z-index z: 10;
p padding p: 5rem;
px pading-left, padding-right px: 5rem;
py padding-top, padding-bottom py: 5rem;
pl padding-left pl: 5rem;
pt padding-top pt: 5rem;
pr padding-right pr: 5rem;
pb padding-bottom pb: 5rem;
m margin m: 5rem;
mx margin-left, margin-right mx: 5rem;
my margin-top, margin-bottom my: 5rem;
ml margin-left ml: 5rem;
mt margin-top mt: 5rem;
mr margin-right mr: 5rem;
mb margin-bottom mb: 5rem;
w width w: 5rem;
w-min min-width w-min: 5rem;
w-max max-width w-max: 5rem;
w-min-max min-width, max-width w-min-max: 5rem;
h height h: 5rem;
h-min min-height h-min: 5rem;
h-max max-height h-max: 5rem;
h-min-max min-height, max-height h-min-max: 5rem;
b border: ${v} solid; b: 5rem;
bl border-left: ${v} solid; bl: 5rem;
bt border-top: ${v} solid; bt: 5rem;
br border-right: ${v} solid; br: 5rem;
bb border-bottom: ${v} solid; bb: 5rem;
bc border-color bc: #f00;
radius border-radius radius: 2rem;
font font-size font: 1.25rem;
bg background background: #f00;
bgc background-color bgc: #f00;
linear transition: all ${v} linear; linear: 0.3s;
ease transition: all ${v} ease; ease: 0.3s;
ease-in transition: all ${v} ease-in; ease-in: 0.3s;
ease-out transition: all ${v} ease-out; ease-out: 0.3s;
ease-in-out transition: all ${v} ease-in-out; ease-in-out: 0.3s;
move-x transform: translateX(${v}); move-x: 50%;
move-y transform: translateY(${v}); move-y: 50%;
move-z transform: translateZ(${v}); move-z: 50%;
rotate transform: rotate(${v}deg); rotate: 180;
scale transform: scale(${v}, ${v}); scale: 0.7;
Ниже приведены компоненты Компонентам не нужно устанавливать значение
col dis:flex; flex-direction:column; col;
row dis:flex; flex-direction:row; row;
center col; justify:center; items:center; center;
fixed position:fixed; fixed;
static position:static; static;
absolute position:absolute; absolute;
relative position:relative; relative;
sticky position:sticky; sticky;
left left:0px; left;
top top:0px; top;
right right:0px; right;
bottom bottom:0px; bottom;
bold font-weight: bold; bold;

commonCSSValues ​​задает некоторые css-значения, а цвет, классификация размеров и проекция берутся из конфигурации tailwindCSS:

Пример использования пресетов:

import React from "react";
import cssin from "cssin";

// 使用预设的自定义样式和 css-value 配合使用
export default () => {
  return (
    <div
      className={cssin`
        bg:--gray-200; 
        p:--2; 
        font:--font-sm; 
        box-shadow:--shadow-xl
      `}
    >
      Button
    </div>
  );
};

Мы можем просмотреть эти два файла, они представляют собой простые конфигурации с использованием API cssin, и друзья могут предоставить лучшие пользовательские стили и компоненты:

commonSheets.ts

commonCSSValues.ts

накладные расходы на производительность

Несмотря на то, что cssin создает стили css во время выполнения, он имеет чрезвычайно низкую нагрузку на производительность.

Мы видим, что создание повторяется 500 раз, и каждый раз создается около 20 стилей, которые потребляют только1.6ms, это связано с тем, что cssin будет кэшировать общее свойство, а также будет кэшировать стиль css, созданный для подсвойства:

console.time(t);
for (let i = 0; i < 500; i++) {
  cssin(
    `transition:all 0.1s ease-in; box-shadow:--shadow-1lg; hover:box-shadow:--shadow-1md; active:box-shadow:--shadow-sm1;`
  );
  cssin(
    `transition:all 0.2s ease-in; box-shadow:--shadow-2lg; hover:box-shadow:--shadow-2md; active:box-shadow:--shadow-sm2;`
  );
  cssin(
    `transition:all 0.3s ease-in; box-shadow:--shadow-3lg; hover:box-shadow:--shadow-3md; active:box-shadow:--shadow-sm3;`
  );
  cssin(
    `transition:all 0.4s ease-in; box-shadow:--shadow-4lg; hover:box-shadow:--shadow-4md; active:box-shadow:--shadow-sm4;`
  );
}
console.timeEnd(t); // 1.60009765625ms

Теперь, чтобы начать использовать его:

$ npm i cssin --save

С нетерпением ждем Star или внести свой вклад, адрес склада:

GitHub.com/или самое горькое/CSS…