Семинар 1: HTML и CSS
После изучения этого раздела вы узнаете, как можно отобразить контент в браузере пользователя, что такое HTML и зачем придумали CSS.
Из дополнительных материалов вы более подробно узнаете про HTML 5, про современное состояние CSS, что такое CSS-библиотеки и препроцессоры CSS.
Введение в HTML
Краткая историческая справка
В течение длительного периода своего существования вычислительная техника спонсировалась и разрабатывалась учеными, поэтому совершенно неудивительно, что раньше всего и лучше всего были решены задачи машинного представления и обработки числовой информации. Даже когда в 70-е и 80-е гг. прошлого века в IT вторгся большой бизнес, решению научных задач посвящалось большое количество времени и усилий.
После числовой обработки компьютеры стали учиться выполнять текстовую, и тут научное сообщество стало крупным поставщиком задач. Дело в том, что научные статьи, особенно технической направленности, изобилуют большим количеством сложновоспроизводимых средствами ЭВМ конструкций, например, математических формул. Быстро стало очевидно, что следует разделить отображение информации на экране и описание этой информации в файле. Описание должно быть максимально простым, желательно чисто текстовым и на каком-либо формальном (то есть ограниченном жестким сводом правил - так, что даже слова местами не поменяешь) языке. Отображение же в такой ситуации получается наоборот очень сложным, поэтому целесообразно написать программу, которая будет анализировать описание и рисовать на экране нужные символы.
Такой подход называется декларативным: вы пишете файл, в котором указываете, что именно вы хотите увидеть. Вы не описываете, как отображать информацию (в смысле не пишете конкретный алгоритм по типу "2 см вниз, 1 см налево, закрасить выделенную область и перейти в точку 0,0"). Как это нарисовать, за вас решает программа. Безусловно, как уже было сказано, программа получается крайне сложной, но и плюсы тут налицо: вы создаете файл, скидываете его коллегам и идете пить чай. В это время коллеги просматривают ваш файл и видят то же самое, что и вы, ведь у всех вас установлена одна и та же сложная программа.
Так появились настольные типографские системы (самая известная из которых TeX) и профессиональные типографские инструменты, например, язык SGML.
К тому моменту, когда Тим Бернерс-Ли занялся созданием того, что сейчас принято называть Всемирной Паутиной, все эти концепции были хорошо известны и многократно реализованы. Когда встал вопрос о том, как организовать обмен информацией во Всемирной Паутине (а изначально нужно было обмениваться научной информацией), не возникало никаких сомнений - нужно использовать декларативный язык. Было решено не пользоваться каким-то существовавшим на тот момент инструментом, а создать новый, простой в использовании, но подходящий для текстовых научных статей язык разметки. Так появился язык HTML, благодаря существованию и развитию котого сегодня вы, в частности, читаете этот текст.
Структура HTML-документа
Прыгнем с места в карьер и попробуем сразу создать HTML-документ. Для этого достаточно создать пустой файл и выставить для него расширение .html. Например, создадим пустой файл index.html.
Если открыть такой файл в браузере (а это скорее всего и произойдет, если вы щелкнете по нему два раза левой кнопкой мыши), то вы не увидите ничего, что вполне логично, ведь файл пуст.
Файл можно открыть и редактировать в любом текстовом редакторе или IDE (Блокнот, Notepad++, gedit, Sublime Text, Vim, Atom, Visual Studio Code, WebStorm и т.д.), здесь мы будем пользоваться редактором Visual Studio Code (VS Code). Открыть и просмотреть файл можно в браузере, которым вы пользуетесь каждый день. Но не забывайте сохранять файл после каждого изменения и перезагружать страницу в браузере:)
Большинство текстовых редакторов имеют режим автодополнения и способны генерировать шаблонный код. Попытаемся сгенерировать HTML-разметку, введя html в открытом файле index.html (чтобы это сработало, в вашем VS Code должен быть установлен пакет HTML-Snippets). Мы увидим следующее:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="screen" href="main.css" />
<script src="main.js"></script>
</head>
<body>
</body>
</html>
Немного определений
Тег
Это некоторый текст в символах <>. Теги как правило парные - открывающий (<html>) и закрывающий (</html>), но иногда тег бывает одиночным (например, тег <meta>), в таких случая согласно строгой спецификации XHTML тег должен закрываться следующим образом: <meta />. Этой рекомендацией можно принебречь, разметка все равно будет отображена из-за требований к совместимости браузеров со старой разметкой. Но лучше так не делать.
Элемент
Это пара тегов и все, что между ними (в случае одиночного тега элемент и тег - одно и то же). Таким образом, <head> - это тег, а
<head>
<meta charset="utf-8" />
<title>Page Title</title>
</head>
уже элемент.
Атрибут
Это свойство элемента. Атрибуты могут быть только у открывающего и одиночного тега и выглядят как <имя-тега имя-атрибута="значение">.
Существует два особых атрибута, которые есть у каждого элемента:
- id - уникальный идентификатор одного элемента на странице; на странице не может быть больше одного элемента с конкретным id;
- class - уникальный идентификатор группы элементов; единственное отличие от id состоит в том, что на станице может быть много элементов с одним и тем же классом.
Рассмотрим более подробно элементы приведенного шаблона HTML-раметки.
<!DOCTYPE html> - это строка, которая говорит браузеру, какую версию стандарта HTML использовать при отображении. Кокретно этот доктайп задает версию HTML 5, наиболее современную на данный момент. При выполнении лабораторных работ рекомендуется использовать ее, более старые версии на сейчас нужны только для обеспечения поддержки старых браузеров.
<html>...</html> - это корневой элемент документа, без него, как и без доктайпа, не может существовать ни один HTML-документ.
Элемент <head> служит для размещения метаинформации о странице. Метаинформация - это такая информация, которая влияет на отображение, но сама по себе не демонстрируется пользователю.
Элемент <meta> - это контейнер для метаинформации. В частности, можно задать кодировку символов (в данном случае utf-8) с помощью <meta charset="utf-8" />. Конструкция <meta name="viewport" content="width=device-width, initial-scale=1"> заставляет браузер подгонять размеры страницы под размер экрана устройства, чтобы пользователю смартфона не пришлось увеличивать контент и скроллить его после каждой загрузки страницы.
Элемент <title> содержит название страницы, которое будет отображено на вкладке в браузере.
Элемент <link> служит для подключения внешних файлов (чаще всего CSS), элемент <script> - JavaScript-кода. Эти два элемента, как и некоторые элементы <meta>, нам пока не нужны, поэтому для простоты мы их опустим.
Элемент <body> - это контейнер для содержимого, которое предназначается для демонстрации пользователю.
Пришло время удалить ненужные элементы и изменить заголовок страницы:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>TODO List</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
</body>
</html>
Список дел: начало
После того, как мы разобрались с HTML, можно начать работу над приложением "Список дел". Для начала нам необходимо сверстать одну страницу без какой-либо программной логики, это будет первый шаг на пути к реализации полноценного приложения.
Любая верстка начинается с эскиза, мы должны себе представить то, что будем верстать. Пусть на странице будет заголовок и основная часть. Основная часть в свою очередь делится на 2 секции - список дел, в котором будут отображены все добавленные дела, и форму добавления дела. Для наглядности нарисуем макет страницы.

Все действия по добавлению разметки будем проводить внутри элемента <body>. Разделим страницу на две части - заголовок и основную часть. В HTML существует элемент <div> - фактически это прямоугольник для ограничения какой-либо области. Элемент <div> в свое время использовался повсеместно, поэтому лет 5 назад было бы нормально написать так:
<body>
<!-- Заголовок -->
<div>Это заголовок</div>
<!-- Основная часть -->
<div>Это основная часть</div>
</body>
Однако из такой разметки (если не читать текст с пояснениями внутри элементов <div>) не очень-то понятно, где заголовок, а где основная часть. В нашем примере, конечно, все довольно просто, но если представить себе настоящую веб-страницу, на которой одни только <div> и их очень много, становится немного не по себе...
В W3C прекрасно понимают эту проблему, поэтому ввели в HTML 5 ряд тегов, которые с точки зрения браузера ведут себя так же, как <div>, но для программиста делают разметку более понятной. Среди них <header>, <footer>, <main>, <aside>. Мы в своей разметке будем приучаться пользоваться ими. Наш фрагмент разметки можно переписать как
<body>
<!-- Заголовок -->
<header>Это заголовок</header>
<!-- Основная часть -->
<main>Это основная часть</main>
</body>
и вы не увидите никакой разницы.
Важно!
Это не методические указания, скриншотов из браузера не будет. Попробуйте сами проработать материал и, если вам непонятно, запустить все примеры в браузере.
Заголовок
Верстка заголовка - самое простое, что нам придется сделать. Достаточно добавить следующую разметку:
<!-- Заголовок -->
<header>
<h1>TODO List</h1>
</header>
<h1> - это устаревший, но до сих пор активно используемый элемент заголовка. Существует 6 заголовков - от h1 до h6, все они отличаются только размером. Чем больше цифра, тем меньше размер.
Основная часть
Список дел
Для разметки списков существуют элементы <ul> (unordered list, если номера элементов не нужны) и <ol> (ordered list, если номера элементов нужны). И в тот, и в другой элемент должны быть вложены элементы <li> (list item).
В нашем случае номера дел в списке не нужны, поэтому воспользуемся элементом <ul>:
<!-- Основная часть -->
<main>
<ul>
<li>Дело 1</li>
<li>Дело 2</li>
</ul>
</main>
Мы знаем, что в <main> нужно будет вложить еще одну секцию, поэтому обернем <ul> в <div> и подготовим еще один пустой <div> для формы добавления дела. Это сделает нашу разметку более чистой, а самое главное, если мы заходим управлять взаимным размещением секций, такая обертка нам сильно поможет.
<!-- Основная часть -->
<main>
<!-- Список дел -->
<div>
<ul>
<li>Дело 1</li>
<li>Дело 2</li>
</ul>
</div>
<hr/>
<!-- Форма добавления дела -->
<div>
</div>
</main>
<hr> - это horizontal line - линия между секциями, которую мы добавили по стилистическим соображениям.
Форма добавления дела
Для того, чтобы пользователь имел возможность вводить данные на веб-сайтах, а сервер имел возможность получать эти данные, был разработан механизм форм: внутри элемента <form> размещаются поля ввода (элемент <input>), пользователь их заполняет и после нажатия кнопки Enter или специальной кнопки на форме происходит отправка данных.
Нам нужно только одно поле с названием дела и одна кнопка подтверждения, в HTML это будет выглядеть как
<!-- Форма добавления дела -->
<div>
<form>
<input />
<input type="submit" value="Создать" />
</form>
</div>
Элемент <input>, как можно заметить, может выступать в роли как поля ввода, так и кнопки подтверждения (<input type="submit" />). Однако в HTML есть элемент <button>, который является "настоящей" кнопкой. Мы можем использовать его, при этом все будет выглядеть и работать так же (главное не забыть указать type="submit"):
<!-- Форма добавления дела -->
<div>
<form>
<input />
<button type="submit">Создать</button>
</form>
</div>
Единственное, чего сейчас не хватает, это подсказки для пользователя: мы-то с вами знаем, что нужно вводить название нового дела, потому что сами разрабатываем эту страницу, а вот пользователи могут не догадаться. Воспользуемся атрибутом placeholder тега input. Плейсхолдер - это значение, которое будет отображено только если поле ввода пустое.
<!-- Форма добавления дела -->
<div>
<form>
<input placeholder="Введите дело" />
<button type="submit">Создать</button>
</form>
</div>
Итак, на первый взгляд все. Вот что мы получили в итоге:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>TODO List</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<!-- Заголовок -->
<header>
<h1>TODO List</h1>
</header>
<!-- Основная часть -->
<main>
<!-- Список дел -->
<div>
<ul>
<li>Дело 1</li>
<li>Дело 2</li>
</ul>
</div>
<hr/>
<!-- Форма добавления дела -->
<div>
<form>
<input placeholder="Введите дело" />
<button type="submit">Создать</button>
</form>
</div>
</main>
</body>
</html>
Введение в CSS
Чтобы изменить отображение элемента, можно пользоваться атрибутами, это мы с вами уже умеем. На заре развития HTML так и делали, но тут возникла одна проблема: если у нас есть один элемент, отображение которого мы ходим изменить, нет проблем, если два или три, то уже хуже, но терпимо. А если 10, 20, 100 элементов, отображение которых мы хотим изменить? Причем не как-то изменить, а так, чтобы эти 10, 20 или 100 элементов выглядели одинаково. Получается, мы должны 100 раз повторить один и тот же набор атрибутов. А что если мы захотим изменить отображение еще раз? Не очень-то заманчивая перспектива потратить часы, а может быть и годы своей жизни на изменение атрибутов...
Конечно же, ребята из W3C о нас позаботились и придумали CSS. CSS или каскадные таблицы стилей - это декларативный язык, который выделился из HTML. Правда, в отличие от HTML, этот язык вспомогательный, то есть не может использоваться самостоятельно без разметки.
CSS реализует несколько простых идей:
- Он разделяет разметку и ее отображение. За разметку отвечает язык HTML, а за отображение - CSS.
- Он позволяет применять одини и те же правила отображения к нескольким элементам (и, как следствие, менять правила отображения нескольких элементов сразу).
Эти идеи существенно повысили удобство работы с HTML и позволили создавать действительно сложные веб-страницы.
Любой файл CSS выглядит как:
селектор1 {
/* свойство 1 */
/* свойство 2 */
/* ... */
}
селектор2 {
/* свойство 3 */
/* свойство 4 */
/* ... */
}
Свойства - это ширина, высота, цвет текста, цвет фона, тень, границы и т.д. Их набор, заключенный в фигурные скобки {}, образует стиль. Это то самое изменение отображения элемента.
Но одного стиля браузеру мало, потому что непонятно, к каким элементам его применять. Правило, которое показывает браузеру, для каких элементов нужно применять стиль, называется селектором.
Проиллюстрируем использование селекторов на примере, однако для начала немного изменим разметку списка дел:
<!-- Список дел -->
<div>
<ul>
<li>
<input type="checkbox" id="1" />
<label for="1">Дело 1</label>
</li>
<li>
<input type="checkbox" id="2" />
<label for="2">Дело 2</label>
</li>
</ul>
</div>
Теперь мы добавили возможность отмечать дела как выполненные - у нас есть не только название дела, но и чекбокс рядом с ним.
Обратите внимание на атрибут for тега <label>. Он появился в HTML 5 и нужен для того, чтобы "приклеить" текст к полю ввода (в данном случае чекбоксу).
Если открыть обновленную страницу в браузере, вы увидите, что точки ненумерованного списка сохранились, а в элементах появились чекбоксы. Выглядит не очень красиво, хотелось бы изменить отображение списка. Тут-то нам на помощь придет CSS.
Мы не будем подключать CSS с помощью элемента <link>, а добавим инлайн-CSS (то есть включим CSS прямо в HTML). Для этого нужно добавить элемент <style> в <head>. Все стили нужно писать только внутри элемента <style>.
Чтобы точки не отображались, нам нужно указать свойство list-style-type: none; для нашего нумерованного списка. Необходимо только подобрать правильный селектор.
Для начала попробуем ul - по названию элемента:
ul {
list-style-type: none;
}
Этот вариант будет работать, но он не лучший. Дело в том, что теперь ни в каком ненумерованном списке не будут отображаться точки, а это может нас не устраивать. Гораздо лучше в данно ситуации воспользоваться атрибутами class или id. В рамках нашей задачи, вероятно, этот список будет уникальным, поэтому присвоим ему id:
<!-- Список дел -->
<div>
<ul id="task-list">
<li>
<input type="checkbox" id="1" />
<label for="1">Дело 1</label>
</li>
<li>
<input type="checkbox" id="2" />
<label for="2">Дело 2</label>
</li>
</ul>
</div>
#task-list {
list-style-type: none;
}
Символ # используется в селекторе элемента по id.
Теперь давайте сделаем так, чтобы при активации чекбокса текст дела зачеркивался.
Для этого нам нужно разработать более сложный селектор. Очевидно, что <input> - это просто чекбокс, весь текст находится в элементе <label>, значит зачеркивать надо его. Таким образом, в селекторе мы должны указать буквально следующее: "<label>, идущий прямо за <input>". В CSS есть возможность указания прямого следования элементов на одном уровне - знак +:
input + label {
text-decoration: line-through;
}
Применение этого правила приведет к тому, что текст будет зачеркнут даже если чекбокс не активен. Нам нужно выбрать только чекбоксы (<input> c атрибутом type="checkbox") и каким-то образом понять, что чекбокс активен.
Для выбора элемента с атрибутом в CSS существует селектор атрибута: input[type="checkbox"].
Для того, чтобы понять, что чекбокс активен (а также что мышка наведена на элемент, фокус помещен на поле ввода, ссылка посещена и т.п.) существует встроенная в CSS возможность - псевдоклассы. Браузер, конечно, знает, когда происходят описанные события, поэтому может грубо говоря "выставить флаги" - этот элемент нажат, эта ссылка посещена и т.д. На этом основана идея псевдоклассов - псевдокласс становится активным, когда наступает то или иное событие. Мы воспользуемся псевдоклассом :checked, то есть "чекбокс активен", таким образом наше правило применится только тогда, когда пользователь нажмет на чекбокс:
input[type="checkbox"]:checked + label {
text-decoration: line-through;
}
На этом можно было бы остановиться, но это все еще не лучший вариант по соображениям производительности. Самым быстрым в CSS считается использование селекторов атрибута id или class. Так как элементов <label> у нас два, а в перспективе может быть больше, то нам ничего не остается кроме как использовать class:
<!-- Список дел -->
<div>
<ul id="task-list">
<li>
<input type="checkbox" id="1" />
<label class="checkable" for="1">Дело 1</label>
</li>
<li>
<input type="checkbox" id="2" />
<label class="checkable" for="2">Дело 2</label>
</li>
</ul>
</div>
#task-list {
list-style-type: none;
}
input[type="checkbox"]:checked + .checkable {
text-decoration: line-through;
}
Как (не) работают формы в HTML??? 😠
На секунду вернемся к формам: попробуйте нажать на кнопку "Создать" - ничего не произойдет. Это явно не то, что мы ожидали. Давайте разбираться.
В разделе, посвященном формам, было написано буквально следующее:
Для того, чтобы пользователь имел возможность вводить данные на веб-сайтах, а сервер имел возможность получать эти данные, был разработан механизм форм: внутри элемента
<form>размещаются поля ввода (элемент<input>), пользователь их заполняет и после нажатия кнопкиEnterили специальной кнопки на форме происходит отправка данных.
Из этого описания непонятны два момента:
- Как браузер понимает, куда нужно отправлять данные?
- В каком виде происходит отправка данных?
Попробуем дать ответы на эти вопросы.
Как браузер понимает, куда нужно отправлять данные?
Для начала нужно определиться, что такое "куда". Во Всемирной Паутине существует специальная сущность, которая называется URL или Uniform Resource Locator. Она позволяет однозначно выбрать конкретный ресурс (веб-страницу) и получить ее. Прелесть URL в том, что путаницы не возникнет - другой страницы с тем же URL быть не может. http://www.example.com, google.com, ya.ru и т.п. - все это примеры URL. Общая схема его такова:
scheme:[//authority]path[?query][#fragment]
Все, что заключено в квадратные скобки - необязательные части URL.
Таким образом, было бы логично использовать URL для указания "места", в которое нужно отправить данные. Элемент <form> так и работает. У него есть атрибут action, в котором можно указать URL назначения. Сделать это можно указав:
- полный URL, например
<form action="www.google.com/search">, в таком случае браузер перейдет по указанному URL. - только path:
<form action="path/to/somewhere">(/в начале стоять не должен!), в таком случае браузер подставит scheme и authority с текущей страницы. Иными словами, если форма находится на http://www.example.com/form иaction="path/to/somewhere", то мы перейдем на http://www.example.com/path/to/somewhere. - ничего - можно не указывать action, тогда форма будет отправлена на текущую страницу.
У нас третий вариант и все равно не работает. Может быть, дело в другом?
У тега <form> еще есть атрибут method - он указывает, каким HTTP-методом нужно отправлять форму. Но вот загвоздка, этот атрибут не является обязательным и у него есть значение по умолчанию - GET... Может быть, нам просто было нечего отправлять?
В каком виде происходит отправка данных?
У нас есть много полей ввода, в которые пользователь вбивает информацию. Как бы вы организовали работу с этими полями, если бы были разработчиками браузера? Можно было бы, конечно, просто записать пользовательский ввод в виде строк в массив и отдать программисту, но это не настолько же удобно, насколько просто в реализации. Гораздо удобнее представлять эти данные в виде пар "ключ - значение", где значение - это то, что ввел пользователь, а ключ - это какое-то произвольное название поля, которое программист даст ему для своего удобства.
Звучит неплохо, но тогда к тегу <input> нужно добавить какой-то атрибут с названием этого поля ввода. Такой атрибут есть и он называется name. В этом-то и была наша проблема - браузер видел, что ни одного поле ввода не содержит атрибута name, и поэтому просто отбрасывал то, что мы ввели.
Если сейчас мы перепишем разметку формы в виде
<!-- Форма добавления дела -->
<div>
<form>
<input placeholder="Введите дело" name="task" />
<button type="submit">Создать</button>
</form>
</div>
а затем сохраним файл, откроем страницу в браузере, введем что-то и нажмем на кнопку "Создать", мы увидим, что URL страницы изменился - в него добавилось ?task=то, что вы ввели. Как мы уже знаем, эта часть URL называется query.
Если при вводе вы использовали латиницу, то вы увидите то, что вы ввели (но пробелы будут заменены знаком +, а некоторые специальные символы - закодированы). Если вы использовали русские буквы, вы увидите только кодировку, так называемый percent-encoding, потому что в URL есть некоторые ограничения на представление символов, не входящих в латинский алфавит.
Объединяя полученные знания
Таким образом, форма работает по следующему принципу:
- Вы помещаете в элемент
<form>столько элементов<input>, сколько вам необходимо. У каждого тега<input>заполняете атрибутname(следите, чтобы он был уникален в пределах формы - браузер никак не отреагирует на повторяющиеся названия полей, а вот вам потом может быть сложно найти ошибку). - Вы указываете (при необходимости) атрибуты
actionиmethodтега<form>. - Когда вы сабмитите форму (подтверждаете ее отправку), браузер переходит по указанному вами в
actionURL (см. правила выше) и добавляет к нему query. То есть по умолчанию данные формы передаются в URL.
Для формы
<form>
<input name="name1" />
<input name="name2" />
<input type="submit" value="Отправить" />
</form>
правило записи параметров в query такое:
?name1=value1&name2=value2
Здесь value1 и value2 - это то, что ввел пользователь в name1 и name2 соответственно.
Обратите внимание, что для разделения query-параметров используется символ & (амперсанд)!
Заключение
Сегодня мы научились верстать HTML-страницы, применять CSS по назначению и поняли, как работают формы. Мы сделали простую страницу со списком дел, однако помимо того, что эта страница выглядит не очень, она пока даже не работает и ее можно открывать только на своем компьютере. Однако не стоит отчаиваться, с будущем мы обязательно исправим эти недостатки. Вот тут доступен полный исходный код примера.
Полезные ссылки
Для дальнейшей работы вам понадобятся справочные материалы по HTML и CSS. В методических указаниях к лабораторным работам справочные материалы приведены в количестве, достаточном (даже более чем) для выполнения лабораторных работ, однако в течение этого курса, не говоря уже о дальнейшем, вы можете столкнуться с какими-либо задачами, решения которых не будут освещены в методичках.
HTML и CSS - это достаточно старые технологии, поэтому по ним существует большое количество документации, в том числе на русском языке. Сразу следует отметить, что в веб-разработке наибольшее предпочтение отдается документации на английском, так как она наиболее свежая и актуальная, но пока не обязательно читать ее (хотя как правило техническая документация написана гораздо более простым языком, чем газеты и уж тем более художественная литература). Можно опираться на сайты:
Также очень важно научиться быстро искать необходимую информацию. Опыт показывает, что наиболее релевантная информация по программированию выдается поисковой системой Google и DuckDuckGo, однако это не является их рекламой. Также, по возможности, искать информацию следует на английском языке. чаще всего вы будете находить ответы на StackOverflow - это информационный портал, на котором собраны миллионы вопросов и ответов по различным областям IT.
Больше полезных ссылок доступно в дополнительных материалах.