В одной моей социальной компании роль фронтенд-разработчиков сравнивают с бас-гитаристами в музыкальных группах: когда-то они мечтали стать сольными гитаристами с шестиструнной электроникой в руках, или, проводя параллель, настоящими «хакерами», гуру информационных технологий, но, споткнувшись об указатели, вынуждены были сделать шаг назад и остаться верстальщиками. Насколько такое представление верно, решайте сами, но лично мои знакомые фронтендеры действительно когда-то пытались учить чуть ли не ассемблер и до сих пор иногда жалеют, что не справились с сегментацией памяти. В этой статье мы рассмотрим противоположный случай — когда опытный системный или прикладной программист внезапно решил стать веб-мастером. Причины могут быть разные. Возможно, это студент, как я, который ещё не получил диплом, с которым можно устраиваться на работу по специальности, а заработать денег нужно уже сейчас. Или начальник приказал системному администратору сверстать сайт компании, потому что больше некому. Ну или, возможно, вас завлекла идея прекратить работать на дядю и стать самодостаточным фрилансером, а на фриланс биржах, как известно, самый ходовой товар — сайты. Так или иначе, выполняя задания из самоучителей по HTML, CSS и JavaScript, вы невольно частично руководствуетесь своим прошлым опытом разработки прикладного и системного ПО, тогда как самоучители рассчитаны на совершенных новичков в мире информационных технологий. В результате у этих новичков первые сайты получаются быстрее и кросбраузернее, чем у вас. А всё потому, что со своим уставом в чужой монастырь не ходят. О некоторых выявленных на собственном опыте ошибках, преследующих начинающих фронтендеров, имеющих увесистое портфолио с алгоритмами на C++, я и расскажу.



Ожидание лёгкой прибыли


Первая ошибка — экономическая. Если вы пришли во фронтенд с целью заработать больше, чем позволяет ваш начальник, я вас сразу разочарую, можете дальше не читать. Спрос на лендинги, вёрстку и визитки под ключ на биржах действительно большой, но и предложение высокое. Вместо 8 часов работы в офисе, во время которых вы выполняете заданную именно вам работу, придётся большую часть дня потратить на самостоятельный поиск этой работы. Имейте в виду, что большинство работодателей готовы сотрудничать, только если вы предоставите им похожие на заказ примеры из своего портфолио, а значит, первый месяц вас гарантированно ждёт труд за шиши, ведь это портфолио нужно сначала собрать, ловя каждый шанс поработать бесплатно. И даже с ним вместе с вами на один и тот же проект откликнутся десятки таких же как вы фрилансеров. Среди них будут и очень опытные верстальщики, которые выполнят половину заказа сразу же и предоставят как демо-версию, и только начинающие, которые как и вы когда-то предложат выполнить всё бесплатно. Скорее всего, работодатель выберет кого-то из этих двух легионов, а остальным придётся ещё несколько часов безрезультатно сидеть за монитором, нажимая F5. Ситуацию можно сравнить с рынком юристов в СНГ — когда-то их отрывали с руками, лишь только они выйдут за порог альма-матер, но теперь предложение намного превышает спрос. При этом фриланс отличается от работы в юриспруденции повышенной опасностью: если у вас нет собственного ИП, заработанные вами на фрилансе деньги по закону могут посчитать нелегальными и вот тогда вы точно пожалеете, что не остались в том уютном офисе, где можно было 8 часов в день заниматься любимым делом и получать за это белую зарплату. Если я всё ещё вас не разубедил, перейдём к следующим ошибкам.



Разброс кода по разным файлам


Мы делаем это в системных языках высокого уровня — каждый класс — в отдельный файл. Хорошие самоучители по вёрстке сразу приучают сохранять HTML и CSS в разных файлах. Тут может показаться, что этот приём применим ко всему. Стоп. Да, хранить CSS код лучше отдельно от HTML, но, например, хранить сброс стилей или шаблоны отдельно от основной массы CSS правил сайта — смертельная ошибка. То же относится к JavaScript, — разбивать скрипты на сотни файлов по классам не нужно, достаточно сгруппировать их по двум файлам: тому, что подключается в заголовке страницы (head) и тому, что добавляется в конец контента (body). Мы привыкли, что программы на компилируемых языках линкуются полностью до начала выполнения. Здесь всё по-другому. Каждое линкование в коде сайта — это дополнительный запрос на сервер. Наверняка вы заметили, как медленно в последнее время стала работать социальная сеть Вконтакте. Откройте в любом браузере панель разработчика, обновите vk.com и посмотрите, как много он совершает GET- и POST-запросов на сервер соцсети. Один такой запрос занимает считанные микросекунды времени, но из-за их количества процесс полной загрузки страницы растягивается на секунды. Запомните: минимальное число запросов — главный метод увеличения скорости сайта. На локальном сервере это незаметно, но становится очевидным при работе с удалённым хостингом. Никто не мешает вам хранить сбросы, шаблоны стилей, классы, библиотеки в отдельных файлах, но перед публикацией всё это нужно «склеить», оставив из исходников по одному файлу HTML и CSS, и пару файлов JS. Для сборки всех файлов JS в один файл, «бандл», существуют webpack, browserify, для аналогичной сборки CSS предназначены процессоры SASS и LESS. Есть и другие методы оптимизации, например, совмещение нескольких изображений (чаще всего списков иконок или аватарок) в одном файле, но это тема отдельной статьи.



Перебор с классами и идентификаторами


Самоучители советуют добавлять ко всем элементам на странице атрибуты классов и идентификаторов, чтобы их можно было легко выделить CSS-селекторами. Это хороший совет, до определённой степени. Когда я только начинал изучать вёрстку, у меня просто всё было усыпано классами. Это — ошибка. Приведу пример.



Именно такой код я писал, будучи новичком в вебе. Теперь рассмотрим все ошибки. Во-первых, в ТЗ не указано разукрашивать вкладки навигации разными цветами и не планируется указывать, а поэтому все идентификаторы вкладок просто зря нагружают процессор пользователя сайта. Смело убираем. Во-вторых, все элементы класса «topnav» являются элементами <li> и вложены в <ul>, мало того, элемент <ul> может содержать только элементы <li>, поэтому наш класс «topnav» тождественен селектору "#topnav li". Стираем классы topnav. Ну и в третьих, в ТЗ указана единственная панель навигации, а значит, на всей странице должен быть только один элемент <nav>. Да, ТЗ может измениться, но добавить идентификатор гораздо проще, чем читать чужой код в поиске нужного слова. К тому же, элементы класса <nav> у нас тоже получаются тождественны селектору «nav ul». Убираем всё.

Вот конечный результат:



Ни одного класса или идентификатора! Но при этом всё нужное выделяется селекторами.

Следующие два кода применяют одни и те же правила:


Первый
nav {
	position: -webkit-sticky;
	position: sticky;
	top: 0;
}
#topnav {
	list-style: none;
	overflow: hidden;
}
.topnav a {
	display: block;
	float: left;
	width: 20%;
	height: 6vh;
	font-family: RMS, monospace, sans-serif;
	font-size: 2vw;
	text-align: center;
	line-height: 6vh;
	color: black;
	background-color: #FF0;
	border-left: 3px dotted red;
	transition: border .2s ease 0s;
}
.topnav:last-of-type a {
	border-right: 3px dotted red;
}
.topnav a:hover {
	border-left-style: solid;
	border-top: 3px solid red;
}
.topnav a:focus {
	border-top: 3px solid red;
}
.topnav:hover + li a {
	border-left-style: solid;
}
.topnav:focus + li a {
	border-left-style: solid;
}
.topnav:last-of-type a:hover {
	border-right-style: solid;
}
.topnav:last-of-type a:focus {
	border-right-style: solid;
}


Второй
nav {
	position: -webkit-sticky;
	position: sticky;
	top: 0;
}
nav ul {
	list-style: none;
	overflow: hidden;
}
nav ul li a {
	display: block;
	float: left;
	width: 20%;
	height: 6vh;
	font-family: RMS, monospace, sans-serif;
	font-size: 2vw;
	text-align: center;
	line-height: 6vh;
	color: black;
	background-color: #FF0;
	border-left: 3px dotted red;
	transition: border .2s ease 0s;
}
nav ul li:last-of-type a {
	border-right: 3px dotted red;
}
nav ul li a:hover {
	border-left-style: solid;
	border-top: 3px solid red;
}
nav ul li a:focus {
	border-top: 3px solid red;
}
nav ul li:hover + li a {
	border-left-style: solid;
}
nav ul li:focus + li a {
	border-left-style: solid;
}
nav ul li:last-of-type a:hover {
	border-right-style: solid;
}
nav ul li:last-of-type a:focus {
	border-right-style: solid;
}


Но второй меньше нагружает и вас, и процессор, и того, кто будет читать ваш код, потому что не придётся искать на странице нужный идентификатор или класс и думать, что означает его имя.
Всё правильно. Выше зачёркнутая информация неверна и тоже представляет собой пример ошибки. Вопреки самоучителям, на определённом этапе постижения вёрстки начинает казаться, что лишние классы и идентификаторы ни к чему, и что второй пример меньше нагружает процессор пользователя сайта, поскольку браузеру не нужно полностью выполнять проход дерева DOM в поисках всех элементов класса ".topnav". Однако, подобное упрощение, наоборот, вызовет увеличение времени поиска и не является оптимизирующим. Всё потому, что селекторы стилей раскрываются справа-налево: во втором коде сначала найдутся все элементы <a> на всей странице, а уже затем произойдёт проверка их родителей на соответствие элементу <li>, потом проверятся родители элементов <li> итд. В итоге, раскрытие нужного селектора займёт проход всего дерева плюс три проверки списка выборки вместо одного прохода в поисках элементов класса ".topnav". Вдобавок, отказ от классов и идентификаторов идёт в разрез в принципом «HTML — для стуктуризации, CSS — для представления», поскольку селекторы CSS не должны зависеть от типа элементов, которые выбирают. То есть, при замене <ul> и <li> на <div> и <span> они должны остаться неизменными. Не пренебрегайте классами и идентификаторами. Лучшим решением, пожалуй, в нашем примере будет такое:

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

Избегание анонимных функций


Мы привыкли, что при написании программ у наших имён функций, переменных и объектов всего три ограничения: они должны начинаться с буквы, содержать только буквы и цифры и не должны совпадать с ключевыми словами языка программирования. Имена сторонних библиотек обычно заключены в удобные пространства имён, поэтому мы обычно не используем лямбда-функции в своих прикладных программах. В вебе с именами дело сложнее. Здесь у JavaScript всего одно глобальное пространство — пространство загруженной страницы. Ничего не случится, если все скрипты вы будете писать для сайта лично. Но для больших и серьёзных проектов понадобятся сторонние решения. И вот они то могут буквально «загадить» это единственное пространство имён, серьёзно ограничив вас в выборе новых идентификаторов. Выход — анонимные лямбда-функции, которые хоть и выполняются чуть дольше, и ресурсов требуют чуть больше, но зато имеют внутри своё личное пространство, независимое от внешнего глобального.

Использование сложных библиотек для решения простых задач


jQuery, React, Vue, Angular, Backbone… Список можно продолжать. Общее у всех этих этих библиотек JavaScript'а то, что они применяются для работы со сложными проектами, когда размер кода действительно имеет значение. Для того же, чтобы просто выбрать элемент на странице по его идентификатору, лучше использовать обычный getElementById(). Он не только работает быстрее, но и в принципе работает на большем количестве старых браузеров. Если ваш скрипт обращается за всё время работы к двум-трём элементам на странице, подумайте, возможно, имеет смысл не нагружать браузер и сеть пользователя тяжёлой библиотекой.

Устаревшие учебные материалы


Это для разработчиков C++ труды Страуструпа останутся актуальными ещё через много десятков лет. Веб-инструменты же развиваются просто с неимоверной скоростью. HTML, CSS, JavaScript, макеты, фреймворки, библиотеки, — пока вы читаете эту статью, у всех них выходят новые версии, часто перечёркивающие старые учебники. Вывод — при выборе учебных материалов для фронтендера важно смотреть на даты выпуска и версии применяемых инструментов (HTML не ниже 5.1, CSS не ниже 3.0, ECMAScript не ниже 6). Возможно, вёрстка HTML не шагнула далеко вперёд со времени выхода HTML 5, но смотреть в 2019 году видеокурсы 2016 года по JS уже поздно. Выбирайте 2018. Ещё лучше, если вы владеете английским языком хотя бы на уровне перевода технического текста со словарём. Тогда сразу посоветую интернет-книгу Eloquent JavaScript.

Отсутствие поддержки старых браузеров


Парадоксально, но если вам повезло найти самую новую подборку учебников по фронтенду, вы можете попасть в другую ловушку — отсутствие поддержки старых браузеров. Хотя элементы <video> и <audio> действительно поддерживаются уже всеми, даже очень древними версиями браузеров, многие эффекты CSS порождают проблемы, и дело не только в страхолютом Internet Explorer. Выход из ловушки один — внимательно читать ТЗ в том месте, где указаны поддерживаемые браузеры, и сверять используемые теги HTML, правила CSS и методы JS по их версиям.

Эта статья — своего рода записная книжка для граблей и будет пополняться с опытом автора.

Комментарии (27)


  1. dimoff66
    08.04.2019 18:47
    +4

    Озаглавить этот опус можно было бы: «Когда поспорил с другом, что после двух дней обучения HTML, CSS и javascript сможешь написать статью на хабре...»

    Детский сад какой-то и почти нулевое знание технологий фронтенда.

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


    Перед следующей статьей почитайте пожалуйста про минификацию файлов…

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


    Вообще за гранью добра и зла. )))


  1. SerafimArts
    08.04.2019 18:53
    +1

    По-моему, это какой-то набор антипаттернов как делать не надо в 2019ом году. Автор не знает не про препроцессоры, ни про компиляцию ассетов. О чём говорят вот такие фразы:

    но перед публикацией всё это нужно вручную «склеить»

    Я не представляю того, кто будет сидеть и вручную это всё склеивать, оптимизировать и минифицировать… Мартышкин труд такой получается.

    Помимо этого, «склеивание» — это спорный момент, т.к. «чанкинг» эффективнее, когда компилится только ядро для перманентного его кеширования браузером, а редкоиспользуемые функции выносятся в отдельные кусочки (чанки).

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

    P.S. Ну и про поддержки браузеров тоже наверное полезно.


    1. JustDont
      08.04.2019 19:16

      P.S. Ну и про поддержки браузеров тоже наверное полезно.

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

      В остальном всё делается автоматикой. Бабель наше всё.


      1. SerafimArts
        08.04.2019 19:32

        Ну, допустим, полифиллить просто так всё нельзя. А какие-нибудь прокси просто невозможно. Как и вёрстку нельзя поправить автоматом. Заменить какой-нибудь отрицательный марджин для IE7 (тьфу-тьфу-тьфу), например.


        1. JustDont
          08.04.2019 19:34
          +1

          «Просто так всё» — конечно нельзя. Но большую часть — можно. Если нет требований на саппорт динозавров, и ИЕ начинается с 11 — можно вообще очень многое.


  1. Tantrido
    08.04.2019 19:14
    +1

    Никто не мешает вам хранить сбросы, шаблоны стилей, классы, библиотеки в отдельных файлах, но перед публикацией всё это нужно вручную «склеить», оставив из исходников по одному файлу HTML и CSS, и пару файлов JS.
    Зачем вручную?! Есть же webpack, browserify и др., которые собирают всё в бандл — один JS файл. Так что модульность никто не отменял: с npm, node.js и т.д. всё очень удобно :) Про CSS препроцессоры тоже ничего не сказал, React, Angular и т.п. — не оценил, посему, думаю, что давать советы по переходу на фронтэнд автору ещё рановато. ;)

    Тоже с C++ перехожу на фронтенд потихоньку, но благодаря предварительному знакомству с node.js удалось не налететь на многие грабли.


    1. 2che Автор
      08.04.2019 19:26
      -1

      Расскажете про свои грабли? Добавлю к своим. И про препроцессоры перепишу, да.


      1. Tantrido
        08.04.2019 19:37

        Да у меня особо и не было: запускаешь сразу какой-нибудь генератор проекта на Node.JS (или .Net Core) с React.JS или pug — он тебе сразу показывает примерную структуру современного проекта: стилей и js файлов, переиспользуемых шаблонов pug и т.п. может быть масса. Типа такого:


        sudo npm i -g generator-node-react
        yo node-react

        или так


        sudo npm install -g create-react-app
        sudo npm update -g 
        create-react-app client

        Всё это потом собирается в бандл и красиво работает. На рабочих примерах в общем лучше учиться, чем изобретать велосипед. Или вот более сложные шаблоны использовать: https://github.com/erikras/react-redux-universal-hot-example


  1. vdem
    08.04.2019 19:40
    +3

    Во-вторых, все элементы класса «topnav» являются элементами li и вложены в ul, мало того, элемент u> может содержать только элементы li, поэтому наш класс «topnav» тождественен селектору "#topnav li". Стираем классы topnav.

    А если вдруг придется использовать не ul/li а div/span к примеру? Менять и теги, и стили? А если в одном месте нужны по какой-то причине ul/li, а в другом div/span? Дублировать стили? Насколько мне известно, как раз нежелательно привязывать стили к конкретным тегам, лучше использовать классы.


    1. megahertz
      08.04.2019 22:19

      Правильно вы заметили. Помимо проблем с заменой div/span, "#topnav li" плохлой вариант с точки зрения производительности. По сути это транслируется в «найти все li, один из предков которых #topnav»


      1. staticlab
        08.04.2019 23:34

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


      1. 2che Автор
        09.04.2019 10:38

        Ну вот тут уже позвольте не согласиться. "#topnav li" даёт команду браузеру выполнить прогон дерева DOM и найти единственный элемент topnav, при нахождении которого поиск прерывается и начинается поиск внутри него. При выборе класса же браузер вынужден выполнять прогон дерева до конца, ища все возможные элементы на странице с классом ".topnav". Самым лучшим с точки зрения производительности является вариант "#topnav > li", при котором на втором этапе происходит только одноуровневый поиск в ширину элементов li.


        1. sfi0zy
          09.04.2019 11:17

          Ну вот тут уже позвольте не согласиться. "#topnav li" даёт команду браузеру выполнить прогон дерева DOM и найти единственный элемент topnav, при нахождении которого поиск прерывается и начинается поиск внутри него.

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


          1. 2che Автор
            09.04.2019 13:05

            Понял, эта статья — тоже ошибка системщика.


  1. PerlPower
    08.04.2019 19:41
    +1

    image


  1. edogs
    08.04.2019 20:29
    +1

    При этом фриланс отличается от работы в юриспруденции повышенной опасностью:
    О_О?!
    если у вас нет собственного ИП, заработанные вами на фрилансе деньги по закону могут посчитать нелегальными
    J_j?!
    Да чтож Вы курили-то?:)


    1. shaman4d
      09.04.2019 11:32

      А что? Что-то поменялось и фрилансеры вышли из тени?


      1. edogs
        09.04.2019 12:50

        Это из серии «в огороде бузина в киеве дядька»©
        Фрилансерство это метод работы, а не путь ее оформления. Никакого знака равенства между фрилансерством и тенью нет. Фирма может принимать оплату на карту сбера и платить зарплату в конвертах, фрилансер может платить налоги.
        Юриспруденция это область работы. Никакого противопоставления фрилансерства и юриспруденции нет. Фрилансер вполне может работать в юриспруденции.
        Заработанные деньги не могут посчитать нелегальными только потому, что они заработаны на фрилансе. Если деньги не украдены и не получены от продажи наркотиков и т.д. — они легальны, ну а если украдены, то нелегальны даже в случае если их украла фирма. Т.е. опять никакой связи между нелегальностью и фрилансом.


        1. 2che Автор
          09.04.2019 14:20

          Вы слишком идеализируете, в РФ причину, к сожалению, могут выдуть из воздуха при желании. Почитайте сайт ЦБ.


  1. sfi0zy
    08.04.2019 21:02
    +2

    Микроформаты — весьма спорная штука, которая выглядит морально устаревшей и прямо скажем встречается в наши дни нечасто. Лучше отправить читателя почитать про Schema.org и OG. Полезнее будет.

    Вместо того, чтобы призывать писать глубокие селекторы на тегах вида «nav ul li a», от которых при поддержке и развитии проекта хочется застрелиться, лучше погуглить про CSS-методологии вроде БЭМ и компании.


  1. parcnfalb
    08.04.2019 22:25

    Последователь Тараса КТЛ и ХаудиХо? Автор одними и теми же тезисами бомбит.


  1. megahertz
    08.04.2019 22:49

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


  1. dom1n1k
    09.04.2019 01:56

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


  1. flancer
    09.04.2019 08:29
    +1

    Автор, не останавливайся, путь от 0 до 0.5 ты уже прошёл. Скажи спасибо всем комментаторам за науку и иди дальше от 0.5 и до 10.0. И пиши, не стесняйся. Гуру разных уровней много, а тех, кто не боится при этом делиться своим опытом — на порядки меньше. Дальше будет прощё. В конце-концов, это хабр, здесь так принято ;)


    1. Frimko
      09.04.2019 10:10

      Да что там делиться то, со временем тебе начинает казаться, что все очень простое и делиться такими банальностями не стоит. Вот делаешь ты стриминговую систему уже с год, плаваешь там как рыба в воде и чувствуешь, что все банально, серо и обыденно. Переходишь к обычной обработке картинок в canvas и думаешь, вот она, сложность! Ан нет, статей что решили твою проблему в инете пруд пруди.


  1. storm_r1der
    09.04.2019 13:05

    Но второй меньше нагружает и вас, и процессор,
    — ложь, селекторы читаются справа налево, поэтому поиск по имени классу будет гораздо быстрее, чем перебор всех a (!) -> li -> ul -> nav.


  1. YemSalat
    11.04.2019 12:03

    Слишком толстый троллинг