Мысли о верстке с JavaScript позиционированием из

Источник: habrahabr
Quiensabe

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

  1. я - дилетант. Хотя моя жизнь напрямую связана с программированием уже более 10 лет, я отношусь тем людям, которым интересно в IT очень многое от 3D моделирования до робототехники. А потому бывает, не знаю элементарных для специалиста вещей. Иногда это помогает, иногда мешает, но что есть, то есть.
  2. если вы хотите в результате "пощупать" технологию в деле, вынужден разочаровать. Все дальнейшее - только изложение мыслей и идей. Создать готовый движок на хорошем уровне у меня не хватит ни времени, ни умений. Впрочем, если кто-то заинтересуется изложенным - я готов всячески содействовать разработке.

Суть идеи.

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

При обычной верстке html - задает структуру контента, а css - управляет и позиционированием и визуальным представлением документа. Эта двойственность css приводит к раздутым файлам стилей, внутри которых бывает сложно ориентироваться. Одни и те же свойства управляют и положением и внешним видом элементов - это вносит путаницу и затрудняет отладку.

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

Разметка

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

Например, так: 

guideX.left = '20%';
guideX.sidebar = '10%+20';
guideX.right = '10%+420';

Таким образом, направляющие становятся свойствами объекта guideX с пользовательскими именами. 

Теперь добавим горизонтальные направляющие:

guideY.top = '20';
guideY.content = 170';
guideY.footer = '100%-120';
guideY.bottom = '100%-20';

Теперь к полученной сетке можно привязать блоки. 
Блок определяется координатами левого верхнего и правого нижнего углов. 

block.name = 'left, top, right, bottom';

Например в нашем случае:

block.logo = 'guideX.left, guideY.top, guideX.left + 300, guideY.content';
block.content = 'guideX.left, guideY.content, guideX.sidebar - 10, guideY.footer';
block.sidebar = 'guideX.content, guideY.content, guideX.right, guideY.footer';
block.footer = 'guideX.left, guideY.content, guideX.right, guideY.footer';

(Конечно, блоки можно определять и напрямую, не используя направляющие, но это затруднит понимание структуры макета)

Также блок можно определить через указание расположения внутри родительского блока:

block.name = 'положение_по_x width, положение_по_y, hieght';

Например, так: 

block.name = 'center 1000, top 50%';

Третьим типом указания расположения блока является указание положения его центра, а также ширины и высоты. Конструкция в этом случае будет выглядеть так:
block.name = 'pos_center центр_по_x, центр_по_y, width, hieght';

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

После всех определений выполняется функция run(); которая на основе реального размера окна браузера, размеров блоков и страницы, рассчитывает размеры и координаты блоков и задает стили для соответствующих div блоков. 

После отслеживаются изменения на странице для соответствующего изменения позиционирования. Например, в данном случае содержимое блока sidebar - может не влезть на экран, что может привести к нарушению структуры. Поэтому изменения размеров блоков отслеживаются, и в данном случае, при увеличении высоты блока sidebar - соответственно сдвинется направляющая guideY.footer, и соответственно изменятся размеры блока content и положение блока footer.

Таким образом, при наполнении страницы не нужны многочисленные вложенные блоки div. Достаточно описать просто:

<div id="logo"> логотип </div>

в любом месте страницы, и логотип встанет на место. При этом внутри div-блока - естественно можно использовать всю стандартную html + css разметку. 

Расширение

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

Вложенные блоки.


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

block.tel = ' in block.logo 10, 100%-50, 100%, 100%';

Или в варианте с указанием стороны пристыковки 

block.tel = ' in block.logo right 100%-10, bottom 50';

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

Зависимости.

Предположим, что нам нужен статичный дизайн в 1000px, по центру окна. Для этого проще всего использовать такой код:

block.name = 'center 1000, top 100%';

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

guideX.left = '';
guideX.right = '';
rule.my1 = 'guideX.left * 2 = 100% - guideX.right';
rule.my2 = 'guideX.right - guideX.left = 1000';

Первые две строки только объявляют направляющие, но не определяют их значения. Вторые две - задают правила, по которым высчитываются координаты направляющих.

Кстати, для переменной ширины блока можно заменить последнюю строку на:

rule.my2 = 'guideX.right - guideX.left = 1000 to 1300';

Оператор "to" - означает, что величина разницы будет от 1000 до 1300, с приоритетом последней.

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

Такой подход позволяет создавать гибкие зависимости между любыми блоками наиболее простым и естественным образом. Анализируя графический макет будущего сайта, человек мыслит примерно такими правилами как "этот блок тянется… этот статичный… этот по ширине равен этому… этот в центре этого… и т.п.". Запись этих заключений в виде правил гораздо проще и логичнее чем стандартные подходы к верстке. При этом совмещение этого подхода с использованием свойств блоков (описано в следующем пункте) позволит реализовать действительно сложные структуры всего несколькими правилами.

Свойства

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

1. Обычные свойства

К любому определенному свойству блока можно обратиться напрямую. 
Поддерживаются: block.name.left, block.name.top, block.name.right, block.name.bottom, block.name.width, block.name.height, возможно другие.

Например, после определения: block.logo = '0, 0, '100, 50'; можно обратиться к block.logo.left или к block.logo.bottom. 

Также к обычным свойствам я отношу параметр заполнения блока. По умолчанию любой блок тянется вниз, при увеличении объема контента. Но написав block.name.fix = true. Можно зафиксировать размер блока.
Если удастся качественно реализовать, можно будет добавить и свойство fit - автоматически выравнивающего масштаб контента в соответствии с размерами блока, по аналогии с соответствующей функцией в издательских системах.

2. Подгонка шрифтов

block.name.fontsize = 'n%'; - этот параметр задает размер шрифта в пропорции от высоты блока. Такой подход позволяет выводить надписи идеально подходящим по размеру шрифтом. Например, вывести текстовый логотип с высотой равной шапке сайта, при любом разрешении. 

3. Подгонка картинок

block.name.image_fit = '[путь/]имя_файла [left/top/right/bottom]'; - позволяет заполнить блок изображением, причем изображение масштабируется таким образом чтобы заполнить блок целиком. Если указан второй параметр - то при подгонке по этой стороне не производится обрезка изображения.

4. Перетаскивание блоков

block.name.dragX = 'true/false [start [, end]]'; - задает возможность перетаскивать блок по оси X в пределах от start до end, от текущего положения. Пример: block.tel.dragX = 'true -10, 80%';
block.name.dragY = 'true/false [start [, end]]'; - аналогично.

Перетаскивание блоков позволяет сделать простую анимацию блоков. Например, такая конструкция.

block.header = '10%, 20, 90%, 300'; // объявляем шапку.
block.slider = 'in block.header 0, 0, 100%, 270'; // в шапке - поле для слайдера.
block.scroll = ' in block.header 0, 270, 33.33%, 100%'; // объявляем скролл.
block.slider_content = 'in block.slider 0, 0, 300%, 100%'; // в слайдере - слайды.
block.slide_1 = 'in block.block.slider_content 0, 0, block.slider.right, 100%'; // слайд 1.
block.slide_2 = 'in block.block.slider_content block.slider.right, 0, block.slider.right*2, 100%'; // слайд 2.
block.slide_3 = 'in block.block.slider_content block.slider.right*2, 0, block.slider.right*3, 100%'; // слайд 3.

Такая запись позволит полностью определить структуру блоков в шапке со слайдером на три слайда, останется только заполнить соответствующие div блоки. 

Добавление записи:

block.scroll.dragX = 'true 0, 100% - block.scroll.width';
rule.my1 = block.slider_content.left = - block.scroll.left*3';

Позволит, перетаскивая блок scroll - перематывать слайдер внутри блока block.slider. 

А запись:

block.slider_content.dragX = 'true'; 

Позволит перематывать слайдер напрямую двигая его (например, на сенсорном экране)

Формальное описание

Формально все операторы выглядят так:
направляющие:

guideX.<имя направляющей> = '<число>';
guideY.<имя направляющей> = '<число>';

блоки:

block.<имя блока> = '[in <имя родительского блока>] {<число>,<число>,<число>,<число> / {left/center/right} <число>, 
{top/midle/bottom} <число> / pos_center <число>, <число>, <число>, <число>} [fix] [fit] [font_size <число>] 
[image_fit [путь/]имя файла] [dragX [<число> [,<число>]]] [dragY [<число> [,<число>]]]';

правила:

rule.<имя блока> = '<число> = <число>';

Где <число> - это любое выражение JavaScript, либо любой процент (будет вычислен исходя из размеров родительского блока), либо пара выражений типа '<число1> to <число2>' - означающее будет выбрано число в диапазоне от <число1> до <число2>, по возможности близкое в <число2>. В выражениях не могут должны зарезервированные слова: to, fit, fix, image_fit, left, center, right, top, midle, bottom, pos_center, in, guideX, guideY, block, rule

После описания разметки обязательно идет вызов функции run();

Чтобы не раздувать статью я не описываю механику работы движка. Но суть проста: в скрипте определяются объекты guideX, guideY, block и rule. После пользователь определяет разметку создавая свойства для этих объектов и определяя значения простыми строками. А при запуске run(); - выполняется перебор этих свойств и определение числовых значений. После этого для всех свойств объекта block ищутся соответствующие им div-блоки и блокам присваивается соответствующее позиционирование. Отрисовка выполняется циклически, чтобы учесть возможные изменения размеров блоков в зависимости от контента, а после аналогичные перестроения происходят при изменении размеров страницы или перемещения подвижных блоков.


Пример

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

Код


<html>
<head>
<script src="js.js"></script>
<script language = 'javascript'>
guideX.left = '10%';
block.content = '0,0,100%,100% image_fit background.jpg';
block.logo = 'guideX.left,12%,100%,23% font_size 100%';
block.slogan = 'guideX.left,23%,100%,26% font_size 70%';
block.slider = 'pos_center 50%, 55%, 700, 270';
block.footer = 'right 100%-guideX.left, bootom 12.6% font_size 15%';
</script>
<style type="text/css">
* {
font-family:"Times New Roman",Georgia,Serif;
color:#fff;
}
</style>
</head>
<body> 
<div id="logo">Logo</div>
<div id="slogan">Cамая компанейская компания</div>
<div id="slider">
<!--  Код слайдера  -->
</div>
<div id="footer">Наш адрес не дом и не улица...<br /> Копирайт (с) CopyRight</div>
</body> 
</html> 


Отображение сайта на разных экранах показано на рисунках.

Заключение

К преимуществам подхода можно отнести: отсутствие мусора в css в виде дополнительных стилей и "костылей", простота разработки адаптивной верстки для любых разрешений, настройка логики позиционирования, используя простые "правила", разделение правил позиционирования от оформления и содержимого документа, возможность частичной автоматизации верстки, используя экспорт направляющих и общей логики разметки из psd-файла с помощью дополнительного скрипта. Также к плюсам можно отнести то, что для работы движка не требуется никаких действий кроме подключения js-файла. А весь "язык разметки" состоит из нескольких типовых выражений, которые легко выучить и применять.

Также можно добавить что и сегодня JavaScript часто используется при верстке сайтов для решения проблем или разработки нестандартных элементов. Описываемый подход мог бы помочь реализовать многие вещи в пару строк, даже если человек не хочет использовать движок для верстки основной структуры страницы. 
Например, для заполнения блока div изображением, с автоматической подгонкой под размер блока, достаточно строки.

block.name = 'image_fit background.jpg'; // блок без указания разметки, но с фоновым изображением

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

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


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=31899