Архив ‘HTML’

Правильный DOCTYPE

Воскресенье, 30 марта, 2008

Известно, что практически у всех броузеров есть два режима: режим обратной совместимости (так называемый quirks mode) и режим соответствия стандарту. Переключение между ними осуществляется по объявлению DOCTYPE, но следует знать, что не все варианты написания DOCTYPE работают во всех броузерах. Наиболее универсальными являются следующие варианты (для Transitional HTML 4.01, Strict HTML 4.01 и XHTML 1.1 cоответственно):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"
        "http://www.w3.org/TR/html4/strict.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
        "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

Кроме того, наличие объявления XML<?xml version=”1.0″ encoding=”….”?> переключает MSIE в режим обратной совместимости, поэтому при использовании XHTML + Content-type: text/html не следует указывать это объявление. (Это не считается нарушением стандарта XHTML.)

Посмотреть полную таблицу соответствия вариантов написания DOCTYPE и режимов рендеринга можно тут: http://hsivonen.iki.fi/doctype/

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

Пятница, 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>';

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

Суббота, 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).

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

Понедельник, 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-код. Возможно, в будущем микроформаты будут пониматься и поисковыми системами.

Отображение блока в нижней части страницы

Пятница, 18 января, 2008

Часто требуется сделать так, чтобы “подвал” страницы отображался в самом ее низу даже в тех случаях, когда на странице мало контента. Реализуется это следующим образом: в CSS тегам body и html присваивается высота 100%.

Далее основной контент берется в один блок div (назовем его content), “подвал” — в другой (назовем его footer). Блоку content присваивается минимальная высота (min-height) 100%, для footerа высота задается явно. Нижнее поле блока content задается равным высоте footerа, а для самого footerа верхнее поле указывается в 2 раза больше, чем его высота.

В результате получаем следующий код:

<html><head><style type="text/css"><!--
html { height: 100%; }
body { height: 100%}
#content { min-height: 100%; margin-bottom: 50px }
* html #content { height: 100% } /* Это для Internet Explorer, который не воспринимает min-height */
footer { height: 50px; position: relative; margin-top: -100px; }
--></style></head>
<body>
<div id="content">
Здесь находится основное содержимое
</div>
<div id="footer">
А это подвал сайта
</div>
</body></html>

Советы: 1) для того, чтобы подвал масштабировался при изменении размера шрифта в броузере, поля и высоту имеет смысл задавать не в пикселях, а в относительных единицах (em);
2) нижнее поле у body должно быть равно нулю (типичная ошибка — использование конструкций вида body { 5px 10px}, которые добавляют не только верхнее, но и нижнее поле).

Тег OBJECT

Среда, 16 января, 2008

Тег Object используется, в основном, для вставки Java-апплетов и Flash-роликов. Но при этом при вставке Flash-роликов совместно с ним часто используется устаревший тег Embed, что вызывает негативную реакцию валидаторов. К сожалению, некоторые даже современные броузеры, в частности, Firefox, без тега Embed не отображают Flash-ролик. Но тем не менее, отобразить ролик без Embed можно и в Firefox, если учитывать следующие его особенности:

1) для ролика должна быть точно указана высота и ширина в пикселях
2) для ролика не должен быть указан параметр classid
3) адрес ролика должен быть указан в параметре data тега Object (при этом вложенный тег <param name=”movie” value=”flash.swf”> должен все равно присутствовать, т.к. он используется MSIE).

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

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

<object data="файл.swf" type="application/x-shockwave-flash" width="ширина" height="высота">
<param name="allowScriptAccess" value="sameDomain">
<param name="movie" value="файл.swf">
<param name="quality" value="high">
<param name="bgcolor" value="#ffffff">
<img src="файл.png" alt="Включите графику или установите Flash-плеер" height="высота" width="ширина">
</object>

Полупрозрачный фон в Internet Explorer

Воскресенье, 6 января, 2008

MSIE 6 не поддерживает свойство прозрачности opacity. Однако добиться прозрачности в нем все же возможно с помощью двух специальных фильтров: Alpha и AlphaImageLoader. Фильтр Alpha позволяет отображать изображения с определенной степенью прозрачности (и применим только к тегу img), фильтр AlphaImageLoader — загружать фоновое изображение (точнее, располагаемое между фоном и передним планом).

Использование выглядит следующим образом:
в CSS для броузеров, поддерживающих полупрозрачные PNG, пишем:

.trans { background: url('images/trans.png'); }

Или, если нам достаточно равномерной однотонной прозрачности:

.trans { background: цвет; opactity: значение }

Здесь значение — степень непрозрачности от 0.0 до 1.0. Такой подход позволяет одно обращение к серверу (не нужно подгружать файл с полупрозрачной картинкой).

Для отображения прозрачного фона в Internet Explorer в head-части HTML-страницы пишем

<!--[if lt ie 7.0]>
<style type="text/css">
.trans { background: none; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/trans.png', SizingMethod="scale" )}
</style>-->

Здесь SizingMethod=”scale” растягивает рисунок до размеров элемента. Если этот параметр не указать, элемент сожмется до размеров рисунка, что в нашем случае нежелательно.

Таким образом, мы создали класс .trans, применение которого к блочным элементам будет делать их полупрозрачными. Файл images/trans.png в простейшем случае должен быть пикселем 1×1

Гораздо удобнее иметь полупрозрачность в виде отдельного класса, и указывать при необходимости два класса для элемента (делается это так: class=”class1 trans”, где class1 — имя другого класса), чем приписывать ее ко всем классам элементов, которые ее используют.

Оффтопик: Также хотелось бы заметить, что в Сети существует статья (причем растиражированная в огромном количестве экземпляров) с опечатками в названии фильтра AlphaImageLoader и параметра SizingMethod. Названия фильтров должны писаться именно так, как они написаны здесь.

О защите от XSS-атак

Воскресенье, 6 января, 2008

При разработке систем, в которых у пользователя есть возможность авторизации и отправки сообщений, существует ряд уязвимостей, с помощью которых можно организовать XSS-атаку путем внедрения JavaScript для отсылки cookies (или URL с идентификатором сессии).

Типичными способами являются следующие:

1. Самый очевидный и наиболее просто блокируемый: вставка тега <script> (отслеживается регулярным выражением вида

preg_replace('|<script(.*?)</script(.*?)>|is','',$buffer)

2. Добавление тега с обработчиком JavaScript-события (конструкции вида <div onMouseOver=”alert(’test’)”></div>. Такие регулярные выражения можно отследить следующим куском кода:

$events = array('onLoad','onClick'); // массив событий
$count=preg_ match_all('|<\w+(\s+[^>]*)>|s',$buffer,$matches);
for ($i=0; $i<$count; $i++) {
  $oldbuf=$matches[0][$i];
  foreach ($events as $curevent) {
    preg_replace('|\s+'.$curevent.'=".*?"|is','',$matches[1][$i]); // вместо '' можно вставить какое-нибудь уведомление о замене
    preg_replace('|\s+'.$curevent.'=\'.*?\'|is','',$matches[1][$i]);
    preg_replace('|\s+'.$curevent.'=\S*|is','',$matches[1][$i]);
  }
  $buffer=str_replace($oldbuf,$matches[0][$i],buffer); // замена исходной строки на очищенную от некорретных обработчиков
}

3. Добавление JavaScript в адрес ссылки или рисунка: (<a href=”javascript:alert(’test’)”></a>).
Корректируется следующим регулярными выражениями:

preg_replace('|<a href="\w+script:.*?"[^>]+>.*?</a>|is','',$buffer);
preg_replace('|<a href=\'\w+script:.*?\'[^>]+>.*?</a>|is','',$buffer);
preg_replace('|<a href=\w+script:\S*[^>]+>.*?</a>|is','',$buffer);

4. Добавление JavaScript в url внутри параметра style, например: <div sytle=”background: url(’javascript:alert(\’test\’)')”></div>

Корректируется следующим куском кода:

$count=preg_ match_all('|<\w+(\s+[^>]*)>|s',$buffer,$matches);
for ($i=0; $i<$count; $i++) {
  $oldbuf=$matches[0][$i];
  preg_replace('|\s+style=".*?"|is','',$matches[1][$i]); // вместо '' можно вставить какое-нибудь уведомление о замене
  preg_replace('|\s+style=\'.*?\'|is','',$matches[1][$i]);
  preg_replace('|\s+style=\S*|is','',$matches[1][$i]);
  $buffer=str_replace($oldbuf,$matches[0][$i],buffer); // замена исходной строки на очищенную от некорретных обработчиков
}

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

1. Броузер MSIE позволяет писать название протокола не только слитно, но и через символы табуляции (а также, возможно, перевода строки), т.е. ссылка вида <a href=”javas cript:alert(’test’)”>Тест</a> в нем будет работоспособна. Поэтому имеет смысл сначала проводить удаление символов табуляции внутри ссылок

2. В броузере MSIE, кроме JavaScript, существует еще и Visual Basic Script, который также может быть внедрен в URL ссылок и рисунков. Он обозначается vbscript (код в примере 3 написан с учетом его возможного наличия).

3. Если пользователю разрешается добавлять прикрепленные файлы и они сохраняются на диск в доступном для просмотра с помощью броузера месте с расширениями .htm, .html , то возможна атака следующего типа: в HTML-файл помещается код JavaScript, и затем атакуемому с помощью средств социальной инженерии предлагается перейти по ссылке, ведущей на этот файл напрямую, вместо того, чтобы скачать его скриптом.

Кроме того, даже если существует проверка на то, что загружаемый файл является графическим, внедрение JavaScript-кода в файл все равно возможно через так называемые EXIF-параметры (например. вместо имени автора можно прописать <script>alert(’test’)</script>), если файл сохраняется на диск с расширениями .html или .htm.

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

Свойство clear

Вторник, 18 декабря, 2007

Часто требуется создать контейнер, внутри которого находятся только элементы со свойством float (например, горизонтальное меню или множество уменьшенных версий фотографий). В некоторых броузерах (в частности, в FireFox) высота таких контейнеров оказывается меньше высоты самих плавающих элементов, в результате чего эти элементы накладываются на текст, идущий после контейнера.

Чтобы избавиться от этого явления, следует воспользоваться свойством clear, предусмотренным в CSS. Это свойтсво помещает блочный элемент, идущий после блока со свойством float, не справа/слева от этого элемента, а ниже (иными словами, clear отменяет действие float). Если элемент со свойством clear находится в самом низу внутри контейнера, то высота этого контейнера определяется по позиции такого элемента, в результате чего проблема с наложением плавающих элементов на нижележащий текст исчезает.

Свойство clear поддерживает следующие значения: none (не используется), left (отменяет float: left), right (отменяет float: right), both (отменяет и float:left, и float:right).

Таким образом, горизонтальное меню, построенное с помощью ненумерованного списка (в соответствии с рекомендациями W3C), будет иметь такой вид:

<div class="menu">
  <ul style="display: block">
    <li style="display: block; float:left">Элемент 1</li>
    <li style="display: block; float:left">Элемент 2</li>
    <li style="display: block; float:left">Элемент 3</li>
  </ul>
  <div style="clear: both"></div>
</div>

Rambler's Top100