Создание демонстрационной формы

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

Настройка

Установите libsass с Grunt Sass и добавьте Bourbon. Node-Sass установлен как зависимость от Grunt-Sass.

$ npm install grunt-sass --save
$ npm install node-bourbon --save

Добавьте файл bower.json

{
  "name": "class-demo",
}

Добавьте некоторые пакеты Bower.

$ bower install color-scale --save
$ bower install type-rhythm-scale --save
$ bower install rwd-toolkit --save

Установите Grunt

npm install grunt --save

Установите grunt-watch

npm install grunt-contrib-watch --save-dev

Добавьте gruntfile.js.

module.exports = function(grunt) {
  grunt.initConfig({
    sass: {
      dist: {
        files: {
          'public/stylesheets/application.css': 'sass/application.scss'
        },
        options: {
          sourceMap: true,
          includePaths: [
            require('node-bourbon').includePaths,
            './bower_components/color-scale',
            './bower_components/type-rhythm-scale',
            './bower_components/rwd-toolkit'
          ]
        }
      }
    },
    watch: {
      source: {
        files: ['sass/**/*.scss', 'views/**/*.jade'],
        tasks: ['sass'],
        options: {
          livereload: true, // требуется для запуска LiveReload
        }
      }
    }
  });
  
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-sass');
  grunt.registerTask('default', ['sass']);
};

Создайте новый Sass-файл

Создайте следующую папку и файл, а затем добавьте небольшой код Sass в файл.

$ mkdir sass
$ touch sass/application.scss

Установите зависимые библиотеки. Добавьте это в application.scss, чтобы Sass был в курсе об этих зависимостях.

@import "bourbon";
@import "type-rhythm-scale";
@import "rwd-toolkit";

Запустите Grunt

$ grunt
$ grunt watch

Контроль версий

Создайте файл .gitignore и добавьте в него следующее:

# Файлы, созданные ОС
####################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# Выходной CSS
#######################
public/stylesheets/*.css
public/stylesheets/*.css.map

# Зависимые пакеты
######################
node_modules/
bower_components

Добавьте в управление версиями:

$ git add --all
$ git commit -m "add all the things"

Макет

Обновите layout.jade для использования application.css:

link(rel='stylesheet', href='/stylesheets/application.css')

Добавьте в LiveReload:

script(src="//localhost:35729/livereload.js")

Обновите браузер, а затем внесите небольшие правки в Sass и Jade-файлы и убедитесь, что LiveReload работает.

Представление

Начнём с макета и добавим в него больше материала, чтобы заставить его работать правильно.

meta(charset='utf-8')
meta(http-equiv='X-UA-Compatible', content='IE=edge')
meta(name='description', content='#{description}')
meta(name='viewport', content='width=device-width, initial-scale=1.0, minimum-scale=0.5 maximum-scale=1.0 minimal-ui')

Обновите файл index.js в ./routes.

res.render('index', { title: 'Contact me', description: 'This is a new demo' });

Откройте ./views/index.jade и добавьте следующее:

section.message-container
  h1.title= title
  form#form.form(action='#', method='get')
    ul
      li
        label(for='name') Your Name:
        input#name(type='text', placeholder='Your Name', name='name', tabindex='1')
      li
        label(for='email') Your Email:
        input#email(type='email', placeholder='Your Email', name='email', tabindex='2')
      li
        label(for='message') Message:
        textarea#message(placeholder='Message…', name='message', tabindex='3')
        
  button#submit Send Message

Настройка интерфейса

Создайте файл:

$ touch _config.scss

И добавьте в него следующий код:

/////// Настройки типографики
// *----------------------------------------
$font-size: 16;

$heading-1: 36;
$heading-2: 32;
$heading-3: 28;
$heading-4: 18;
$heading-5: 18;
$heading-6: 18;

$line: $font-size * 1.5;
$small-point-size: 10;
$large-point-size: 14;

$primary-font-family: #{"Helvetica Neue", Arial, sans-serif};
$secondary-font-family: #{"Helvetica Neue", Arial, sans-serif};
$heading-font-family: #{"Helvetica Neue", Arial, sans-serif};


/////// Папка для шрифтов по умолчанию
// *----------------------------------------
$fontDir: "fonts/";


/////// Папка для изображений по умолчанию
// *----------------------------------------
$imgDir: "images/";


/////// Базовые цвета
// *----------------------------------------
$alpha-primary:   #5a2e2e;        // красный
$bravo-primary:   #3e4147;        // зелёный
$charlie-primary: #fffedf;        // жёлтый
$delta-primary:   #2a2c31;        // синий
$echo-primary:    #dfba69;        // акцент

$alpha-gray:      #333;           // чёрный


/////// Математика с цветом
// *----------------------------------------
@import "color-scale";


/////// Семантические переменные
// *----------------------------------------
// абстрактное значение «white» легко применяется к семантическому классу объектов
$white:                                #fff;

// основной цвет заголовка
$primary-header-color:                 $alpha-gray;

// начертание заголовка по умолчанию
$heading-font-weight:                  normal;

// основной цвет шрифта для приложения
$primary-text:                         $alpha-gray;

// цвет ссылок по умолчанию
$href-color:                           $delta-color;

// цвет тени по умолчанию
$shadow-color:                         fade-out($alpha-color, 0.5);

// цвет рамки по умолчанию
$border-color:                         $alpha-color;


/////// Цвета для HTML5
// *----------------------------------------
// используется для тега <ins>
$ins-color:                            $charlie-color;

// испольуется для тега <mark>
$mark-color:                           $charlie-color;

// цвет выделения в Webkit
$webkit-tap-hightlight:                $delta-color;

// переопределяет выбранные цвета в браузере
$selection-color:                      $charlie-color;
$selection-text-color:                 $primary-text;


//////// Свойства анимации по умолчанию
// *----------------------------------------
$trans: .333s ease;

Добавьте в файл application.scss:

/////// Настройка приложения — вот где происходит основная магия
// *----------------------------------------
@import "config";

Сброс CSS

Создайте файл:

$ touch _reset.scss

Добавьте в application.scss:

/////// Стандартный сброс CSS
// *-------------------------------------------------
@import "reset";

Добавьте следующий код:

// * Оставим по умолчанию
// *-------------------------------------------------

html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, abbr, 
address, cite, code, del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, 
b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, 
thead, tr, th, td, article, aside, figure, footer, header, hgroup, menu, nav, section, menu, 
time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
  vertical-align: baseline;
  background: transparent;
}

* {
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

body {
  font-size: 100%;
  -webkit-font-smoothing: antialiased;
}

article, aside, figure, footer, header, hgroup, nav, section {
  display: block;
}

// * Адаптивные изображения и другие встроенные объекты
// * Замечание: стиль для IMG вызовет проблемы, если вы используете изображения как спрайты, скажем, в виде пользовательских меток для Google Maps.
// * Было сообщение о проблеме с картами Google, но мы не смогли повторить или выявить проблему.

img, object, embed {
  max-width: 100%;
}

img {
  border-style: none;
  border-color: transparent;
  border-width: 0;
}

// * мы используем много UL, но без маркеров
// * не забудьте восстановить маркеры внутри содержимого

ol,ul {
  list-style: none;
}

blockquote, q {
  quotes: none;
  &:before, &:after {
    content: '';
    content: none;
  }
}

a {
  margin: 0;
  padding: 0;
  font-size: 100%;
  vertical-align: baseline;
  background: transparent;
  &:focus {
    text-decoration: underline ;
    outline: none;
  }
}

del {
  text-decoration: line-through;
}

pre {
  //white-space: pre
  // * CSS2
  white-space: pre-wrap;
  // * CSS 2.1
  //white-space: pre-line
  // * CSS 3 (2.1 на самом деле)
  word-wrap: break-word;
  // * IE
}

input {
  &[type="radio"] {
    vertical-align: text-bottom;
  }
}

input, textarea, select, button {
  font-family: inherit;
  font-weight: inherit;
  background-color: #fff;
  border: 0;
  padding: 0;
  margin: 0;
}

table {
  font-size: inherit;
}

sub, sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
}

sup {
  top: -0.5em;
}

sub {
  bottom: -0.25em;
}

// * стандартизация любых моноширинных элементов

pre, code, kbd, samp {
  font-family: monospace, sans-serif;
}

input {
  &[type=button], &[type=submit] {
    @extend %stipe-cursor-pointer;
  }
}

button {
  cursor: pointer;
  margin: 0;
  width: auto;
  overflow: visible;
}

a.button {
  display: inline-block;
}

// * более привлекательный масштаб изображений в IE7

.ie7 img {
  -ms-interpolation-mode: bicubic;
}

// * Вот где всё веселье начинается
// *-------------------------------------------------

a:link {
  -webkit-tap-highlight-color: $webkit-tap-hightlight;
}

ins {
  background-color: $ins-color;
  color: black;
  text-decoration: none;
}

mark {
  background-color: $mark-color;
  color: $primary-text;
  font-style: italic;
  font-weight: bold;
}

::selection {
  background: $selection-color;
  color: $selection-text-color;
}

::-moz-selection {
  background: $selection-color;
  color: $selection-text-color;
}

Глобальный макет

$ mkdir layouts
$ touch layouts/_global.scss
$ touch layouts/_manifest

Добавьте в _global.scss:

body {
  background-color: $delta-scale-juliet;
}

Добавьте в application.scss:

/////// Макеты
@import "layouts/manifest";

Создание модуля

В папке sass создайте папку module с необходимыми файлами внутри:

$ mkdir modules
$ mkdir modules/message-container
$ touch modules/message-container/_module-message-container.scss
$ touch modules/message-container/_manifest.scss

Добавьте следующее в файл _module-message-container.scss:

.message-container {
  margin: 1em auto;
  width: 90%;
  padding-bottom: 100px;
  @media #{$tablet} {
    width: 75%;
  }
  @media #{$desktop} {
    width: 50%;
  }
}

Добавьте в _manifest.scss:

@import "module-message-container";

Добавьте в application.scss:

/////// Модули
@import "modules/message-container/manifest";

Центральный манифест модуля

В application.scss мы могли бы ввести каждый модуль по одному, как описано выше, но можем также добавить манифест в корень modules, который будет импортировать все манифесты, содержащиеся в этой папке.

Таким образом, в application.scss мы делаем следующее:

/////// Модули
@import "modules/manifest";

Затем в modules/manifest.scss мы делаем так:

/////// Подмодули
@import "message-container/manifest";

Это поможет упростить управление, поскольку нам никогда не придётся обновлять файл application.scss и корневую папку модулей, где мы работаем. Нам просто нужно добавить новый список. Всё импортируется и всё работает.

Наша структура папок будет выглядеть следующим образом:

|- application.scss
|--- modules/
|----- _manifest.scss
|----- message-container/
|------- _manifest.scss
|------- _module-message-container.scss

Типографика

Создайте новый Sass-файл:

$ touch _typography.scss

Добавьте в него следующий код:

html {
  font: em($font-size, 16) $primary-font-family;
  line-height: baseline($font-size);
  color: $primary-text
}

h1, h2, h3, h4, h5, h6, [role=heading] {
  @include heading();
}

.title {
  margin-bottom: em(5);
  padding: 0.25em 0;
  text-align: center;
  background-color: $delta-scale-bravo;
  color: $white;
  border-radius: em(5) em(5) 0 0;
}

Добавьте ниже сброса CSS в application.scss:

/////// Основа
@import "typography";

Формы

Создайте новый Sass-файл:

$ touch _forms.scss

Создайте новую папку forms:

$ mkdir forms
$ midir forms/extends

Добавьте следующие файлы:

$ touch forms/_manifest.scss
$ touch forms/extends/_default-inputs.scss
$ touch forms/extends/_display-block.scss
$ touch forms/extends/_manifest.scss

Вставьте следующее в forms/extends/_manifest.scss:

@import "default-inputs";
@import "display-block";

Добавьте следующий код в forms/extends/_default-inputs.scss:

%default-inputs {
  width: 100%;
  height: 100%;
  padding: 2.25em 1em 1em;
  outline: none;
  font-size: 1em;
}

Добавьте следующее в forms/extends/_display-block.scss:

%display-block {
  width: 100%;
  display: block;
}

Добавьте в forms/_manifest.scss:

@import "extends/manifest";

И в _forms.scss:

@import "forms/manifest";

.form {
  ul {
    border-bottom: 1px solid $hotel-gray;
    background-color: $white;
    margin-bottom: 1em;
  }
  li {
    border: 1px solid $hotel-gray;
    border-bottom: 0;
    position: relative;
  }
}

label {
  @extend %display-block;
  position: absolute;
  font-size: em(16);
  top: .5em;
  left: 1em;
  color: orange;
  opacity: 1;
  transition: #{$trans} top, #{$trans} opacity;
  .js-hide-label & {
    opacity: 0;
    top: 1.5em;
  }
}

input[type="text"] {
  @extend %display-block;
  @extend %default-inputs;
}

input[type="email"] {
  @extend %display-block;
  @extend %default-inputs;
}

textarea {
  @extend %display-block;
  @extend %default-inputs;
  height: 8em;
  resize: none;
}

Кнопки

Добавьте следующий файл:

$ touch _buttons.scss

Добавьте в application.scss ниже импорта формы:

@import "buttons";

Откройте и добавьте следующий код:

button {
  @extend %default-inputs;
  -webkit-appearance: none;
  background: orange;
  color: white;
  border-radius: em(3);
  padding: 1em;
}

jQuery

Откройте layout.jade и добавьте в конце документа:

script(src='//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js')
script(src="/javascripts/app.js")

Создайте следующий файл:

$ touch public/javascripts/app.js

Откройте app.js и добавьте в него следующее:

// Проверка поддержки placeholder
$.support.placeholder = (function(){
  var i = document.createElement('input');
  return 'placeholder' in i;
})();

// Скрываем метки по умолчанию, если поддерживается placeholder
if($.support.placeholder) {
  $('.form li').each(function(){
    $(this).addClass('js-hide-label');
  });
}

$('.form li').find('input, textarea').on('keyup blur focus', function(){

  // Кэшируем наши селекторы
  var el = $(this),
  parent = el.parent();

  // Добавление или удаление классов
  if( el.val() === '' ) {
    parent.addClass('js-hide-label');
  } else {
    parent.removeClass('js-hide-label');
  }

});

Автор и редакторы

Автор: Дейл Санде
Последнее изменение: 19.10.2015
Редакторы: Клим Щербаков