С самого начала истории интернета мы нуждались в стилях для наших сайтов. Многие годы нам для этого служил CSS, развивавшийся в своём темпе. И здесь мы рассмотрим историю его развития.

Думаю, все согласятся с таким определением: CSS используется для описания представления документа, написанного на языке разметки. Также ни для кого не будет новостью, что за время развития CSS стал довольно мощным средством и что для использования в команде нужны дополнительные инструменты.

Дикий CSS


В 1990-е мы увлекались созданием «обалденных» интерфейсов, wow-фактор был самым важным. В те времена ценились inline-стили, и нас не заботило, если какие-то элементы страницы выглядели по-разному. Веб-страницы были милыми игрушками, которые мы насыщали прикольными гифками, бегущими строками и прочими кошмарными (но впечатляющими) элементами, стараясь привлечь внимание посетителей.



Затем мы начали создавать динамические сайты, но CSS оставался оплотом беспредела: каждый разработчик имел собственное представление, как делать CSS. Кто-то боролся со специфичностью (specificity), приводившей к визуальной регрессии при появлении нового кода. Мы полагались на !important, тем самым желая высечь в камне символ нашей воли к тому, чтобы элементы интерфейса выглядели определённым образом. Но вскоре мы поняли:


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


SASS спешит на помощь


SASS превратил CSS в приличный язык программирования, представленный в виде препроцессингового движка, реализующего в таблицах стилей вложенность, переменные, миксины, расширения (extends) и логику. Так что вы можете лучше организовать свои CSS-файлы, и вам доступны несколько способов разложения больших кусков CSS-кода по более мелким файлам. В своё время это стало прекрасным нововведением.

Принцип такой: берётся CSS-код, предварительно обрабатывается, и в общий CSS-пакет помещается скомпилированный файл. Круто? На самом деле не слишком. Через некоторое время стало понятно, что без стратегий и применения лучших методик SASS приносит больше проблем, чем решает.

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

Пока не появился BEM…

BEM и концепция компонентов


BEM стал глотком свежего воздуха. Он позволил нам больше думать о возможности многократного использования и компонентах. По сути, эта технология вывела семантику на новый уровень. Теперь мы могли быть уверены, что className — уникален и что за счёт использования простого соглашения Block, Element, Modifier снижается риск специфического отображения.

Взгляните на пример:

<body class="scenery">
  <section class="scenery__sky">
    <div class="sky [sky--dusk / sky--daytime] [sky--foggy]">
      <div class="sky__clouds"></div>
      <div class="sky__sun"></div>
    </div>
  </section>
  <section class="scenery__ground"></section>
  <section class="scenery__people"></section>
</body>

Если вы проанализируете разметку, то сразу увидите работу соглашения BEM. В коде есть два явных блока: .scenery и .sky. Каждый из них имеет собственные блоки. Лишь у sky есть модификаторы, потому что, к примеру, туман, день или закат — всё это разные характеристики, которые могут применяться к одному и тому же элементу.

Для лучшего анализа взглянем на сопровождающий CSS, содержащий некий псевдокод:

// Block
.scenery {
   //Elements
  &__sky {
    fill: screen;
  }
  &__ground {
    float: bottom; 
  }
  &__people {
    float: center;
  }
}

//Block
.sky {
  background: dusk;
  
  // Elements
  
  &__clouds {
    type: distant;
  }
  
  &__sun {
    strength: .025;
  }
  
  // Modifiers
  &--dusk {
    background: dusk;
    .sky__clouds {
      type: distant;
    }
    .sky__sun {
      strength: .025;
    }
  }
  
  &--daytime {
    background: daylight;
    .sky__clouds {
      type: fluffy;
      float: center;
    }
    .sky__sun {
      strength: .7;
      align: center;
      float: top;
    }
  }
}

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

BEM хорош тем, что делает компоненты уникальными #reusabilityFtw. При таком подходе некоторые паттерны становились очевиднее по мере внедрения нового соглашения в наши старые таблицы стилей.

Но при этом возникли и новые проблемы:

  • Процедура выбора className превратилась в кропотливую задачу.
  • Со всеми этими длинными именами классов разметка стала раздутой.
  • Необходимо явно расширять каждый компонент интерфейса при каждом повторном использовании.
  • Разметка стала излишне семантической.

CSS-модули и локальное пространство видимости


Некоторые проблемы не смогли решить ни SASS, ни BEM. Например, в логике языка отсутствует концепция истинной инкапсуляции. Следовательно, задача выбора имён классов возлагается на разработчика. Чувствовалось, что проблему можно было решить с помощью инструментов, а не соглашений.

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

CSS-модули быстро стали популярны в экосистеме React, и сегодня они используются во многих проектах. У них есть свои преимущества и недостатки, но в целом это хорошая, полезная парадигма.

Однако… Сами по себе модули не решают ключевых проблем CSS, они лишь показывают нам способ локализации определений стилей: умный способ автоматизации BEM, чтобы нам больше не пришлось заниматься выбором имён классов (ну или хотя бы заниматься этим реже).

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

Вот как выглядит локальный CSS:

@import '~tools/theme';

:local(.root) {
  border: 1px solid;
  font-family: inherit;
  font-size: 12px;
  color: inherit;
  background: none;
  cursor: pointer;
  display: inline-block;
  text-transform: uppercase;
  letter-spacing: 0;
  font-weight: 700;
  outline: none;
  position: relative;
  transition: all 0.3s;
  text-transform: uppercase;
  padding: 10px 20px;
  margin: 0;
  border-radius: 3px;
  text-align: center;
}


@mixin button($bg-color, $font-color) {
  background: $bg-color;
  color: $font-color;
  border-color: $font-color;

  &:focus {
    border-color: $font-color;
    background: $bg-color;
    color: $font-color;
  }

  &:hover {
    color: $font-color;
    background: lighten($bg-color, 20%);
  }

  &:active {
    background: lighten($bg-color, 30%);
    top: 2px;
  }
}

:local(.primary) {
  @include button($color-primary, $color-white)
}

:local(.secondary) {
  @include button($color-white, $color-primary)
}

Это просто CSS, а его главное отличие в том, что все className с добавлением :local будут генерировать уникальные имена классов наподобие:

.app–components–button–__root?—?3vvFf {}

Можно сконфигурировать генерируемый идентификатор с помощью параметра запроса localIdentName. Пример: css–loader?localIdentName=[path][name]–––[local]–––[hash:base64:5] для облегчения отладки.

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

Полное вливание CSS в JavaScript с помощью styled-components


Styled-components — это визуальные примитивы, работающие как обёртки. Они могут быть привязаны к конкретным HTML-тегам, которые всего лишь обёртывают дочерние компоненты с помощью styled-components.

Этот код поможет понять идею:

import React from "react"
import styled from "styled-components"
// Simple form component

const Input = styled.input`
  background: green
`

const FormWrapper = () => <Input placeholder="hola" />

// What this compiles to:
<input placeholder="hola" class="dxLjPX">Send</input>

Всё очень просто: styled-components использует для описания CSS-свойств шаблонное буквенное обозначение (template literal notation). Похоже, что команда разработчиков попала в точку, объединив возможности ES6 и CSS.

Styled-components предоставляет очень простой паттерн для многократного использования и полностью отделяет интерфейс от компонентов функциональности и структуры. Создаётся API, имеющий доступ к нативным тегам — либо в браузере как HTML, либо нативно используется React Native.

Вот как передаются в styled-components кастомные свойства (или модификаторы):

import styled from "styled-components"

const Sky = styled.section`
  ${props => props.dusk && 'background-color: dusk' }
  ${props => props.day && 'background-color: white' }
  ${props => props.night && 'background-color: black' }
`;

// You can use it like so:
<Sky dusk />
<Sky day />
<Sky night />
  

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

Основной интерфейс может многократно использоваться кем угодно


Стало быстро понятно, что ни CSS-модули, ни styled-components сами по себе не были идеальным решением. Необходим некий паттерн, чтобы всё это эффективно работало и масштабировалось. Такой паттерн возник из определения, чем является компонент, и его полного отделения от логики. Это позволило создать основные компоненты (core components), единственное предназначение которых — стили.

Пример реализации таких компонентов с помощью CSS-модулей:

import React from "react";

import classNames from "classnames";
import styles from "./styles";

const Button = (props) => {
  const { className, children, theme, tag, ...rest } = props;
  const CustomTag = `${tag}`;
  return (
    <CustomTag { ...rest } className={ classNames(styles.root, theme, className) }>
      { children }
    </CustomTag>
  );
};

Button.theme = {
  secondary: styles.secondary,
  primary: styles.primary
};

Button.defaultProps = {
  theme: Button.theme.primary,
  tag: "button"
};

Button.displayName = Button.name;

Button.propTypes = {
  theme: React.PropTypes.string,
  tag: React.PropTypes.string,
  className: React.PropTypes.string,
  children: React.PropTypes.oneOfType([
    React.PropTypes.string,
    React.PropTypes.element,
    React.PropTypes.arrayOf(React.PropTypes.element)
  ])
};


export default Button;

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

Теперь ваш компонент можно применить так:

import React from "react"
import Button from "components/core/button"

const = Component = () => <Button theme={ Button.theme.secondary }>Some Button</Button>

export default Component

Продемонстрирую аналогичный пример полной реализации кнопки с помощью styled-components:

import styled from "styled-components";

import {
  theme
} from "ui";

const { color, font, radius, transition } = theme;

export const Button = styled.button`
  background-color: ${color.ghost};
  border: none;
  appearance: none;
  user-select: none;
  border-radius: ${radius};
  color: ${color.base}
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: ${font.base};
  font-weight: bold;
  outline: none;
  position: relative;
  text-align: center;
  text-transform: uppercase;
  transition:
    transorm ${transition},
    opacity ${transition};
  white-space: nowrap;
  width: ${props => props.width ? props.width : "auto"};

  &:hover,
  &:focus {
    outline: none;
  }

  &:hover {
    color: ${color.silver};
    opacity: 0.8;
    border-bottom: 3px solid rgba(0,0,0,0.2);
  }

  &:active {
    border-bottom: 1px solid rgba(0,0,0,0.2);
    transform: translateY(2px);
    opacity: 0.95;
  }

  ${props => props.disabled && `
    background-color: ${color.ghost};
    opacity: ${0.4};
    pointer-events: none;
    cursor: not-allowed;
  `}

  ${props => props.primary && `
    background-color: ${color.primary};
    color: ${color.white};
    border-color: ${color.primary};

    &:hover,
    &:active {
      background-color: ${color.primary}; 
      color: ${color.white};
    }
  `}

  ${props => props.secondary && `
    background-color: ${color.secondary};
    color: ${color.white};
    border-color: ${color.secondary};

    &:hover,
    &:active {
      background-color: ${color.secondary}; 
      color: ${color.white};
    }
  `}
`;

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

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

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

Звучит превосходно. Казалось бы, нужно следовать этому паттерну. Вместе с ним мы начали искать и другие полезные решения.

Получатели свойств


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

// Prop passing Shorthands for Styled-components
export const borderProps = props => css`
  ${props.borderBottom && `border-bottom: ${props.borderWidth || "1px"} solid ${color.border}`};
  ${props.borderTop && `border-top: ${props.borderWidth || "1px"} solid ${color.border}`};
  ${props.borderLeft && `border-left: ${props.borderWidth || "1px"} solid ${color.border}`};
  ${props.borderRight && `border-right: ${props.borderWidth || "1px"} solid ${color.border}`};
`;

export const marginProps = props => css`
  ${props.marginBottom && `margin-bottom: ${typeof (props.marginBottom) === "string" ? props.marginBottom : "1em"}`};
  ${props.marginTop && `margin-top: ${typeof (props.marginTop) === "string" ? props.marginTop : "1em"}`};
  ${props.marginLeft && `margin-left: ${typeof (props.marginLeft) === "string" ? props.marginLeft : "1em"}`};
  ${props.marginRight && `margin-right: ${typeof (props.marginRight) === "string" ? props.marginRight : "1em"}`};
  ${props.margin && `margin: ${typeof (props.margin) === "string" ? props.margin : "1em"}`};
  ${props.marginVertical && `
    margin-top: ${typeof (props.marginVertical) === "string" ? props.marginVertical : "1em"}
    margin-bottom: ${typeof (props.marginVertical) === "string" ? props.marginVertical : "1em"}
  `};
  ${props.marginHorizontal && `
    margin-left: ${typeof (props.marginHorizontal) === "string" ? props.marginHorizontal : "1em"}
    margin-right: ${typeof (props.marginHorizontal) === "string" ? props.marginHorizontal : "1em"}
  `};
`;
// An example of how you can use it with your components

const SomeDiv = styled.div`
  ${borderProps}
  ${marginProps}
`

// This lets you pass all borderProps to the component like so:

<SomeDiv borderTop borderBottom borderLeft borderRight marginVertical>

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

Это позволяет не хардкодить границы для каждого конкретного компонента, что экономит нам кучу времени.

Placeholder / Функциональность наподобие миксина


В styled-components можно использовать весь потенциал JS, чтобы функции были не просто получателями свойств и чтобы разные компоненты могли совместно использовать код:

// Mixin like functionality

const textInput = props => `
  color: ${props.error ? color.white : color.base};
  background-color: ${props.error ? color.alert : color.white};
`;

export const Input = styled.input`
  ${textInput}
`;

export const Textarea = styled.textarea`
  ${textInput};
  height: ${props => props.height ? props.height : '130px'}
  resize: none;
  overflow: auto;
`;

Компоненты макета


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

import styled from "styled-components";
import {
  theme,
  borderProps,
  sizeProps,
  backgroundColorProps,
  marginProps
} from "ui";

const { color, font, topbar, gutter } = theme;

export const Panel = styled.article`
  ${marginProps}
  padding: 1em;
  background: white;
  color: ${color.black};
  font-size: ${font.base};
  font-weight: 300;
  ${props => !props.noborder && `border: 1px solid ${color.border}`};
  width: ${props => props.width ? props.width : "100%"};
  ${props => borderProps(props)}
  transition: 
    transform 300ms ease-in-out,
    box-shadow 300ms ease-in-out,
    margin 300ms ease-in-out;
  box-shadow: 0 3px 3px rgba(0,0,0,0.1);

  ${props => props.dark && `
    color: ${color.white};
    background-color: ${color.black};
  `}

  &:hover {
    transform: translateY(-5px);
    box-shadow: 0 6px 3px rgba(0,0,0,0.1);
  }
`;

export const ScrollView = styled.section`
  overflow: hidden;
  font-family: ${font.family};
  -webkit-overflow-scrolling: touch;
  overflow-y: auto;
  ${props => props.horizontal && `
    white-space: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    `
  }
  ${props => sizeProps(props)}
`;

export const MainContent = styled(ScrollView)`
  position: absolute;
  top: ${props => props.topbar ? topbar.height : 0};
  right: 0;
  left: 0;
  bottom: 0;
  font-size: ${font.base};
  padding: ${gutter} 3em;

  ${props => props.bg && `
    background-color: ${props.bg};
  `}
`;

export const Slide = styled.section`
  ${backgroundColorProps}
  font-weight: 400;
  flex: 1;
  height: ${props => props.height ? props.height : "100%"};
  width: ${props => props.width ? props.width : "100%"};
  justify-content: center;
  flex-direction: column;
  align-items: center;
  text-align: center;
  display: flex;
  font-size: 3em;
  color: ${color.white};
`;

export const App = styled.div`
  *, & {
    box-sizing: border-box;
  }
`;

Компонент <ScrollView /> получает в виде свойств ширину и высоту, а также свойство горизонтали для появляющейся внизу полосы прокрутки.

Вспомогательные компоненты


Они облегчают нам жизнь и позволяют активно заниматься многократным использованием. Здесь мы храним все часто используемые паттерны. Вот некоторые из полезных для меня вспомогательных компонентов:

import styled, { css } from "styled-components";

import {
  borderProps,
  marginProps,
  backgroundColorProps,
  paddingProps,
  alignmentProps,
  positioningProps,
  sizeProps,
  spacingProps,
  theme
} from "ui";

const { screenSizes } = theme;

export const overlay = `
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0,0,0,0.5);  
`;

// You can use this like ${media.phone`width: 100%`}

export const media = Object.keys(screenSizes).reduce((accumulator, label) => {
  const acc = accumulator;
  acc[label] = (...args) => css`
    @media (max-width: ${screenSizes[label]}em) {
      ${css(...args)}
    }
  `;
  return acc;
}, {});

// Spacing

export const Padder = styled.section`
  padding: ${props => props.amount ? props.amount : "2em"};
`;

export const Spacer = styled.div`
  ${spacingProps}
`;

// Alignment

export const Center = styled.div`
  ${borderProps}
  ${marginProps}
  ${backgroundColorProps}
  ${paddingProps}
  ${alignmentProps}
  ${positioningProps}
  ${sizeProps}
  text-align: center;
  margin: 0 auto;
`;

// Positioning

export const Relative = styled.div`
  ${props => borderProps(props)};
  position: relative;
`;

export const Absolute = styled.div`
  ${props => marginProps(props)};
  ${props => alignmentProps(props)};
  ${props => borderProps(props)};
  position: absolute;
  ${props => props.right && `right: ${props.padded ? "1em" : "0"}; `}
  ${props => props.left && `left: ${props.padded ? "1em" : "0"}`};
  ${props => props.top && `top: ${props.padded ? "1em" : "0"}`};
  ${props => props.bottom && `bottom: ${props.padded ? "1em" : "0"}`};
`;

// Patterns
export const Collapsable = styled.section`
  opacity: 1;
  display: flex;
  flex-direction: column;
  ${props => props.animate && `
    transition: 
      transform 300ms linear,
      opacity 300ms ease-in,
      width 200ms ease-in,
      max-height 200ms ease-in 200ms;
    max-height: 9999px;
    transform: scale(1);
    transform-origin: 100% 100%;

    ${props.collapsed && `
      transform: scale(0);
      transition: 
        transform 300ms ease-out,
        opacity 300ms ease-out,
        width 300ms ease-out 600ms;
    `}
  `}

  ${props => props.collapsed && `
    opacity: 0;
    max-height: 0;
  `}
`;

export const Ellipsis = styled.div`
  max-width: ${props => props.maxWidth ? props.maxWidth : "100%"};
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
`;

export const Circle = styled.span`
  ${backgroundColorProps}
  display: inline-block;
  border-radius: 50%;
  padding: ${props => props.padding || '10px'};
`;

export const Hidden = styled.div`
  display: none;
`;

Тема


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

export const theme = {
  color: {
    primary: "#47C51D",
    secondary: '#53C1DE',
    white: "#FFF",
    black: "#222",
    border: "rgba(0,0,0,0.1)",
    base: "rgba(0,0,0,0.4)",
    alert: '#FF4258',
    success: 'mediumseagreen',
    info: '#4C98E6',
    link: '#41bbe1'
  },
  icon: {
    color: "gray",
    size: "15px"
  },
  font: {
    family: `
    -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    Roboto,
    Helvetica,
    Arial,
    sans-serif,
    'Apple Color Emoji',
    'Segoe UI Emoji',
    'Segoe UI Symbol'`,
    base: '13px',
    small: '11px',
    xsmall: '9px',
    large: '20px',
    xlarge: '30px',
    xxlarge: '50px',
  },
  headings: {
    family: 'Helvetica Neue',
  },
  gutter: '2em',
  transition: '300ms ease-in-out'
};

export default theme;

Преимущества


  • Вся мощь JS у нас в руках, полное взаимодействие с интерфейсом компонента.
  • Не нужно с помощью className связывать компоненты и стили (это делается без вашего участия).
  • Огромное удобство разработки, не приходится забивать себе голову именами классов и их привязкой к компонентам.

Недостатки


  • Ещё нужно тестировать на реальных проектах.
  • Создано для React.
  • Проект очень молодой.
  • Тестирование надо проводить через aria-label или с помощью className.

Заключение


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

Такой подход необходим для корректного масштабирования, и его можно достичь даже при условии использования чистого CSS и BEM. Всё дело лишь в объёме работы и LOC, необходимых для каждой реализации. В целом styled-components можно назвать подходящим решением для большинства React-проектов. Его ещё нужно активно тестировать, но проект выглядит многообещающе.
Поделиться с друзьями
-->

Комментарии (40)


  1. iXCray
    20.01.2017 12:51
    +8

    Жепячество какое-то о_О


  1. bromzh
    20.01.2017 12:53
    +7

    Styled components — так-себе эволюция. Вторая ветка пока не зарелизилась, а в первой были порой детские проблемы: https://habrahabr.ru/company/jugru/blog/315772/#comment_9923636


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


  1. Prometheus
    20.01.2017 12:55
    +10

    В итоге что?
    В итоге — все эти пре/пост процессоры никакого отношения к CSS не имеют, они всего лишь «организую» декларации в структуре проекта. Никакая эволюция CSS тут не значится, эволюционируют инструменты.

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

    А вот когда программисты занимаются версткой — вот тогда начинается весь этот зоопарк, который вместо ПРОСТОТЫ с дальнейшей поддержкой, дает лишнюю головную боль. В CSS не должно быть никаких переменных и вычислений, у него декларативная роль.

    Пишите на чистом CSS, а инструментам отведите роль пространства имен и сборщика — тогда будет всем счастье…


    1. shapovalov_org
      20.01.2017 13:41
      -2

      Точно, эволюция CSS это CSS от версии 1 до версии 3, и не нужно из CSS делать язык программирования усложняя простое! Он и так прост и шаблонен до не куда, используйте фреймворки CSS для облегчения процесса верстки типа Bootstrap, остальные инструменты по моей практике лишь усложняют процесс


      1. kana-desu
        20.01.2017 15:18
        -1

        и не нужно из CSS делать язык программирования усложняя простое!

        А это разве усложнение? Зачем это разделение на верстку и программирование? Почему бы не думать не в масштабах сайта, а в масштабах компонентов, где каждый небольшой элемент пишется одним человеком, который пишет и логику, и стили, и верстку? А раз он пишет все, так почему бы не писать это в одном месте (!= в одном файле) единообразно (т.е. все в виде react-компонентов)? При этом мы получаем еще и реактивные стили.

        А вот сама реализация styled-components мне не нравится, сейчас работаю над чем-то похожим, но для clojure


        1. denismaster
          20.01.2017 15:33
          +6

          А если жизнь крутится не только вокруг React?)


          1. kana-desu
            20.01.2017 15:38

            То в этом случае я могу сказать, что понятие компонент есть не только в react) Веб-компоненты с shadow-dom, angular 2 тоже вроде как на компонентах, amp, да даже старые добрые jquery-виджеты.


            1. denismaster
              20.01.2017 15:58

              Вообще, лет так эдак через 10 джуны будут бегать по форумам, искать готовые компоненты для какой-то задачи, все как в свои времена было в Delphi


        1. Prometheus
          20.01.2017 17:22
          +2

          >>Зачем это разделение на верстку и программирование?

          Ну, вы же знаете, есть специализация. В правильно организованном проекте, у каждого своя зона ответственности. Менеджер проекта ставит задачи на дизайнера, на верстальщика, на программиста, на тестировщика и т.п.
          Или может, вы хотите и можете, каждый из уровней делать самостоятельно? Хватит знаний и опыта?

          >>а в масштабах компонентов

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

          >>так почему бы не писать это в одном месте

          Ой — все в одном месте, это мы уже проходили. Предлагаете опять мешать все в кучу — и логику и представление? Ну, как так :)


    1. webhtmlcssjsdev
      24.01.2017 12:36
      +1

      Абсолютно согласен. Все же не реактом единым так сказать. А все что тут по напридумывали — весь этот css in js жесть полная. Пре/пост процессоров более чем достаточно для решения большинства задач становящихся перед верстальщиком — ИМХО.
      И еще такой момент — вот автор статьи хоть немного думал о том как этот АД с styled-components будет использовать обычный верстальщик который придет в компанию. Да там же черт ногу сломит. А если у специалиста огромный опыт в верстке и глубинное понимание тонкостей но слабый или вообще мизерный опыт в js — для такого специалиста такой подход вообще закрыт тогда. В противовес мне могу сейчас сказать, что будут брать программиста — но я ни за что не поверю что даже самый обалденный программист будет знать верстку так же хорошо как верстальщик с большим опытом реальных проектов.


    1. PsyHaSTe
      24.01.2017 15:48

      На чистом CSS писать больно хотя бы из-за двух вещей: отсутствие автопрефиксера и отсутствие переменных.


      1. Prometheus
        25.01.2017 19:33

        1) Если вы используете Gulp, просто берете и проходитесь по css-файлу autoprefixer`ом

        2) Если вам нужны переменные, тогда используйте препроцессоры.
        Мне переменные не нужны, на деле не было ни одного случая, чтобы приходилось потом брать и менять их значения…


        1. PsyHaSTe
          26.01.2017 01:49

          Так и так проходиться препроцессором. Так почему бы не писать на более удобном языке? SASS/LESS/whatever? Или от того, что входным файлом гульпа будет css он стал менее препроцессорным?


          1. Prometheus
            26.01.2017 11:39

            если вам нравится мешанина, химера = «css+синтаксис препроцессора+многоуровневая нотация» — это дело вашего вкуса.

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

            чем проще — тем лучше, особенно с поддержкой и дальнейшим развитием проекта.


  1. MrCheater
    20.01.2017 12:58
    -1

    Autoprefixer на этапе компиляции работает?
    Если нет, тогда CSS-Modules на голову выше.


  1. MikhailMKZ
    20.01.2017 13:00

    Спасибо за статью!
    Дополнение: одним из авторов styled-components является Max Stoiber, с которым тут недавно публиковалось интервью


  1. justboris
    20.01.2017 13:14
    +7

    Статья называется "Эволюция CSS", но при этом больше половины статьи нам просто рекламируют очередной модный способ писать стили без CSS.


  1. justboris
    20.01.2017 13:15

    И еще вопрос к переводчику:
    можно ли считать, что публикация перевода в блоге Mail.ru означает, что компания рекомендует такой подход и в будущем тоже планирует разрабатывать свои интерфейсы с использованием styled-components?


    1. AloneCoder
      20.01.2017 13:21
      +3

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


      1. justboris
        20.01.2017 13:31
        +1

        Спасибо за ответ!


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


  1. Jaromir
    20.01.2017 14:04

    А может пора остановиться, перестать изобретать новые CSS-перверсии и терпеливо подождать shadow dom? Недолго вроде осталось


    1. bromzh
      20.01.2017 14:14
      +2

      Модный нынче реакт не особо дружит с shadow-dom (да и стандартами W3C в целом), вот и придумывают подобное.


      1. Jaromir
        20.01.2017 14:19
        +2

        Чую, переход с реакта на веб компоненты будет большой общей болью году так в 18-19


  1. Ronnie_Gardocki
    20.01.2017 14:54
    +4

    2017 год, а у людей сложность стилей в препроцессорах заканчивается на примитивном нестинге. Сколько не слежу за этим бредовым хайпом вокруг css in js, все никак не могу найти ни одного внятного примера более менее сложных стилей. Тут даже от примитивных примеров глаза вытекают, а как интересно будет выглядеть цикл по 10+ элементам, с использованием nth-child, где внутри будут использоваться миксины, «обратные» переопределения на основе классов на далеком родителе и так далее?

    Ну не пользовались этим люди SASS'ом на полную катушку, ну зачем они пытаются другим впарить что вот этот франкенштейн чем то лучше, если он пока что абсолютно точно уступает по всем фронтам, когда дело доходит реальной препроцессорной css магии.


    1. anttoshka
      21.01.2017 14:38

      А как вы используете SASS кроме обычной вложенности и переменных? Был бы рад, если бы подсказали как улучшить свою жизнь с Sass =)
      У меня получилось только небольшие условия строить для небольшого плагина.


      1. Ronnie_Gardocki
        21.01.2017 15:41

        Вот моя демка с примером — http://codepen.io/suez/pen/AXQaEg
        — простые mixin'ы для оверрайда свойств на основании класса у удаленного родителя.
        — множество обычных переменных с таймингами и так далее.
        — scoped переменные внутри элементов и циклов для удобства.
        — BEM naming с помощью &__ и подобных вещей.
        — циклы с интерполяцией и подобными плюшками.

        JS в демке лишь добавляет/убирает 1 класс к двум элементам.


  1. iDzyubin
    20.01.2017 16:13

    SASS превратил CSS в приличный язык программирования
    Язык программирования? Что, простите?


  1. DenimTornado
    20.01.2017 16:23
    +2

    Блин, отстаньте от JS! JSX, styled-components, что дальше, backend..? Oh..wait


    1. Jaromir
      20.01.2017 16:59
      +3

      > что дальше

      Всё это вместе в большом WASM-блобе


  1. dom1n1k
    20.01.2017 16:36
    -1

    <div class="sky [sky--dusk / sky--daytime] [sky--foggy]">

    Скобочки, слеши — это что вообще такое, следы какого-то фреймворка?
    Или это автор просто в вольном стиле показал необязательные параметры?


  1. Mexis
    20.01.2017 19:58
    +2

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

    Не говорю, что нет приимуществ, но их мало для использования в практике.
    В моём случае код пишется медленнее исли использовать пре/пост процессоры.

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


  1. SPAHI4
    20.01.2017 21:45
    +3

    Каждый день появляются новые способы написания стилей. Это все, конечно, круто, но есть единственный верный способ инкапсуляции CSS — это Shadow DOM. Тут все будет работать как надо, даже если виджет вставлен на сторонний сайт. Единственная проблема — поддержка браузеров.


  1. novoxudonoser
    21.01.2017 03:47
    +2

    Круто, давайте убьём клиент, слабому китайскому смартфону за 50$ будет очень весело долго обрабатывать всю эту мешанину до отрисовки страницы. Можно конечно отрендерить на ноде и отдать клиенту, но всё равно боли будет у клиента много. Такое ощущения что эти люди свято верят что у каждого их пользователя i7 + ssd + свободные гигов 16 опреативки.


  1. PaulZi
    23.01.2017 09:24
    +1

    Какой-то совсем JSS получился.


    1. justboris
      23.01.2017 12:47
      +2

      Вы удивитесь, то библиотека с именем JSS уже существует: https://github.com/cssinjs/jss


      И в чем-то даже лучше, чем описанное в статье


    1. Mexis
      30.01.2017 13:56

      PPAP прям


  1. ehots
    25.01.2017 13:34

    Вот сижу такой пропитываюсь знаниями и где то недрах мозга тихий голос шепчет «а ты уверен что это истинна и стоит делать так как тут написано?»
    Я учусь программированию в веб (css,html,js) уже пробовал как то заниматься этим пару лет назад на уровне код в блокноте, о фреймворках, саблайме, бэм и прочих радостях узнал и начал осваиваться пару месяцев назад. Что стоит из статьи принять к сведению и пытаться учить и пользовать?
    p.s. мой первый коммент на хабре, не кидайте тапками пожалуйста.


    1. zo0m
      26.01.2017 13:39
      +2

      Учите постепенно, начиная с базовых вещей: CSS в частности, а вот когда вам станет его не хватать, поймете о чем речь в статье.
      Те проблемы которые решаются выше — пока еще не ваши проблемы :) Иначе рискуете примкнуть к «культу карго», т.е. повторять за другими не понимая в своих действиях смысла.


      1. ehots
        26.01.2017 13:46

        Спасибо большое за совет, я вроде и сам понимаю что нужно с азов учить, но хочется то все и сразу. А как только начинаешь что то интересное читать, всякие angular.js, node.js, bootstrap, html5, websockets, и прочее прочее, это начинает засасывать, и вот ты сидишь из ушей дым и понимаешь что ничего ты не понимаешь…
        Но желание разобраться и научиться все еще никуда не пропадет.


        1. IT_Hound
          27.01.2017 00:08

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