Прогрессивное улучшение в JavaScript

Прогрессивное улучшение в JavaScript

Всем привет из армии, а точнее с военных сборов ;-)

Сегодня мы продолжим наш давний разговор про прогрессивное улучшение. Напомню, что до этого мы рассматривали теорию прогрессивного улучшения и ее приложение к HTML и CSS. В этой статье мы будем говорить о JavaScript, а точнее рассматривать фреймворк jQuery.

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

Ликбез

Итак, думаю вы помните, что суть прогрессивного улучшения состоит в слудующем:

  • доступность и семантичность верстки;
  • внешние стили и скрипты;
  • верстка, стили и скрипты выступают отдельными «слоями», которые накладываются один на другой, а не смешываются как коктейль.

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

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

Подключение скриптов

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

Вот плохой пример подключения и выполнения клиентских скриптов:

...
<link rel="stylesheet" href="typo.css"/>
<script type="text/javascript" src="huge-file.js"></script>
</head>
<body onload="runMyScripts();">
...

А вот хороший:

...
<script type="text/javascript" src="huge-file.js"></script>
<script type="text/javascript" src="init.js"></script>
</body>
</html>

Файл init.js запусткает необходимые скрипты и может выглядеть как-то так (обычно запускаемых функций намного больше):

$(document).ready(function() {
runMyScripts();
});

Привязка функций

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

Итак, плохой пример:

<a href="#" onclick="runMyFunc(this);" class="onclickLinks">ссылка №1</a>;
<a href="#" onclick="runMyFunc(this);" class="onclickLinks">ссылка №2</a>;
...
<a href="#" onclick="runMyFunc(this);" class="onclickLinks">ссылка №N</a>;

А вот это уже хороший:

$('a.onclickLinks').each(function() {
this.click(function(e) {
runMyFunc($(e.target));
});
});

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

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

Работа со стилями

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

<script type="text/javascript">
...
$('#someDiv').css({
'font-weight': 'bold',
'color': '#990000',
'border': '#000 3px dotted'
});
...
</script>

Это кошмар. Во-первых, это неудобно, так как если вы захотите (или скажет дизайнер) сменить цвет (то есть часть стиля), то менять его вы будете внутри JavaScript (программная часть) — не логично, не так ли? Так что лучше завести для этого отдельный класс — при смене визуалки логика не будет затронута, только стили. Делать лучше вот так:

<style>
.someClass {
font-weight: bold;
color: #990000;
border: #000 3px dotted;
}
</style>

...

<script type="text/javascript">
...
$('#someDiv').addClass('someClass');
...
</script>

Вывод: разделяем стили и клиентскую логику, не мешаем JavaScript и CSS.

 

Итак, думаю, что этой статьей я смог убедить вас в том, что следования принципам прогрессивного улучшения помогают писать более правильный, удобный и красивый код. Если есть, что добавить, то комментарии к вашим услугам.

Расскажите друзьям

Оцените статью:
  • 1
  • 2
  • 3
  • 4
  • 5

Комментарии — 16

андрей
согласен с автором на все 100.
Особенно ценно последнее замечание по изменению стилевых свойств элемента непосредственно в js коде. Это ведёт к не меньшей неразберихе и негибкости, чем интеграция js в html-код.
#
андрей
Сашко
Согласен тоже. Стал умнее :)
#
Сашко
sanchosrancho
При разработке сайта (страницы) от начала до конца можно использовать следующий подход:
1. Сначала создать структуру документа (xhtml)
2. Затем описать представление с помощью стилей (css + images)
3. В конце добавить интерактивность (javascript)

На каждом этапе, нужно вносить минимум изменений в уже реализованные слои. При этом, на каждом шаге сайт (страница) должен полностью работать.
Bonch
Довольно тривиальные советы.
Думаю, вам стоило бы рассказать про разделение логики в javascript на внешний вид и поведение подробнее.
Например, знаете ли вы, почему в xhtml strict запретили аттрибут target? Все потому, что ребята хотят отделить поведение (javascript) от внешнего вида (css) и описания (xhtml) документа.

Вот про это я бы почитал - может бы что-то новое для себя открыл :)
А так просто лень самому писать у себя. Трудно выдавить из себя текст :)
Alex
>Им кажется, что прописать событие или функцию непосредственно в HTML-коде страницы >быстрее и правильнее, но это не так.

Тут вы не совсем правы. Дело в том, что на выборку селекторов тоже будет тратиться время, а иногда и очень много времени. Например, на странице 500 комментариев и надо привязать к каждому комменту (какому-то его блоку) несколько событий. В таком случае - выборка всех сенлекторов может занять много времени, поэтому возникает как бы эффект подвисания браузера. (Особенно это ярко выражено в случае FF и IE)
#
Alex
r-ip
ХМ

$('a.onclickLinks').each(function() {
    this.click(function(e) {
        runMyFunc($(e.target));
    });
});


а не проще ли так?


$('a.onclickLinks').click(function() {
   runMyFunc($(this));
});
N13
В целом - присоединяюсь к автору. Вот только интересно (по поводу последнего примера): хорошо, когда событие влияет на мгновенное переключение класса (клик - и блок мгновенно должен стать оранжевым). А если требуется плавное (анимированное) изменение свойства? Простые примеры:
- уведомление о совершенном действии (обычно AJAX): появляется с ярким фоном (дабы обратить внимание), а затем затухает в обычный фон
- удаление элемента (либо затухание в нулевую прозрачность, либо свертывание по высоте)
Лично я для реализации таких вещей не знаю способов, отличных от воздействия на конкретные css-свойства блоков. Если кто-то подскажет, буду признателен (Методы animate, toggle, fadeIn и fadeOut не предлагать, потому что это по сути те же манипуляции с конкретными css-свойствами).
#
N13
Grin
N13, в том же мутулзе есть Морф, который позволяет делать плавный переход от одного класса к другому.
C0vax
Интересно. Многое из написанного уже знакомо, но иногда на практике забываю применить. А вот по поводу того что js файлы в конце нужно подключать - это для меня открытие :)
Вобщем спасибо, хороший пост.
Тарас
А кнопочка класная получилась!
B@rmaley.e>
[quote]$('a.onclickLinks').click(function() {
runMyFunc($(this));
});[/quote]
Тогда вообще так:
$('a.onclickLinks').click(runMyFunc); И в runMyFunc использовать указатель this.
Кстати, в статье неправильно - при использовании each ссылка this ведет на DOM-объект, а не его jQuery версию.
#
B@rmaley.e>
dizelbox
Статья понятная, но я вот не очень пойму, как сделать, чтобы к примеру новый записы, подгружаемые, меняли свой фон.
Иван
Что-то никто ничего не говорит про первый пункт, а я скажу. Не согласен с мнением что в самом конце страницы грузить будет всегда правильно. На самом деле все зависит от содержания подключаемого скрипта.

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

- если там непосредственно в теле идет что-то типа document.write(...), то скорее всего это генерируется текст для вывода - значит, вероятнее всего, помещать нужно в body.
#
Иван
Maxin
как-то я не очень согласна по поводу того, что скрипты вешать в конце кода. не получится ли так, что события onClick будут выполняться с задержкой? + часть функций вообще может начать выполняться не правильно, да и на внешний вид может повлиять, особенно, если скриптом какие-нибудь рюшечки налеплены (
#
Maxin

Новый комментарий

как выглядит какой тег
жирный текст <b>жирный текст</b>
курсивный тект <i>курсивный тект</i>
зачеркнутый текст <s>зачеркнутый текст</s>
подчеркнутый текст <u>подчеркнутый текст</u>
ссылка <a href="адрес">ссылка</a>
function foo() { ... }
<pre><code>function foo() { ... } </code></pre>
разрешенные теги или посмотреть как будет выглядеть
как выглядит какой тег
жирный текст <b>жирный текст</b>
курсивный тект <i>курсивный тект</i>
зачеркнутый текст <s>зачеркнутый текст</s>
подчеркнутый текст <u>подчеркнутый текст</u>
ссылка <a href="адрес">ссылка</a>
function foo() { ... }
<pre><code>function foo() { ... } </code></pre>
разрешенные теги или посмотреть как будет выглядеть

metin2 pvp metin2 pvp serverler pvp serverler