Архив категории «Верстка»

  • Zen Coding v0.5

    Как, наверно, многие догадались по постам на Smashing Magazine, Ajaxian и Хабре, вышел Zen Coding v0.5. Видео, описывающие прелести нового ядра:

    Все видимые нововведения описаны на смашинге, посмотрим, что изменилось «под капотом»:

    • Новый формат описания аббревиатур. Никаких объектов, используются «человеческие» описания тэгов: 'img': '<img src="" alt=""/>'. Во время первого запуска парсер читает настройки и преобразовывает их в специальные объекты для быстрой работы. В данном случае важен синтаксис тэга: например, /> в конце определения означает, что тэг одиночный и не может содержать потомков.
    • Переменные. В настройках добавилась специальная секция variables, в которой определяются переменные, подставляемые в аббревиатуры. Переменные подставляются как ${variable}, но есть ряд предопределённых элементов, которые имеют особые значения: ${id}, ${class}, ${child}. Переменные нужны для того, чтобы можно было быстро менять некоторые стандарнтные значения в аббревиатурах и сниппетах (например, язык). В дальнейшем планируется задавать свои переменные для отдельных проектов.
    • Профили вывода. Можно настроить формат вывода генерируемого кода: выводить в HTML/XHTML диалекте, менять регистр тэгов и атрибутов, менять типы кавычек. Первые наброски документации: http://code.google.com/p/zen-coding/wiki/ZenCodingAPI
    • Сниппеты поддерживают атрибуты id и class. Это можно увидеть на видео в самом конце, в примере с Django блоком. В сниппете можно указать, куда должно подставляться значение атрибутов id и class — получаем, таким образом, легко расширяемые сниппеты.
    • Наследование. Аббревиатуры и сниппеты для конкретного языка могут наследоваться от других языков. Например, для XSL я указал, что его снипетты должны наследоваться от HTML — таким образом при редактировании XSL можно пользоваться стандартными HTML-аббревиатурами + добавлять специфичные для конкретного языка. Наследование задается через параметр extends, указывая через запятую языки:
      'xsl': {
      	'extends': 'css,html',
      	'abbreviations': {
      		...
      	}
      }
      
    • Улучшен API самой библиотеки. Из JS-версии удалил все зависимости от Eclipse, теперь код работает в любом стандартном JS окружении. Добавилось несколько вспомогательных функций для упрощения работы. Но API всё ещё очень далёк от идеала, буду его улучшать.
    • Все комментарии в коде переведены на английский язык.

    Буквально сегодня утром сделал объединил свою ветку разработки с транком, так что там теперь лежит последняя версия. Больше информации о Zen Coding (ну и на меня — красивого — посмотреть :) ) можно увидеть в моём докладе на 404fest.

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

    Notepad++

    Все очень хотят поддержку этого редактора, но проблема в том, что у него нет возможности добавить расширения через скрипты. Единственный известный мне способ расширить NP++ — написать плагин на C++, используя API редактора. На сях я не пишу, приложения под винду никогда не создавал, поэтому нужна помощь человека, который в этом разбирается. В идеале: нужно написать мост WSH-C++, который позволит писать расширения на JavaScript для NP++. Как минимум: предоставить простой API на JavaScript специально для Zen Coding, который я буду дёргать и говорить, что нужно сделать (опять же, с помощью WSH).

    В TextMate не всё работает

    Да, в TextMate пока работает только разворачивание аббревиатур. Обёртывание аббревиатурами и выделение тэгов не работают — опять же, из-за ограничений API редактора. Но есть уже некоторые наброски решений этой проблемы (спасибо Антону Полещуку).

    Метки: , ,
  • Универсальный способ декорирования блоков

    В прошлой домашке я предложил читателям придумать способ вёрстки блоков со скругленными уголками и тенью. Если посмотреть на решения, то увидите, что большинство из них очень похожи друг на друга: 4 элемента, разбросанных по углам, одинаково «необычный» вид картинки, небольшие различия в наложении блоков. Давайте рассмотрим подробнее, за счет чего работают эти способы, а также почему эта статья не называется «Создание скруглённых блоков с тенью».

    Начать, в первую очередь, стоит с определения проблемы, которую нужно решить. Предположим, у нас есть блок со скруглёнными уголками и тенью:

    1

    Внутри блока есть контент неопределенной ширины и высоты, тень полупрозрачная; сам блок может иметь как заданную ширину (пиксели, проценты), так и автоматическую (width: auto). Наша задача: найти наиболее оптимальный способ вёрстки подобных блоков. Под оптимальностью я подразумеваю наименьшее количество элементов, наименьшее количество графических файлов, работа во всех современных браузерах, минимальное количество правок под конкретный браузер. Все эти принципы так или иначе влияют на производительность и надёжность нашего решения, особенно на крупных проектах.

    Справедливости ради стоит отметить, что мы будем рассматривать неопределенность габаритов контента в каком-то определенном диапазоне, например, 1000×1000 пикселей. То есть я буду рассказывать про какие-то небольшие контекстные всплывающие блоки, которыми сейчас переполнены различные сайты. Если вам нужно будет, например, сделать тень у блока, в котором содержится основной контент сайта, то лучше выбрать другой способ.

    Простой способ

    Если присмотреться внимательно на пример выше, то можно сразу же найти простое и оптимальное решение: мы разделим наши декорации на 4 зоны, в каждой из которых покажем определенный фрагмент одной фоновой картинки:

    2

    • Первая область: растягивается по горизонтали и вертикали, background-position: top left;
    • Вторая область: ширина фиксированная, растягивается по вертикали, background-position: top right;
    • Третья область: растягивается по горизонтали, высота фиксированная, background-position: bottom left;
    • Четвертая область: ширина и высота фиксированная, background-position: bottom right.

    Реализовать такую конструкцию — проще простого, но есть один нюанс: блоки должны растягиваться не на всю ширину контейнера, а на ширину контейнера минус ширина бокового блока (в данном случае это 2 и 4). То же самое касается высоты. Решается эта задача довольно просто. Не каждый знает, что задавать размеры блокам можно не только с помощью CSS-свойств width и height , но и с помощью комбинаций left/right и top/bottom у абсолютно спозиционированных элементов. Примерный код может выглядеть так:

    <style type="text/css">
    	.shadowed {
    		position: relative;
    		left: 200px;
    		top:  100px;
    		padding: 10px;
    		width: 30%;
    		max-width: 450px;
    	}
    
    	.sh {
    		position: absolute;
    		background: url(./shadow.png) no-repeat;
    		z-index: -1;
    	}
    
    	.tl {
    		/* задаем высоту */
    		top: -6px;
    		bottom: 12px;
    
    		/* задаем ширину */
    		left: -11px;
    		right: 14px;
    	}
    
    	.tr {
    		width: 25px;
    		top: -6px;
    		bottom: 12px;
    		right: -11px;
    		background-position: top right;
    	}
    
    	.bl {
    		left: -11px;
    		right: 14px;
    		bottom: -16px;
    		height: 28px;
    		background-position: bottom left;
    	}
    
    	.br {
    		width: 25px;
    		height: 28px;
    		right: -11px;
    		bottom: -16px;
    		background-position: bottom right;
    	}
    </style>
    <div class="shadowed">
    	Hello world
    	<div class="sh tl"></div>
    	<div class="sh tr"></div>
    	<div class="sh bl"></div>
    	<div class="sh br"></div>
    </div>
    

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

    • не работает растягивание с помощью top/bottom и left/right;
    • свойства bottom и right работают не правильно (позиция элемента отсчитывается от чётной ширины/высоты контейнера);
    • полупрозрачный PNG нельзя наложить и позиционировать как обычный фон.

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

    Растягивание по горизонтали

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

    3

    Если же этот блок сместить влево на ширину декорации справа, то мы как раз освободим место для блока номер 2. А если родителю указать overflow: hidden, то выпирающий слева кусок первого блока не будет виден. Это именно то, что нам нужно: при растягивании контейнера оба блока будут занимать всю доступную ширину и нормально стыковаться друг с другом:

    4

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

    5

    Решить эту проблему, опять же, довольно просто: обрамим первый и второй блок еще одним блоком, которому выставим width:100%; overflow: hidden и верхний и боковые паддинги по размеру тени. Так как мы задали ширину, то боковые паддинги увеличат размер блока до нужных значений и наша тень будет полностью отображаться. А overflow: hidden с основного контейнера можно убрать, и это даст нам дополнительное преимущество: мы сможем разместить внутренний элемент за границами контейнера (например, кнопку закрытия).

    Добавив padding у внутреннего контейнера, мы столкнёмся с тем, что первый блок будет меньшего размера, чем нам нужно. Но, опять же, так как у него задана ширина, мы можем «добить» ширину до нужного значения с помощью свойства padding-right:

    4_2

    Картинка

    Как вы знаете, полупрозрачные PNG в IE6 нельзя наложить в качестве фона, для этих целей используется фильтр AlphaImageLoader, который, к сожалению, нельзя позиционировать как фон. Но так совпали звёзды, что наше «необычное» растягивание блока из предыдущего шага поможет нам решить эту проблему. Первый блок мы сместили влево на ширину правой декорации, её же мы и отсекли. Соответственно, если мы перенесём правую декорацию в самое начало нашего спрайта, то мы сможем наложить одну и ту же картинку на оба блока:

    sprite-sample

    Правая декорация у первого блока будет скрыта overflow:hidden контейнера, а ширина второго блока равна ширине правой декорации и покажет только её. А если перенести вверх еще и нижнюю часть, то мы сможем наложить один и тот же спрайт на все 4 блока:

    sprite2

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

    Расположение блоков справа и снизу

    Как я уже отметил, в IE6 неправильно работают CSS-свойства right и bottom, и для нас это проблема, так как мы имеем дело с полупрозрачными элементами. Любая нестыковка блоков даже в 1 пиксель будет сразу бросаться в глаза.

    Свойство right исправить очень просто: достаточно вместо него воспользоваться margin-left:100% — это разместит блок ровно у правого края, а с помощью left можно подтянуть блок в нужное место. С bottom немного сложнее: я не знаю альтернативных путей, кроме как позволить самому контенту опустить этот блок до нужного уровня. На предыдущем шаге мы добавили обёртку с двумя блоками внутри, туда же мы добавим и контент. Под обёрткой разместим наши нижние блоки.

    Эта обёртка и будет определять, на какой высоте окажутся блоки 3 и 4. Согласно спецификации CSS, элемент с position: absolute, у которого не указаны позиционирующие свойства — top/right/bottom/left — должен размещаться в том месте потока документа, где размещался бы статический элемент. Это очень удобно, так как благодаря этому можно делать различные трюки в виде выносных блоков, привязанных к определённому слову в тексте (например, смотрите выноску про Hyatt Hotel на сайте Башни Федерации).

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

    Нижние блоки

    Если помните, мы убрали overflow: hidden у самого контейнера. Поэтому, чтобы растянуть блоки 3, 4 так же, как и 1, 2, нам, похоже, придется добавить еще одну обёртку. Однако есть одно CSS-свойство, о котором кодеры часто забывают — это свойство clip. С помощью него мы и скроем выпирающий левый край.

    Результат

    Надеюсь, вы поняли саму идею, за счет чего работает большинство решений, присланных пользователями. Кратко подведу итог: для верстки декорированных блоков понадобится 5 элементов и одна картинка. Элементы располагаются следующим образом: одна обёртка, в которой находятся левый верхний и правый верхний углы, а также контент. У этой обёртки выставлен overflow: hidden, который скрывает выпирающие части у декоративных блоков, а также задает контекст форматирования. Эта же обёртка определяет позицию двух нижних блоков по вертикали. Выпирающая левая часть у левого нижнего блока отрезана с помощью clip. Спрайт мы подогнали таким образом, чтобы нам не нужно было указывать background-position, который всё равно не сработает в IE6, так как там мы воспользуемся фильтрами. В этом спрайте мы как бы вывернули блок наизнанку, переместив нижнюю часть вверх, а правую — влево.

    А вот и моё решение. Как видно из примера, решение полностью кроссбраузерное, для IE6 понадобилось всего лишь добавить padding у некоторых блоков (это можно сделать и с помощью одноразового expression).

    С помощью этого способа можно декорировать любой блок, где надо равномерно покрыть все 4 стороны. Например, можно плоскую и скучную обложку книги превратить в объёмную, как это сделано на сайте Аймобилко (правда, там используется немного другой способ из-за технических особенностей сайта):

    imobilco

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

    Метки: , , ,
  • Домашка №2: результаты

    Во второй домашке приняло участие 11 человек, поэтому можно сделать мини-рецензии по каждому участнику. На этот раз победителя нет, так как большинство участников прекрасно справились с задачей (честно признаюсь, не ожидал такого) и каждый должен сам для себя выбрать оптимальный способ, исходя из своих отношений к IE6, который является главной головной болью при решении подобных задач. Всё-таки, его доля на рынке с каждым днём становится все меньше и меньше. Если чьё-то решение пропустил — пишите в комментарии, обязательно добавлю.

    Результат домашки состоит из двух частей, вторую размещу завтра/послезавтра.

    Ante

    http://stanut.by/_/dz02/quad/ — 5 элементов, 1 спрайт, 1 expression для IE6

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

    Степан Резников

    http://stepan-reznikov.appspot.com/static/homework2-decor/index.html — 10 элементов, 1 спрайт

    Решение получилось совсем без хаков для IE6 (фильтр AlphaImageLoader не считается), но смущает количество декоративных элементов — целых 10 штук.

    daer

    http://chikuyonok.ru/u/hw2/daer/templates/round.html — 8 элементов, 2 спрайта, DD_belatedPNG для IE6, не зависит от высоты контента

    Чем-то похоже на решение Стёпы, только элементов 8, а не 10, и используется два спрайта вместо одного. Однако это решение не ограничено по высоте, что является плюсом. Очень некрасиво моргает при ресайзе в IE6, требует много времени на инициализацию из-за DD_belatedPNG.

    GreLI

    http://chikuyonok.ru/u/hw2/greli/homework2.html — 6 элементов, 1 спрайт, очень много исправлений для IE

    Решение, в целом, неплохое, но очень сильно смущает обилие исправлений для IE — то, чего изначально нужно было избежать. Поддерживать такой код довольно сложно и трудоёмко. Однако решение интересно прежде всего тем, что GreLI виртуозно воспользовался багом IE для достижения необходимого результата:

    В моём примере кстати вообще нет overflow. Для обрезания в IE6 используется то, что за пределами элемента с hasLayout отображаются только блоки с position:relative. Ну или абсолютно позиционированные. Декоративные же либо позиционируются абсолютно с клипингом, либо проставлен position:static. Такое вот полезное применение бага.

    Отсутствие overflow означает, что в блок можно поместить элемент, который будет отображаться за его пределами (например, кнопка закрытия окошка). Отдельный плюс GreLI за подробное комментирование кода.

    kizu

    http://test.kizu.ru/crnrz/var-1001.html — 6 элементов, 1 спрайт, много исправлений для IE
    http://test.kizu.ru/crnrz/var-2002.html — 7 элементов, 1 спрайт, 1 expression для IE, много исправлений для IE, не зависит от высоты контента

    Скептически настроенный kizu прислал целых два очень неплохих варианта, один из которых не зависит от высоты контента, что обошлось ему в один дополнительный элемент и expression для IE. Ну а само решение грешит теми же проблемами, что и у GreLI: большое количество исправлений для IE.

    frozenbear

    http://epoint-group.ru/css-work/round-corners/ и http://epoint-group.ru/css-work/round-corners-v2/ — 4 элемента, 1 спрайт, очень тяжеловесное решение для IE6, проблемы в Opera 10

    Рекордсменом по экономии декоративных элементов стал frozenbear: его решение использует всего 4 элемента. Что вышло боком для IE6: мой бедный ослик сначала долго думал, открывать ли ему эту страницу, а после 2—3 минут раздумий таки очухался и показал решение во всей красе. А все из-за специального скрипта, который генерирует кучу блоков с фильтрами, тем самым сильно нагружая IE6. Кроме того, есть проблемы в браузере Opera с отображением инлайнового блока. Вывод: для Opera верстать сложнее, чем для IE6 :)

    Но больше всего мне понравился подход к созданию спрайта. В первом случае у части изображения отсутствовала тень, что позволило наложить друг на друга две половинки одной картинки без ненужных перехлёстов полупрозрачных областей. Но у такого подхода есть один недостаток — максимальный размер блока ограничен только половиной размера изображения. Этот недостаток был исправлен во втором примере тоже довольно необычным способом: прозрачность тени была увеличена в 2 раза. При наложении друг на друга двух половинок спрайта тень получалась именно такой, какой была в макете.

    Anton Poleshchuk

    http://chikuyonok.ru/u/hw2/ap/ — 6/5 элементов, 1 спрайт

    Очень хорошее решение: минимум исправлений для IE6 (вместо height: 1%; можно было бы написать zoom: 1 в основном CSS), нет expressions. Практически полностью повторяет моё решение :)

    Vii

    http://chikuyonok.ru/u/hw2/vii/ — 5 элементов, 1 спрайт

    Решение очень хорошее, особенно понравилось то, что декоративные элементы находятся рядом, а не разбросаны по всему блоку. Но маленький недостаток всё-таки есть: это необходимость указать отдельно для IE6 свойство clip.

    Revers

    http://rg-jam.ru/revers/block_shadow.html — 5 элементов, 1 спрайт, проблемы в Opera

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

    Владислав Трушин

    http://chikuyonok.ru/u/hw2/sloter/ — 7 элементов, 1 спрайт, тяжелое решение для IE6 (VML, expression)

    Для IE6 решение получилось чересчур громоздким: некэшируемые expressions для размеров блока, VML для отрисовки PNG. Всё это отрицательно сказывается на производительности.

    Олег Коровин

    http://olegkorovin.spb.ru/magicframe/ — 6 элементов, 1 спрайт

    В сравнении с другими решениями, у Олега для декоративных элементов не используется position: absolute. У этих блоков относительное позиционирование, а нужного расположения блоков Олег добивается с помощью отрицательных марджинов. Довольно интересный подход, стоит обратить на него внимание.

    Только в IE6 все довольно плохо: при ресайзе окна начинают пропадать блоки, не работает инлайн.


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

  • Zen Coding онлайн

    Специально для 404fest доделал новую версию Zen Coding под номером 0.5. Анонс этой версии и всех нововведений появится в ближайшие дни (сначала для Eclipse, потом через несколько дней и на остальных редакторах). Также, для этого фестиваля добавил поддержку еще одного редактора — editArea, который представляет собой редактор исходного кода, работающий прямо в браузере. Так что все прелести Zen Coding теперь можно оценить в онлайне и даже поставить его себе на сайт или в CMS.

    Метки: ,
  • Как создавался WebWeb

    В пятницу, 7 августа, состоялось открытие художественного проекта WebWeb, в котором я принимал участие. Не спрашивайте меня, что это все означает, я и сам не понимаю; это такое высокое искусство. Для меня самым интересным разделом был Death: если подвигать курсором влево-вправо, то можно увидеть, как по лошади ползет тень, описывая ее контуры.

    death

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

    Макет от дизайнера

    Дизайнер прислал мне макет, в котором он нарисовал 33 состояния тени.

    step1

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

    Смотрим внимательно на саму тень. По сути, это две пересеченные линии, одна из них — перекладина — простая, как пять копеек, а вторую можно представить как обычную кривую, отрисованную контуром (stroke). Решение этой задачи будет выглядеть следующим образом: создаем кривые, которые описывают каждое состояние тени…

    step2-1

    …а затем будем рассчитывать между координатами точек новую линию, в зависимости от позиции курсора.

    step2-2

    Важно помнить, что набор точек должен быть одним и тем же (то есть в одной линии не может быть больше или меньше точек, чем в другой). Я делал так: отрисовал первую тень, продублировал путь (path) и передвинул точки в другое положение. И так еще 31 раз.

    Хранение кривых внутри JavaScript

    Линии отрисовали, теперь нужно придумать, как будем их хранить и использовать в JS. У нас возможны два типа линий: обычная, прямая линия и кривая Безье. Сам контур тени представляет собой массив таких линий. Для удобства и краткости записи создаются две прокси-функции, которые просто будут возвращать объект с координатами:

    /**
     * Точка
     */
    function p(x, y) {
    	return {x: x, y: y};
    }
    
    /**
     * Кривая Безье
     */
    function bz(cp1x, cp1y, cp2x, cp2y, x, y) {
    	return {
    		cp1x: cp1x,
    		cp1y: cp1y,
    		cp2x: cp2x,
    		cp2y: cp2y,
    		x: x,
    		y: y
    	};
    }
    
    // пример использования
    var line = [p(381, 289), p(427.33, 254), bz(427, 254, 427, 244, 433, 237)];
    

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

    var shadow = {
    	min: Number.POSITIVE_INFINITY,
    	max: Number.NEGATIVE_INFINITY,
    	lines: {},
    	degs: []
    };
    
    /**
     * Добавляет линию, описывающую тень
     * @param Массив точек
     */
    function addLine() {
    	// преобразуем объект аргументов в настоящий массив
    	var points = Array.prototype.slice.call(arguments, 0);
    
    	/** Первая точка линии */
    	var first = points[0],
    		/** Последняя точка линии */
    		last = points[points.length - 1];
    
    	// считаем угол наклона линии
    	var deg = -Math.atan2(last.y - first.y, last.x - first.x) / Math.PI * 180;
    
    	shadow.degs.push(deg);
    	shadow.lines[deg] = points;
    	if (deg < shadow.min)
    		shadow.min = deg;
    
    	if (deg > shadow.max)
    		shadow.max = deg;
    }
    

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

    Экспорт данных из фотошопа

    На первый взгяд, это самая рутинная и скучная часть работы: все 33 контура тени теперь нужно перенести из фотошопа в JS, причем в том формате, который мы выбрали. Решение «в лоб» — наводить курсор на каждую точку кривой, запомнить координаты и записать их в JS. Потратил час только на то, чтобы таким образом записать 3–4 линии (и те с ошибками). Так дело не пойдет, нужно как-то автоматизировать этот процесс.

    Я помню, что в адобовском иллюстраторе есть опция экспорта кривых в SVG, а у фотошопа есть функция экспорта кривых в иллюстратор (File → Export → Paths to Illustrator). Что ж, это уже что-то. Так как иллюстратора у меня нет, экспортированный файл высылаю дизайнеру и прошу его пересохранить в SVG.

    Но все равно SVG не самый удобный формат для моей задачи. Во-первых, у его Path Data есть два типа данных — абсолютные и относительные координаты. Например, запись l10,20 означает смещение на 10 пикселей по горизонтали и 20 пикселей по вертикали относительно предыдущей точки, а запись L10,20 уже означает смещение в координату x=10, y=20. Во-вторых, в SVG присутствует короткая запись однотипных инструкций: например, L10,20 L30,40 L0,60 можно записать как L10,20,30,40,0,60 и иллюстратор любит этим пользоваться. В общем, парсинг из SVG далеко не тривиальная задача.

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

    ...
    %Adobe_Photoshop_Path_Begin:<< /defaultFill false >>
    *u
    %AI3_Note:<< /operation /xor /defaultFill false >>
    1 XR
    551.5000 248.5000 m
    596.0000 283.5000 L
    601.0000 285.5000 595.5000 299.5000 607.0000 303.0000 C
    616.0000 309.0000 626.0000 317.5000 634.0000 323.5000 c
    642.0000 329.5000 662.5000 339.0000 670.0000 345.5000 c
    677.5000 352.0000 690.5000 376.5000 699.0000 384.5000 C
    711.0000 398.5000 719.0000 379.5000 y
    854.5000 487.0000 l
    N
    *U
    %Adobe_Photoshop_Path_End
    ...
    

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

    Вспомнить школу

    Настало время приступить к программированию самой логики. Алгоритм работы будет следующим: во время движения мышки рассчитываем угол наклона линии, соединяющей курсор и начальную точку (в нашем случае это столб), добавляем к этому углу 180˚ и получаем угол наклона тени. Затем находим два статических контура, между которыми находится полученный угол, строим новый контур и отрисовываем его. Все просто, не так ли? :)

    step3

    Прежде, чем начать, нам нужно вспомнить школьный курс математики и геометрии. У большинства моих преподавателей было типичное совковое мировоззрение: задавая вопрос «зачем мне все это нужно?» я получал ответ вроде «это нужно для поступления в ВУЗ», а о способе применения этих знаний в жизни тактично умалчивали. Если б я знал, что буду заниматься программированием анимации и графики, я бы совсем иначе относился к учебе. Так что если вы еще учитесь — наматывайте на ус и не повторяйте моих ошибок :)

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

    graph

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

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

    // считаем угол наклона линии  от курсора до начальной точки
    var cursor_deg = Math.atan2(y, x) + Math.PI / 4 * 3;
    // считаем угол линии контура тени
    var line_deg = 315 - cursor_deg / Math.PI * 180;
    

    Следует помнить, что все вычисления с углами через Math.xxx функции должны вестись в радианах, а не углах.

    Итак, нужный угол мы получили, теперь осталось на основе него построить контур тени. Как указано выше, алгоритм следующий: находим два статических контура, между которыми располагается искомый контур, и считаем новый. Расчет ведется следующим образом: берется отрезок, соединяющий две одинаковые точки, и его длина умножается на некий коэффициент. Этот коэффициент рассчитывается исходя из близости искомого контура к одному из статических. Например, если искомый контур находится ровно посередине, то коэффициент будет 0.5, если ближе к первому, то, например 0.2 и так делее. На практике все довольно просто:

    /**
     * Высчитывает параметры контура для указанного угла
     * @param {Number} deg
     * @return {Array}
     */
    function calculateLine(deg) {
    	// угол должен быть не меньше минимального и не больше максимального
    	deg = Math.min(shadow.max, Math.max(shadow.min, deg));
    
    	var result = [], d1, d2, coeff;
    	for (var i = 1; i < shadow.degs.length; i++) {
    		d1 = shadow.degs[i - 1];
    		d2 = shadow.degs[i];
    
    		if (deg >= d1 && deg <= d2) {
    			// нашли нужный диапазон, считаем коэффициент
    			coeff = 1 - (deg - d1) / (d2 - d1);
    			break;
    		}
    	}
    
    	if (coeff !== null) {
    		var l1 = shadow.lines[d1],
    			l2 = shadow.lines[d2];
    
    		// считаем координаты нового контура
    		for (var j = 0; j < l1.length; j++) {
    			var p1 = l1[j],
    				p2 = l2[j],
    				point = {};
    			for (var p in p1) if (p1.hasOwnProperty(p)) {
    				point[p] = p2[p] + (p1[p] - p2[p]) * coeff;
    			}
    
    			result.push(point);
    		}
    	}
    
    	return result;
    }
    

    Начинаем рисовать

    Основные элементы логики описаны, осталось собрать их вместе. Для рисования я буду использовать Canvas, для IE, соответственно, VML с помощью прослойки excanvas. Пишем промежуточный класс CanvasAdapter, который будет рисовать графику по выбранному ранее формату записи контуров, пишем вспомогательные функции, отслеживающие перемещение курсора и изменения размера экрана (чтобы не тратить лишний раз ресурсы на расчет координат начальной точки контуров) и проверяем:

    step41

    Вполне неплохо. Обращаем внимание на то, что контур тени — так как это обычная кривая — неестественно смотрится на ягодицах лошади:

    step5

    Нужно отрезать выступающий кусок контура. Для решения этой задачи на потребуется создать конструкцию из трех слоев. Первый слой — рисуем прямую линию от начала и до конца тени, как будто лошади вообще нет и у нас голый пол. Второй слой — сама лошадь в PNG, она будет скрывать ту часть прямой тени, которая находится под лошадью. И, наконец, третий слой — полноценный контур тени, на который наложена маска. То есть получается два canvas-элемента, между которыми располагается картинка.

    Помним, что у нас есть замечательный конвертер, который может из ai-формата сделать наш внутренний формат, поэтому в фотошопе быстренько рисуем маску и экспортируем ее в JS. Особая точность маске не нужна, у меня она получилась вот такой:

    step6

    Собираем все вместе, смотрим:

    step7

    Осталось совсем немного: отрезать верхушку тени, чтобы она смотрелась естественно. Можно воспользоваться методом canvas.clearRect(), однако в IE, из-за ограниченной поддержки excanvas, это не сработает. Поэтому размещаем сверху <div> с белым фоном, который будет скрывать ненужную часть. Просто и эффективно.

    Рисуем перекладину

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

    var intersection = lineIntersection(0, line_y, 1000, line_y, last_point.x, last_point.y, first_point.x, first_point.y);
    canvas.transform(1, 0, (line_deg - 90) / 50, 1, intersection.x - 125, intersection.y);
    canvas.fillRect(0, 0, 250, 10);
    

    Вот и все. Делаем окончательный тюнинг, чтобы все работало гладко и смотрим на окончательный результат. Осталось добавить, что excanvas не поддерживает и маски, поэтому тень в IE смотрится не очень красиво, но для проекта это не критично. Интересующиеся могут исследовать исходный код страницы, чтобы увидеть все детали и жуткий баг Оперы, связанный с использованием масок в canvas.

    Метки: , , ,
  • Религиозные войны

    Не ожидал, что статья про верстку двух колонок одинаковой высоты вызовет целый холивар на Хабре. В комментариях дискуссия велась по двум вопросам: зачем вообще нужно так извращаться и почему верстать таблицами — дурной тон. Если с первым вопросом более-менее разобрались (правдивые комментарии оставили errr, Jenek и ArtyV), со вторым вопросом все довольно грустно. Одни кричат, что таблицы для нетабличных данных — не семантично и не круто, вторые — что таблицами все делается проще и быстрее. И те, и другие в корне не правы.

    Верстка сайта, как и дизайн, это решение поставленной задачи, а не очередной способ понтануться перед коллегами-гиками или схалявить. Я еще ни разу не получал задания «написать html-код», но постоянно получаю «сделать сайт», а это — не одно и то же. Сайт — это живой механизм со своим внутренним миром, своими проблемами и планами на будущее. От того, как вы его спроектируете, зависит то, рассыпется ли он при малейшем дуновении ветра или выдержит удар ядерной боеголовки (дружно вспоминаем сказку про трех поросят).

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

    С семантикой тоже не все замечательно. Я не отрицаю, что это здорово и правильно, но вот скажите, если ли официальная спецификация семантичной верстки? Или же все это — частное мнение отдельных личностей, которое разнится от человека к человеку? Как, например, мне сверстать шахматную доску, чтобы любой user agent понял, что это именно шахматная доска, а не бессмысленное нагромождение элементов?

    Семантичность того или иного решения в первую очередь должна определятся решаемой задачей, а не частным мнением людей со стороны. Вот типичный пример, на котором я ловлю большинство идеологов семантичной верстки. Как у любого ИТ-специалиста, у этих ребят в своих блогах есть листинги кода. И этот листинг обычно сопровождается нумерацией строк, что очень даже удобно при описании принципов работы кода. И как же эти листинги оформляются? Правильно, через <ol>/<li> конструкции. Семантично? — вроде да. А я считаю, что нет. Нумерация — это декоративная составляющая листинга, которая никак не связана с самим кодом. А с помощью <ol>/<li> нумерация вдруг стала смысловой составляющей. Что выливается в то, что 95% пользователей при попытке скопировать этот код или его часть получат нумерацию строк впридачу. А ведь этот код вывешивается именно с целью дать посетителю скопировать и опробовать его. Нарушение семантики налицо. Некоторые, конечно, догадываются об этой проблеме, но решают они ее не отдельной колонкой с нумерацией, а кнопкой «view plain». То есть пользователю предлагается потанцевать с бубном только ради того, чтобы скопировать текст.

    Резюмируя все вышесказанное. При выборе «сверстать таблицами или блоками», равно как и в любой другой подобной задаче, нужно руководствоваться тщательным анализом той среды, в которой будет работать то или иное решение, а не идиотскими стереотипами или собственной ленью. Если 1% аудитории сайта — это десятки тысяч пользователей, приносящих реальный доход, то мой выбор — таблицы. Если нужно делать сложный презентационный макет с кучей уникальных по дизайну страниц, то я выбираю блоки. Как-то так.

  • Две float-колонки одинаковой высоты

    Хочу поделиться своим способом верстки двухколоночных макетов, где обе колонки должны иметь одинаковую высоту. Тема, казалось бы, уже избитая: любой западный (а с ними и отечественный) ресурс выдаст вам с десяток способов сделать это. Но с одим нюансом: это будут макеты-«кирпичи», то есть макеты фиксированной ширины. Предел возможностей — одна растягивающаяся колонка. Я покажу как сделать две (и более) растягивающиеся колонки, причем это будет не эмуляция в виде толстого цветного бордера, а именно полноценная колонка, которой можно задать, например, свою фоновую картинку.

    Правильный способ

    Наиболее правильным на сегодняшний день способом верстки многоколоночных макетов является использование CSS-свойства display: table-*, например, вот так:

    <div style="display:table-cell;width:50%">
    	<div style="display:table-row">
    		<div style="display:table-cell;background:red">column 1</div>
    		<div style="display:table-cell;background:blue">column 2</div>
    	</div>
    </div>
    

    Проблема в том, что это не работает в IE6/7, которые составляют значительную долю рынка браузеров. Что ж, придется воспользоваться альтернативным способом.

    Альтернативный способ

    Как обычно, сначала разберем проблему на составляющие. Предположим, у нас есть двухколоночный макет, первая колонка шириной 25% от контейнера, а вторая — 50%:

    col1

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

    Наиболее очевидным и стабильно работающим способом создания колонок из блоков является использование CSS-свойства float. Однако, как вы уже поняли, это не решит нашей проблемы с колонками разной высоты:

    col2

    Какие свойства есть у float-блоков? Они находятся в потоке, значит, могут влиять на высоту контейнера. То есть если мы обрамим блоки контейнером и создадим у него правильный контекст форматирования (либо через clear-элемент, либо через overflow: hidden), наш контейнер примет высоту наибольшей колонки:

    col3

    А если мы добавим не один, а два контейнера, то оба они будут высотой с наибольший блок:

    col4

    Обращаем внимание на размеры колонок: первая 25%, вторая 50%. То есть вторая колонка ровно в 2 раза больше первой. Соответственно, если первому — внешнему — контейнеру мы задаим ширину в 25%, а второму — внутреннему — 200% (две ширины внешнего контейнера, что будет соответствовать 50% относительной всей страницы) и сместим его на ширину контейнера вправо, мы получим подобие того, чего хотим добиться:

    col5

    Осталось разобраться с текстовыми колонками. У нас появился новый контейнер, от которого рассчитываются размеры колонок. Так как левая колонка должна быть шириной в 25% от страницы, а ширина внутреннего контейнера равна 50% от страницы, то новая ширина колонки будет равна 50% (50% × 0.5 = 25%). Сама колонка не должна влиять на ширину, но все еще должна быть в потоке, поэтому подавляем влияние ширины колонки на поток с помощью margin-right:-100%, а сам элемент смещаем влево на половину ширины контейнера, то есть на 50%. Получаем именно то, что нам нужно:

    col6

    А вот сам HTML-код, с помощью которого реализуется эта конструкция:

    <style type="text/css">
    	.col-wrap1 {
    		width:25%;
    		background:blue;
    	}
    
    	.col-wrap2 {
    		width:200%;
    		margin-right:-100%; /* чтобы IE6 не раздвигал контейнер */
    		position:relative;
    		left: 100%;
    		background:red;
    	}
    
    	.col1 {
    		float:left;
    		width:50%;
    		margin-right:-100%;
    		position:relative;
    		left:-50%;
    	}
    
    	.clear {
    		clear:both;
    		font-size:0;
    		overflow:hidden; /* тройной презерватив для IE */
    	}
    </style>
    <div class="col-wrap1">
    	<div class="col-wrap2">
    		<div class="col1">left column</div>
    		<div class="col2">center column</div>
    		<div class="clear"></div>
    	</div>
    </div>
    

    Резюмируя все вышесказанное: я создал два контейнера, который являются дублерами основных колонок, и раздвигаются по высоте этими самыми колонками. Остается добавить, что этот способ является более гибким, чем использование CSS-свойств display: table-*, потому что сами колонки можно перемещать с помощью свойств top и left. Чтобы продемонстрировать потенциал этого решения, я сделал специальный пример. Обратите внимание, что у каждой колонки есть свой бордюр и фоновая картинка, выровненная по правому нижнему краю, что в принципе не возможно в других известных способах.

    На основе этого способа можно создать и больше растягивающихся колонок одинаковой высоты. Пример: сайт ВТБ24. Там три колонки одинаковой высоты; верстка осложняется тем, что первые две колонки должны быть в общей рамке, между которыми есть вертикальный разделитель. Когда я готовился к одному из мастер-классов, в одной книге про «качественную верстку» (естественно, западного автора), я прочил, что такое реализовать невозможно :) Для меня это стало очередным подтверждением, что там не умеют верстать качественные растягивающиеся сайты.

    Два слова о верстке макетов

    На первый взгляд может показаться, что этот способ слишком специфический и подходит далеко не для каждого макета. Это не так. Основной трюк заключается в том, чтобы правильно определить модульную сетку и ширину колонок и контейнеров. Пока дизайнеры не слышат, признаюсь: первое, что я делаю при верстке макета — удаляю гайды, которые нарисовал дизайнер. Они мне нужны лишь для того, чтобы понять, как должны выравниваться блоки, саму модульную сетку я делаю на основе тщательного анализа макетов (на это может уйти целый рабочий день). После этого 7 колонок превращаются в 2 контейнера-дублера с 2…4 колонками в каждом. Может, потом подробнее опишу этот момент, пока могу дать общий совет, старайтесь подбирать такие ширины контейнеров и колонок, чтобы они делили 100 без остатка, а именно: 50%, 25%, 20%, 10%, 5%, 2%, 1%. Тогда вы сможете без особых хлопот выравнивать блоки по горизонтали в вертикали в независимых контейнерах.

    Метки: , , ,
  • Спрайты в вебе. Часть 1

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

    Что такое спрайты?

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


    Спрайт с сайта «Житлобуд»

    Такой подход дает сразу несколько преимуществ. Во-первых, объем одного файла как правило меньше, чем сумма объемов отдельных файлов. Это можно объяснить снижением издержек на сохранение одного изображения: всякие там заголовки, указывающие на формат изображения, или общая палитра цветов, если речь идет об индексированном PNG или GIF. Бородатые кодеры могут вспомнить рекомендации 90-х годов по разбивке одного большого файла на несколько мелких, чтобы создать иллюзию у пользователя, что сайт грузится быстрее :) Такой подход создавал именно иллюзию, так как суммарный объем нескольких файлов был больше, чем объем одного файла, а сама картинка грузилась дольше.

    Во-вторых — самое главное — сокращается количество HTTP-запросов к серверу. Некоторые ребята не обращают на это внимание, а зря: зачастую отдельный запрос обходится намного дороже, чем десяток «лишних» данных в одном изображении. Не буду подробно расписывать этот момент, так как это тема для отдельного разговора.

    Итак, мы уже знаем, что спрайты — это круто и модно. Ограничено ли применение спрайтов только группировкой разных изображений в одно?

    Назад в прошлое

    Будучи неопытным юнцом, я очень любил играть в игры. Больше всего меня интересовало то, как же эти игры делаются. Тогда еще не было повсеместного использования 3D-графики, все игры, в которые я играл, в основном были 2D-аркадами (Another World, Commander Keen, Moles, Prince of Persia, эх…), активно использующими спрайты. Вообще, слово «спрайт» получило широкое распространение именно благодаря видеоиграм, и именно видеоигры больше всего повлияли на меня как на веб-разработчика.

    Помимо обычной группировки изображений можно выделить еще несколько типов спрайтов.

    Раскадровка


    Слон с сайта «Паритет98»

    Раскадровка, по сути, представляет собой набор кадров для анимации, сохраненных в одном файле. Для такого спрайта пишется контроллер на JavaScript, который управляет скоростью и направлением смещения спрайта. По сравнению с обычной GIF-анимацией это дает нам следующие преимущества:

    1. Можно использовать JPEG или полупрозрачный PNG.
    2. Более широкие возможности по оптимизации изображения.
    3. Можно самостоятельно управлять скоростью и направлением анимации, имея один и тот же набор кадров (то есть используя всего одно изображение).

    При создании такого спрайта нужно помнить следующее. Для начала нужно выбрать размер кадра; такой, чтобы в нем без проблем уместилась любое изображение из раскадровки +10-20% свободного пространства по бокам для надежности. Это позволит в дальнейшем без особых хлопот модифицировать изображение.

    Затем нужно точно совместить изображения в кадрах, чтобы при анимации не были заметны рывки. Если все сделаете правильно, то на создание JS-контроллера уйдет минимум сил и времени.

    Циклический спрайт

    Этот тип спрайтов в основном применяется для создания механизмов наподобие прелоудера: некая повторяющаяся текстура на блоке неопределенной ширины.

    Тут, конечно, руки так и чешутся использовать GIF-анимацию, однако перфекционистов вроде меня может не устроить плавность движения. Сравните:

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

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

    Слои

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

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

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

    Естественно, этот пример довольно простой и примитивный: уверен, что многие так и поступили бы с этой картинкой. Наибольший эффект от такого типа спрайтов достигается в том случае, когда сердцевина имеет не прямоугольную форму. Хороший пример: раздел «Отделение Imperia» сайта Imperia Private Banking:

    imperia-branch

    Огромный узор на двери был разделен на 2 слоя: сердцевину и окантовку, каждый слой был по-своему оптимизирован, что в итоге позволило мне сэкономить около 200 КБ. Как быстро разделить изображение на два таких слоя я писал в статье «Про PNG. Часть 2».

    Векторные маски

    К сожалению, не всегда подобные картинки можно эффективно разделить по слоям. Например, когда сердцевина не прямоугольной формы содержит фотографическое изображение. В этом случае на помощь приходят современные браузерные технологии, а именно SVG, Canvas и VML. С помощью них можно наложить векторные маски на прямоугольную JPEG-картинку, добившись необходимого внешнего вида. Для этих целей я написал специальную библиотеку под названием ictinus, которая занимается решением таких задач. Хороший пример использования использования спрайтовых масок (и моей библиотеки :) ) — главная страница сайта «Аймобилко»:

    imobilco

    В середине страницы находится красивый тизер продукта, у которого изображение должно принимать «неправильную» форму (в данном случае — коробка компакт-диска с загнутым углом). Так как фон не однородный (и тоже, кстати, меняется), единственным очевидным способом решения этой задачи было создание отдельного PNG-изображения весом более 100 КБ для каждого такого продукта. Меня такой расклад не устраивал, поэтому я решил в качестве эксперимента применить ictinus (на тот момент был в состоянии очень сырой альфа-версии). На прямоугольное JPEG-изображение накладывается векторная маска (в зависимости от типа продукта), затем под эту картинку ставится PNG-тень. Результат оказался более чем убедительным. Помимо сильной экономии на траффике пользователя я сэкономил нервы заказчику: теперь ему достаточно любому продукту в админке поставить галочку «Показывать на главной», а не готовить в фотошопе новые картинки.

    ***

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

    Скачать JS-котроллер для спрайтовой анимации



    Метки: , , , ,
  • Для вдохновения

    Покопался тут в своих старых проектах, нашел некоторые демки, которые я делал для разных конференций и проектов. Может, кому пригодится. Сразу скажу: большая часть из них не работает в IE, некоторые глючат во всех остальных браузерах. Все представленные демки — не более чем разминка для решения более сложных задач.

    • Стиралка — водим курсором по картинке, стирая защитный слой (HTML, JS, CSS).
    • Экскаватор — Для конференции РИТ-2008. Полностью программная анимация, использовались принципы инверсной кинематики (Canvas, JS).
    • Инфоскроллер — Реализация инфоскроллера Артема Горбунова на JS: анализирует текущий документ и строит из него упрощенную схему для скроллера. Делался в качестве домашнего задания для технологов Студии Лебедева (я, кстати, был той сволочью, которая их раздавала). Руки не дошли довести его до нормального состояния.
    • Волшебные пузырьки — Демонстрация способа имитации масок не прямоугольной формы (HTML, CSS, JS). Эта демка использовалась разработчиками IE8 для тюнинга производительности.
    • Спрей — Для конференции РИТ-2008. Простенькая анимация цвета и движения объектов вдоль кривой Безье (JS, jTweener).
    • Переливающиеся слова — Для конференции РИТ-2008. Тоже простая анимация: в основном демонстрируется способ у обычного текста выхватить отдельные слова и анимировать их (HTML, CSS, JS). Кстати, повторить это на флэше гораздо сложнее :) . Особенно с учетом того, что текст растягивается и можно менять размеры шрифта.
    Метки: , , , ,
  • Zen Coding на Python (+TextMate)

    Портировал движок Zen Coding на Python, теперь его можно интегрировать в другие редакторы, которые могут вызывать сторонние скрипты. Сам скрипт уже в SVN.

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

    PS: в работе плагин для Coda, но в этом редакторе есть некоторые сложности, которые пока не удалось обойти. Жду ответа от разработчиков.

    Метки: , ,

← cтарое новое →