Архив февраля 2008

Оптимизация графики

Пятница, 29 февраля, 2008

Когда на сайте используется большое количество графических файлов, его загрузка сильно замедляется даже в том случае, если суммарный объем файлов достаточно мал. Происходит это из-за большого количества запросов к серверу (кроме того, каждый запрос — это около 0.5 Kb исходящего траффика и столько же входящего). Но есть способ уменьшить этот эффект и для графических файлов, размеры которых заранее известны (например, скругленные уголки, пиктограммы и т.п.). Для этого рисунки со сходными размерами и цветовой палитрой помещаются в один файл, а далее выводятся как фон слоя с помощью свойства background-position. В итоге получается примерно следующее (в данном примере 3 графических файла помещены в один графический файл горизонтально):

<div style="background:url('allpics.gif'); height: 16px; width: 16px; background-position: 0px 0px"></div>Картинка 1
<div style="background:url('allpics.gif'); height: 16px; width: 16px; background-position: 16px 0px"></div>Картинка 2
<div style="background:url('allpics.gif'); height: 16px; width: 16px; background-position: 32px 0px"></div>Картинка 3

Еще одним достоинством этого способа оптимизации является более семантически правильная верстка (т.к. служебные изображения с семантической точки зрения предпочтительнее представлять в виде divов с background, чем в виде img).

Использование редиректов

Четверг, 28 февраля, 2008

Обычно после отправки какой-либо формы выводится страница с сообщением о том, что обработка формы прошла успешно, а затем с помощью META-тега пользователь перенаправляется на следующую страницу. Такой способ позволяет избавиться от некоторых неприятных явлений (например, повторной отправки формы при нажатии кнопки “Обновить”) , но неудобен для пользователя: либо пользователи, давно работающие с сайтом, уже знают это сообщение и не хотят дожидаться автоматического перехода, в результате чего им приходится нажимать на ссылку явно, либо новички наоборот, не успевают сообщение читать.

Но есть более эффективный способ решения такой ситуации: использовать вместо META-тега стандартный переход HTTP по статусу 302, а сообщение об успешном редактировании выводить на той странице, куда будет выполнен переход. Такой вариант позволит с одной стороны, не допустить многократной отправки формы (проверенно в Opera 9.x, Firefox 1.5, 2.x, MSIE 6.x и 7.x) а с другой — не заставлять пользователя делать лишний щелчок мышью или ждать лишние секунды.

Но при этом возникает вопрос: как же узнать, нужно ли отображать сообщение со статусом Ok или нет? Решается это достаточно просто: при выполнении редиректа в новый URL приписывается определенный параметр, например, Ok=1 по наличию которого затем и принимается решение о выводе сообщения.

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

В итоге получаем примерно такой код:

header('HTTP/1.1 302 Object Moved');
header('Location: '.$_SERVER['HTTP_HOST'].'/newpage.php?ok=1');
// вывод заголовочной части HTML-страницы
echo 'Форма успешно обработана.  <a href="'.$_SERVER['HTTP_HOST'].'/newpage.php">Перейти на следующую страницу</a>';

Объединение JavaScript и CSS-файлов для ускорения загрузки

Четверг, 28 февраля, 2008

Когда страница использует большое количество внешних JavaScript-файлов или скриптов CSS (а такое часто бывает, если используются библиотеки типа Prototype или jQuery), время ее загрузки существенно растет, так как каждый такой файл — это новое обращение к серверу, т.е. трата нескольких сотен миллисекунд. Но тем не менее, есть способ избежать эту проблему: воспользоваться серверным скриптом, который объединит несколько указанных файлов в один и отдаст его броузеру. Таким образом, выполняется всего один запрос к серверу для JavaScript и один запрос для CSS.

Существует уже готовое решение. Для того, чтобы воспользоваться им, нужно скачать и поместить в корень сайта файл combine.phps, а затем прописать в .htaccess такие правила для mod_rewrite:

RewriteEngine On
RewriteBase /
RewriteRule ^css/(.*\.css) /combine.php?type=css&files=$1
RewriteRule ^javascript/(.*\.js) /combine.php?type=javascript&files=$1

Далее можно подключать JavaScript-файлы, просто перечисляя их через запятую с помощью таких конструкций:

<script src="/javascript/my1.js,my2.js,jquery.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="/css/style.css,my1.css,my2.css"> 

Если файлы физически расположены в каком-то другом каталоге, то достаточно изменить переменные в самом файле combine.phps:

	$cachedir = dirname(__FILE__) . '/cache';
	$cssdir   = dirname(__FILE__) . '/css';
	$jsdir    = dirname(__FILE__) . '/javascript';

на нужные пути.

К недостаткам данного способа можно отнести обязательное наличие mod_rewrite на сервере. Впрочем, в большинстве броузеров будет работать и прямой вызов скрипта (потрбуется переименовать его из combine.phps в combine.php) вида “/combine.php?type=javascript&files=my1.js,my2.js,jquery.js".

Формы без использования таблиц

Суббота, 16 февраля, 2008

При верстке форм часто требуется расположить поля ввода и подписи к ним в два столбца (обычно слева подписи, справа — поля). Часто такое делается с помощью таблиц, но есть более удобный и правильный с точки зрения семантической верстки способ: использование тега label и свойств CSS.

Выполняется такая верстка следующим образом: форме задается свойство position: relative, затем внутри нее помещаются теги label, у которых также задано свойство position: relative, и в эти теги помещаются поля ввода с position:absolute.

В итоге получается примерно такой код:

<html><head><style type="text/css"><!--
form {position: relative }
label {position: relative; display: block }
input {position: absolute; left: 50% }
--> </head><body>
<form action="" method="get"><fieldset><legend></legend>
<label>Название поля 1: <input type="text" name="f1" size="30"></label>
<label>Название поля 2: <input type="text" name="f2" size="30"></label>
<button type="submit">Отправить</button>
</fieldset></form>
</body></html>

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

Кроме того, в указанном примере приведен тег fieldset (стандарт HTML 4.01 Strict предусматривает его обязательное наличие в форме).  Если поля формы заключены в этот тег, то они по умолчанию размещаются в одной строке (если бы его не было, после каждого поля начиналась бы новая строка). Так как в данном случае этого не нужно, мы поменяли режим отображения label на блочный (свойство display: block).

Особенность свойства position:absolute

Суббота, 16 февраля, 2008

Частым заблуждением начинающих верстальщиков является мнение, что свойство position:absolute позволяет задавать координаты элемента только относительно страницы (элемента body). На самом деле, можно сделать и абсолютное позиционирование элемента относительно родительского элемента. Для этого родительского элемента также должно быть задано свойство position:absolute или же position:relative.

Например, вот в этом коде у вложенный слой будет отстоять на 150 пикселей по вертикали от начала страницы:

<div style="height:100px"></div>
<div style="position: relative; height: 200px; width: 200px;">
  <div style="position: absolute; top: 50px;">Этот текст будет в 150 пикселях от верха страницы</div>
</div>

Если же в указанном примере убрать position:relative, текст будет выводиться в 50 пикселях от верха.

Микроформаты

Понедельник, 11 февраля, 2008

В настоящее время возникло такое явление, как микроформат. Микроформат представляет собой стандартизованный набор тегов XHTML/HTML и имен стилей CSS для описания данных того или иного типа. В частности, существуют следующие микроформаты:

  • hAtom
    Микроформат, предназначенный для данных, которые могут быть объединены в новостные ленты, преимущественно это контент блогов, но не только. hAtom основан на формате новостных лент Atom.
  • hCalendar | hCalendar Creator
    Простой и открытый формат для составления календаря и описания событий, может быть внедрен в (X)HTML, Atom, RSS и произвольный XML.
  • hCard | hCard Creator
    Формат для описания людей, компаний, организаций и мест, с помощью семантического XHTML.
  • hResume | hResume Creator
    Микроформат для публикации резюме.
  • hReview | hReview Creator
    Микроформат для внедрения обзоров (продуктов, сервисов, событий т.д.) в (X)HTML, Atom, RSS и произвольный XML.
  • rel="nofollow"
    HTML атрибут, указывающий поисковым машинам, что ссылка не должна влиять на ранжирование целевой страницы.
  • rel="tag"
    Добавив rel="tag" к гиперссылке можно указать для целевой страницы назначенный автором тег (ключевое слово, тему), к примеру: <a href="http://technorati.com/tag/tech" rel="tag">tech</a>.
  • XFN
    XHTML Friends Network (XFN) простой способ показать связи между людьми с помощью гиперссылок, разработанный Global Multimedia Protocols Group. XFN позволяет выразить отношение к человеку, добавив соответствующее значение атрибута rel к ссылке на его сайт, например: <a href="http://jeff.example.org" rel="friend met">.
  • XOXO
    XOXO (eXtensible Open XHTML Outlines) Позволяет использовать существующие элементы XHTML для создания новых форматов.
  • xFolk
    Формат для публикации коллекций ссылок.

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

Загрузка файла с возможностью докачки

Среда, 6 февраля, 2008

В HTTP-протоколе предусмотрена возможность получения части загружаемого файла или страницы. Для в запросе передается специальный параметр Range, который имеет вид Range: bytes=начало-конец. В ответе вместо обычного статуса 200 Ok выдается статус 206 Partial Content и добавляются поля Accept-Ranges: bytes и Content-Range: bytes начало-конец/общая_длина, при этом в поле Content-Length указывается длина только той части, которая передается клиенту.

На PHP это можно реализовать примерно так:

function send_file($filename) {
// примечание: в $filename -- полное имя файла, который нужно отдать клиенту
$length=filesize($filename);
if ($_SERVER["HTTP_RANGE"]) { // проверяем, пришел ли заголовок Range
  $range = $_SERVER["HTTP_RANGE"];
  $range = str_replace('bytes=','', $range);
  list($range_start,$range_end) =explode("-", $range);
  header('HTTP/1.1 206 Partial Content');
  header('Accept-Ranges: bytes');
  header('Content-Range: bytes '.intval($range_start).'-'.intval($range_end).'/'.$length);
}
else {
  $range_start=0;
  $range_end=$length-1;
  header('HTTP/1.1 200 Ok');
}
header('Content-Length: '.($range_end-$range_start+1));
header('Content-Type: application/octet-stream');
header('content-disposition: attachment; filename="'.basename($filename).'"');
header("Last-Modified: ".date('r',filemtime($filename)));
$fh=fopen($filename,'rb');
fseek($fh,$range_start);
$position=$range_start;
$bufsize=1*1024*1024;
while ($buffer=fread($fh,$bufsize) && $position<$range_end) {
  if ($position+$bufsize>$range_end) $buffer=substr($buffer,0,$range_end-$position);
  $position+=$bufsize;
  print $buffer;
}
fclose($fh);

Следует отметить, что поле content-disposition должно писаться со строчной (малой) буквы, т.к. в противном случае его некорректно воспринимает броузер Opera.

GZIP-сжатие страниц, сгенерированных PHP-скриптом

Вторник, 5 февраля, 2008

Для того, чтобы включить сжатие результатов выдачи PHP-скрипта, достаточно вызвать функцию ob_start(’ob_gzhandler’). Однако в случае, если в настройках PHP включена настройка zlib.output_compression, происходит конфликт, в результате которого генерируется предупреждение. Чтобы этого не происходило, можно воспользоваться таким кодом:

if (!ini_get('zlib.output_compression')) {
  ob_start('ob_gzhandler',9); // 9 -- уровень сжатия
}
else { ob_start(); }

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


Rambler's Top100