Генерация CSS От LESS к Stylus, от фреймворка — к тулкиту Interlabs 23 июня 2014 1 / 43
Nov 28, 2014
Генерация 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