Генерация CSS: от LESS к Stylus

Post on 28-Nov-2014

655 views 8 download

description

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

Transcript of Генерация CSS: от LESS к Stylus

Генерация CSSОт LESS к Stylus, от фреймворка — к тулкиту

Interlabs

23 июня 2014

1 / 43

О чем речьДва года LESS + Boot.LESS, пора двигаться дальше:

• IE7 — давай, до свидания1

• адаптивный дизайн→ responsive design• исправление допущенных проектировочных ошибок

LESS — хорошо, но хотелось бы:

• более компактный код• ближе по духу к CSS (просто свойства внутри правил)• простые расширения на JavaScript

Новый препроцессор + новый фреймворк1http://theie7countdown.com/ 2 / 43

Именование классов.namespace-element-subelement--modifier

Базовая модель остается без изменений, улучшаем:

• отказываемся от префикса app- — уменьшаем объем CSS• классы состояний: is-active, is-valid и т.д., всегдаопределяются только вместе с другими классами

• несколько стандартных классов (block, block-group и т.д.)

.app-top-menu→ .top-menu

.top-menu-item–active→ .top-menu-item.is-active

3 / 43

box-sizing: border-boxСамый главный выигрыш от отказа от IE7:

• упрощает работу с сетками, особенно с тянущимися• существенно упрощает стилизацию форм• уменьшает количество уровней вложенности DOM• если очень надо IE7 — отдельные стили и (или) polyfill

margin

border

padding

content

box-sizing: content-box

margin

border

padding

content

box-sizing: border-box

Де-факто стандарт современных CSS-фреймворковBootstrap, Foundation, Pure и т.д.

4 / 43

Новый препроцессор

http://learnboost.github.io/stylus/

5 / 43

Stylus• вложенные правила — как в LESS• синтаксис, основанный на отступах (как в Python)• минимальный синтаксис (но с осторожностью)• transparent mixins: макросы как пользовательскиеCSS-свойства (killer feature)

• циклы, хеши, блоки, списки параметров• простая расширяемость на JavaScript• абстрактные классы, расширяемость классов• единое пространство имен (как и в CSS)

Современный LESS функционально не уступает, но сложнее имногословнее, старый LESS — многое отсутствовало.

6 / 43

Stylus: вложенные правилаПохоже на LESS, но отступы определяют вложенность:

ul, ol, li // через запятуюmargin: 0

.block // или списком

.block-groupdisplay: block

.menu-itema

text-decoration: none&:hover // & = parent/.is-hover // / = root

text-decoration: underline

7 / 43

Stylus: переменные и макросыbaseline ?= 8px // переменная, значение по умолчаниюsans-16 = { // переменная-хеш

font-size: 16px,line-height: 24px

}text-lines(n) // функция

return (n*baseline)

margin-top(s) // переопределение стандартного свойстваif ’’ == unit(s) and s != 0margin-top: text-lines(s)

elsemargin-top: s

text-style(style) // макро/пользовательское свойствоfont-size: style.font-size if style.font-sizeline-height: style.line-height if style.line-height

bodytext-style: sans-16 // font-size: 16pxmargin-top: 2 // line-height: 16px

// margin-top: 16px8 / 43

Stylus: управляющие конструкцииsupport-ie = true

.inlinedisplay: inline-blockif support-ie // префиксный if

zoom: 1

vertical-size(num, adjust = 0)adjust = 0 if ’’ == unit(adjust) // постфиксный ifreturn (vertical-baseline*num - adjust) // return

// постфиксный unless (if (!())name = font-path + "/" + files unless match("^(http://|/)", files)

// Циклыscale = 8px 10px 12px 16px 20pxfor s, i in scale

size-{i}font-size: s

9 / 43

Stylus: блоки кодаmedia(query = any)

if query == any{block} // передаваемый блок

else@media query

{block}

+media(above-480) // если вызов начинается с +,.sidebar // то передается вложенный блок

width: 40%

code = // можно присвоить переменнойwidth: 20pxheight: 20px

.style // и выполнить подстановку{code}

10 / 43

Stylus: @extendПозволяет выполнять композицию селекторов:

.message { // .message, .warning {padding: 10px; // padding: 10px;border: 1px solid #eee; // border: 1px solid #eee;

} // }//

.warning { // .warning {@extend .message; // color: #E2E21E;color: #E2E21E; // }

}

• появился в SASS, раньше не было в LESS теперь есть и там• может существенно сократить размер CSS• применяя, помним о размере генерируемых селекторов• mixin() vs @extend — индивидуально для каждого случая

11 / 43

Stylus: @extend// Множественный @extend:.a // .a, .c {

color: red // color: red;.b // .b, .c {

width: 100px // width: 100px;.c // }

@extend .a, .b // .c {height: 200px // height: 200px;

// }

// Абстрактный класс (placeholder)$block // .content-block,

display: block // .menu-item {float: left // dispay: block

.content-block // float: left;@extend $block // }

.menu-item // .menu-item {@extend $block // color: blue;color: blue // }

12 / 43

Стандарт кодирования Stylus

• используем пробельные отступы• используем : для разделения свойства и значения(синтаксис позволяет не использовать)

• имена переменных без специальных символов, $ — дляабстрактных классов

• - для разделителей в именах• вызов макросов — в виде свойств• вызов макросов самого верхнего уровня — в виде явноговызова macro()

• внутренние макросы — с префиксом -• список параметров через пробел, если не создает проблем

Главный принцип — семантическое сходство с CSS

13 / 43

Новый фреймворк тулкитBare

• набор макросов Stylus, часть взята из Nib• тулкит — (почти) не навязывает свою структуру,предоставляет средства для реализации необходимойструктуры, convention over configuration

• макросы реализуют дополнительных свойств CSS• единое пространство имен с префиксами дополнительныхсвойств и переменных

• responsive design + IE8

Семантически стараемся расширить CSS, а не строить над нимсложную систему макросов.

14 / 43

Модульная структура• модуль — отдельный файл .styl• модули могут объединяться в более крупные модели черезrequire в index.styl

• имя модуля — префикс для имен переменных и макросовмодуля (и следовательно, пользовательских CSS-свойств)

• загрузка модуля не приводит к генерации каких-либоCSS-классов, только к загрузке макросов

• генерация классов (если есть) — в виде отдельного макроса• use-имя-модуля — стандартное именования макросагенерации классов

@require ’normalize’ // классы не генерируютсяuse-normalize() // явная генерация классов

15 / 43

vendor + css3• просто пишем обычный CSS, без специальных макросов• свойства CSS3 автоматически транслируются вvendor-свойства, если это необходимо

// Stylus /* CSS */.button .button {

border-radius: 4px -webkit-border-radius: 4px;-moz-border-radius: 4px;border-radius: 4px;

}

Реализация:макро border-radius()→ макро vendor()→ vendor.js,при использовании мы даже не замечаем реализации.

16 / 43

normalize + resetЧистый reset недостаточно, чистый normalize — избыточныйсброс для элементов, не относящихся к основному контенту.

Используем комбинацию:

• normalize для нормализации различий и устранениямелких проблем

• reset для сброса отступов контентных элементов• для контентных элементов настраиваем типографику так,как нам необходимо

use-normalize() // - генерация правил нормализацииuse-reset() // - генерация правил сброса

// Или просто...use-bare()

17 / 43

Вертикальный ритм

aa

margin

padding

• все вертикальные размеры кратны базовому шагу• контент выравнивается за счет кратной высоты строки• border компенсируется корректировкой внутреннегоили внешнего отступа

• вложенный элементы в пределах разной line-heightмогут иметь различную относительную высоту

• display: inline-block может упростить сложныеслучаи

• выравнивание картинок переменного размера —жестко определенный контейнер или JavaScript

• базовый шаг — половина или треть высоты строкибазового шрифта — от 8px до 11px

18 / 43

vertical + textВертикальный ритм важен, необходимо упростить реализацию.

vertical-baseline = 8px // определяем вертикальный шаг

Переопределяем margin, padding, height для поддержкиunitless единиц измерений — количества вертикальных единиц:

margin-top: 2 // margin-top: 16px (2*8px)height: 10 // height: 80px (10*8px)padding: 1 20px 2 // padding: 8px 20px 16px

// Если необходимо, отступы можно корректировать:margin-top: 2 2px // margin-top: 14px (2*8px - 2px)

Расширяем CSS вместо громоздкого набора макросов19 / 43

vertical + textРитм = кратный line-height + адекватный размер шрифта.

Вместо индивидуального пересчета метрик (как раньше)определим набор текстовых стилей для всего проекта.

sans-medium = { // пример определения текстового стиляfont-family: sans-serif,font-size: 18px, // нормально вписывается в line-heightline-height: 24px, // кратно базовому шагуfont-variant: small-caps

}

.sidebartext-style: sans-normal // применяем стиль целиком

.sidebar-titletext-metrics: sans-medium // применяем метрику, шрифт наследуется

20 / 43

vertical + text• стиль определяет не полный внешний вид, а базовуютипографику элемента

• вариации в inline-элементах в пределах line-height —относительные размеры через em

• в процессе дизайна стараемся минимизироватьколичество стилей

• определения стилей могут отличаться для разныхмедиа-вариантов

• при необходимости стиль можно корректировать, добавляяк высоте строки необходимое число базовых единиц

.button // кнопка с большими отступамиtext-metrics: sans-medium 2 // за счет увеличенного line-height

21 / 43

fontsОпределение шрифтов — как и раньше, через макро:

// URL файлов шрифтовfont-path ?= ’/fnt’

// %s — переменное расширение шрифтового файлаuse-font-face(’Bitstream Vera Serif Bold’, ’VeraSeBd.%s’)

@font-face {font-family: ’Bitstream Vera Serif Bold’;font-style: normal;font-weight: normal;src: url(/fnt/VeraSeBd.eot?) format(’eot’),

url(/fnt/VeraSeBd.woff) format(’woff’),url(/fnt/VeraSeBd.ttf) format(’truetype’);

}

22 / 43

Разноеclearfix, position, text, overflow

clearfix: true // говорит само за себя :)fixed: top // сокращение для позиционированияabsolute: top left // еще сокращение для позиционированияcentered: true // горизонтальное центрирование блокoverflow: ellipsis // показ части текстаtext-hidden: true // скрывает текстовый контент элемента

linear-gradient

background: linear-gradient-image( // => background:40px, // url(’data:image/png;base64, iVB...rgba(255,255,255, .2) 0%,rgba(255,255,255, .2)

)

23 / 43

mediaГенерация медиа-вариантов + IE8 (ждать уже не долго2 ,)

• нужно избежать дублирование описаний вариантов• стараемая избежать избыточных @media в CSS• желательно как-то следовать Mobile First

Нужна выборочная генерация для отдельных медиа-вариантов.

// site.styl+media(any, ie) // стили по умолчанию, используются IE8.labeltext-style: sans-small

+media(any) // стили по умолчанию, не используются IE8display:none

+media(above-480, ie) // медиа-вариант, используется IE8display: block

2http://theie8countdown.com/24 / 43

media: непосредственная генерация

// Просто загружаем файл .label {@import ’site’ font-family: sans-serif

font-size: 12pxline-heightL: 16px

}.label {

display: none}@media screen and (min-width: 480px) {

.label {display: block;

}}

Проблемы: порядок следования @media, вариант для IEнесовместим с Mobile First, каждый новый +media() —дублирование @media в CSS.

25 / 43

media: выборочная генерация

media-query устанавливает вариант, @media не используется:

media-query = above-480 .label {@media above-480 { display: block;@import ’site.styl’ }

}

Для IE8 используем значение второго аргумента +media():

media-query = ie .label {@import ’site.styl’ font-family: sans-serif;

font-size: 12px;line-height: 16px;

}.label {

display: block;}

26 / 43

media: итогоИспользование +media() позволяет:

• не думать о порядке следования @media при описаниикомпонентов, главное в итоге сгенерировать их вправильном порядке

• генерировать отдельные файлы для разных вариантов иподключать их в зависимости от возможностей устройства,(например, max-device-width)

• генерировать отдельный legacy-вариант

• предопределенные точки перехода не являютсяобязательными

• предопределенные точки соответствуют либо Mobile First(above-*) или Desktop First (below-*)

27 / 43

Разметка страницыСейчас используем наборы сгенерированных классовтипографских сеток, проблемы:

• хорошо в адаптивном дизайне, хуже — в responsive• неудобно в ситуациях, предусматривающих flow контента,например, responsive витрина магазина

• избыточное количество классов• замусоренная разметка, теряется семантичность разметки• не отменяет сетки на уровне дизайна — мы говорим ореализации

Альтернатива: система блоков по мотивам PocketGrid3

3http://arnaudleray.github.io/pocketgrid/28 / 43

blocks: идеяbox-sizing + блоки процентной ширины + естественный flow

• block-group — контейнер для блоков (примерно grid row)• block — блок (примерно grid cell), float: left• по умолчанию все блоки 100% — mobile first!• разная процентная ширина блоков в медиа-вариантах —разные сетки без дополнительных классов.

• блок может содержать вложенную группу блоков• gutter определяется внутренним отступом блоков• gutter фиксированный (в пределах медиа-варианта)• block и block-group — семантические классы,отображение — целиком в CSS

29 / 43

blocks: использование

<div class="head block-group">...</div><div class="page block-group">

<div class="page-content block"><h2>Site content</h2><p>...</p>

</div><div class="page-sidebar block">

<h3>Sidebar</h3><p>...</p>

</div></div><div class="foot block-group">...</div>

30 / 43

blocks: использование+media(any, ie)

.pageblocks-gutter: 20px // горизонтальный gutter

+media(above-480) // по возможности.page-content // располагаем рядом,

width: 60% // по умолчанию —.page-sidebar // друг под другом

width: 40% // (width: 100%)

+media(above-1024) // на больших разрешениях.page

block-gutter : 40px // увеличиваем gutter

31 / 43

blocks: flow<div class="showcase block-group">

<div class="showcase-item block"><h3 class="item-title">Item 1</h3><p class="item-info">Description 2</p>

</div>

<div class="showcase-item block"><h3 class="item-title">Item 2</h3><p class="item-info">Description 2</p>

</div>...

</div>

Разметка не разделяет позиции по горизонтали отдельнымиконтейнерами рядов.

32 / 43

blocks: flow+media(any, ie).showcaseblocks-gutter: 20px 2 // 2*8px — вертикальный gutter

+media(above-1024).showcaseblocks-gutter: 40px 3

.showcase-itemwidth: 25% // 4 столбца на десктопе

+media(above-640).showcase-itemwidth: 33.33333% // 3 столбца на планшете

+media(above-480).showcase-itemwidth: 50% // два столбца на смартфоне

Если высота одинакова, блоки переносятся автоматически.33 / 43

iconsЕдиный способ подключения иконных шрифтов:

<i class="icon icon--oi" data-glyph="save"></i>

• класс .icon — общий класс для всех иконок• класс .icon–oi — модификатор для конкретного иконногошрифта

• data-glyph="save" — определяет отображаемую иконку

На данный момент включен Open Iconic4: user-icons(’oi’).4https://useiconic.com/open

34 / 43

Интерфейсные элементыСтилизация элементов интерфейса — сложная задача:

• использование box-sizing делает жизнь проще• проекты слишком визуально разные для единого решения• существующие фреймворки ограничивают внешний видопределенной моделью

Поэтому:

• normalize + box-sizing — минимальная подготовка• соглашения + абстрактные классы без визуальногооформления в качестве основы

• (возможно) вспомогательные макросы для типовыхвариантов оформления

35 / 43

buttons• $buttons-behavior — базовое отображение + поведение• $buttons-button — минимальная геометрия в пределахline-height

• use-buttons() — .button производный от$buttons-button

• inline-block, размеры — относительно контейнера

+media(any).button // настройка в проектеborder: noneborder-radius: 0.5em

.button--defaultcolor: white // - стилизация вида кнопокbackground-color: #999

.button--smallfont-size: 80% // - относительный размер шрифта

36 / 43

forms: соглашение по верстке

• .form — контейнер для элементов формы, соответствуетстроке формы или всей форме

• .form-control — сложный элемент управления изнескольких элементов, например, <label> c <inputtype="checkbox"> внутри

• .form-label — метка поля (<label> или контейнер с<label>)

• .form-field — контейнер для полей формы

• .form может использоваться совместно с .block-group• .form-field, .form-label — совместно с .block• результат — можно менять вид формы в медиа-вариантах

37 / 43

forms: пример<div class="signup-form">

<div class="form form--aligned block-group"><div class="form-label block"><label for="name">Your name:</label></div><div class="form-field block"><input id="name" class="form-input"></div>

</div>

<div class="form form--stacked block-group"><div class="form-label block"><label for="about">About you:</label></div><div class="form-field block"><textarea id="about"></textarea></div>

</div>

<div class="form form--stacked block-group"><div class="form-field block"><label class="form-control"><input type="checkbox" name="agree">Yes, I agree.

</label></div>

</div>

</div>

38 / 43

forms: стилизацияuse-forms() // базовые классы

+media(any) // общие настройки.formblocks-gutter: 40px 2 // отступы между рядами

.form-labeltext-metrics: sans-small 2 // увеличенная высота строкиlabeltext-metrics: sans-small

.form-inputtext-metrics: sans-smallpadding-top-bottom: 1 2px // скорректированный отступpadding-left-right: 0.6emborder: solid 1px #aaawidth: 100%

+media(above-640) // на большом экране.form--aligned // для строк с выравниванием.form-label // устанавливаем горизонтальныеwidth: 10% // размеры

.form-fieldwidth: 70%

39 / 43

Структура файловsrc/css/ Исходники для CSS.

site/ Генерация стилей сайта:any.styl - стили для всех вариантовdesktop.styl - стили только для десктопаie.styl - IE8mobile.styl - мобильные стилиstyles/ Исходные таблицы стилей сайта:

common/ Общие стили для всех страницindex.styl Индексный файл для всех модулейpage.styl - стили страницыforms.styl - стили форм... - и т.д.

... Стили для отдельных режимов.index.styl Индексный файл всего сайта.

40 / 43

Точки входа// any.styl: общие стили для всех устройствrequire ’../lib’media-query = any // не обращаем внимания на@import ’styles’ // legacy-признак

// mobile.styl: стили для мобильных устройствfor m in above-480 above-320 above-240 // порядок важен!

media-query = m@media m

@import ’styles’

// ie.styl: отдельный CSS для IE8media-query = ie@import ’styles’

41 / 43

Самое главноеПри использовании любого CSS-препроцессора:

• даже используя препроцессор, вы пишете CSS• оперируйте в первую очередь понятиями CSS, а непрепроцессора

• старайтесь получить оптимальный CSS, а не красивыйисходный код для препроцессора

• всегда проверяйте генерируемый код

Препроцессор — инструмент для получениякачественного CSS, а не его замена.

42 / 43

use-bare()private: https://bitbucket.org/interlabs/bare

43 / 43