Я увлеклась веб-дизайном и разработкой в конце 90-х. Чёрт побери, как это было давно. И как это было ужасно. Я имею в виду, что сделать сайт и опубликовать его представляло хитрое дело, а заказчиков можно было пересчитать по пальцам.

Мне казалось, что большинство разработчиков помнят те дни или хотя бы следующее десятилетие, но нет. Недавно мне попался на глаза твит, автор которого удивлялся технике простановки закруглённых углов до появления border-radius (сделать отдельную картинку для каждого закруглённого угла и точно её позиционировать). Я до сих пор помню, как мы затаив дыхание ждали, когда border-radius станет стандартом и с него уберут префикс в браузерах.

С другой стороны, многие лишь слегка попробовали веб-дизайн в старые времена и полагают, что с тех пор ничего не изменилось.

Эта статья для всех. История CSS и веб-дизайна, как я её помню.

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

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

Первые дни


В начале не было никакого CSS.

Это было очень плохо.

Мой любимый артефакт той эпохи — книга издательства O'Reilly, по которой я изучала HTML: The Definitive Guide. Несколько изданий этого руководства вышло в середине и конце 90-х гг. Книга действительно рассказывает только о HTML, вообще без единого упоминания CSS. У меня её больше нет и не могу найти сканы в интернете, но есть страница из более новой редакции этой книги HTML & XHTML: The Definitive Guide (об XHTML поговорим позже). Вот советы передового веб-дизайна образца 90-х годов:


«Чётко выделите горизонтальными линиями верхний и нижний колонтитулы»

Нет, это не border-top. Это <hr>. Заголовок страницы почти наверняка центрирован с помощью <center>.

На странице стандартные фон, шрифт и цвет текста. Отчасти потому, что это руководство сначала представляет начальные концепции; отчасти потому, что это чёрно-белая книга, а отчасти потому, что она отражала реальность — раскрашивать что-то на странице было огромным геморроем.

Допустим, вы хотите сделать красными все заголовки. Для этого нужно было проставить такие теги:

<H1><FONT COLOR=red>...</FONT></H1>

для каждого заголовка. Надеюсь, вы никогда не решите перейти на синий!

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

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

Помню, как на многих сайтах Geocities появилось интересное альтернативное решение: совершенно новый вид для каждой новой веб-страницы. Всё к чертям, верно? Просто на каждой новой странице делайте всё, что хотите.

Возможно, это была вершина веб-дизайна.

Чёрт, я скучаю по тем дням. Полностью открытый веб, ни твиттера, ни фейсбука. Если вам есть что сказать, вы должны сделать собственный сайт. Это было потрясающе. Никто не знал, что он делал; держу пари, что подавляющее большинство веб-дизайнеров в то время были невежественными подростками-любителями (как и я), которые копируют странички у других невежественных подростков-любителей. Половина интернета представляла собой фанатские порталы об аниморфах, с необъяснимыми заставками-предупреждениями, что сайт лучше всего работает при разрешении экрана 640?480 (предположительно, каждый 12-летний подросток с недостаточным разрешением экрана должен купить новый монитор). Все крутые ребята используют Internet Explorer 3 — самый продвинутый браузер. Однако некоторые лузеры всё ещё сидят в Netscape Navigator, поэтому на главной странице нужно разместить анимированную гифку “Best in IE”.

Это была также эпоха «безопасных для интернета цветов» — палитры из 216 цветов, где каждый канал равнялся 00, 33, 66, 99, cc или ff, потому что у некоторых ещё оставались 256-цветные мониторы! Сегодня мы не думаем об этом, принимая как должное 24-битный цвет.

На самом деле, многое из того, что мы сейчас воспринимаем как должное, тогда было непонятным и трудным. Хотите одинаковую навигацию на каждой странице сайта? Ладно, никаких проблем: скопируйте/вставьте код навигации на каждую страницу. Если обновите этот код, обязательно обновите каждую страницу — но, скорее всего, вы забудете это сделать на некоторых страницах, а сайт станет похож на археологические раскопки, с несколькими слоями страниц из разных «эпох».

Гораздо проще использовать фреймы, когда окно браузера разбивается на сетку, а в каждой ячейке загружается отдельная страница… но тогда люди запутаются, если попадут на отдельную страницу без фреймов, как это часто бывает, когда они приходят из поисковой системы, такой как AltaVista (не могу поверить, что объясняю фреймы, но в самом деле никто не использовал их с 2001 года… вы знаете, что такое iframes? Здесь буковка 'i' означает inline, то есть встроенные фреймы, чтобы отличать их от обычных фреймов на весь экран).

PHP ещё даже не получил такое название, и никто о нём не слышал. Эта странная смесь Perl и CGI была действительно трудной для понимания, и она не работала на вашем собственном компьютере, ошибки трудно найти и диагностировать, и в любом случае Geocities её не поддерживал. Если вы действительно везучий и продвинутый разработчик, то ваш хост работал на веб-сервере Apache, и тогда можете использовать его встроенный язык динамической сборки Server Side Includes и написать что-то вроде этого:

<BODY>
    <TABLE WIDTH=100% BORDER=0 CELLSPACING=8 CELLPADDING=0>
        <TR>
            <TD COLSPAN=2>
                <!--#include virtual="/header.html" --> 
            </TD>
        </TR>
        <TR>
            <TD WIDTH=20%>
                <!--#include virtual="/navigation.html" --> 
            </TD>
            <TD>
                (actual page content goes here)
            </TD>
        </TR>
    </TABLE>
</BODY>

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

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

…Итак, давайте посмотрим на сайт Space Jam.



Пример: Space Jam


Если вы не в курсе, «Космический джем» — величайший фильм всех времён. Он рассказывает о крайне недолговечной баскетбольной карьере кролика Багза Банни, который вместе с живым Майклом Джорданом спасают планету от какой-то угрозы со стороны инопланетян. Затем вышла серия очень успешных и крайне смешных продолжений этого фильма.

И нам действительно очень повезло, что спустя 24 года после своего запуска веб-сайт «Космического джема» всё ещё работает! Прямо здесь и сейчас у нас есть возможность изучить лучшее достижение веб-дизайна образца 1996 года.

Во-первых, обратите внимание, что каждая страница сайта является статической. И это статическая страница с расширением .htm, а не .html, потому что до версии Windows 95 мы ещё были привязаны к именам файлов в формате 8.3 (восемь символов для имени, три символа для расширения). Не знаю, почему это имело значение в URL, ведь никто не запускал Windows 3.11 на веб-сервере, но ладно.

Вот CSS для главной страницы:

<body bgcolor="#000000" background="img/bg_stars.gif" text="#ff0000" link="#ff4c4c" vlink="#ff4c4c" alink="#ff4c4c">

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

Обратите внимание на чрезвычайно точное расположение гиперссылок для навигации. Этот подвиг совершён так же, как все это делали в 1996 году: с помощью таблиц.

На самом деле, у таблиц есть одно функциональное преимущество перед CSS в вёрстке, что было очень важно в те дни, потому что с нажатым Ctrl вы могли выделить ячейку таблицы или даже несколько. Такой своеобразный «ретро-отладчик» показывает, как расположены ячейки в макете. Это было здорово, потому что первый нормальный отладчик Firebug вышел только в 2006 году — целое десятилетие спустя!



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

<table width=500 border=0>
<TR>
<TD colspan=5 align=right valign=top>
</td></tr>
<tr>
<td colspan=2 align=right valign=middle>
<br>
<br>
<br>
<a href="cmp/pressbox/pressboxframes.html"><img src="img/p-pressbox.gif" height=56 width=131 alt="Press Box Shuttle" border=0></a>
</td>
<td align=center valign=middle>
<a href="cmp/jamcentral/jamcentralframes.html"><img src="img/p-jamcentral.gif" height=67 width=55 alt="Jam Central" border=0></a>
</td>
<td align=center valign=top>
<a href="cmp/bball/bballframes.html"><img src="img/p-bball.gif" height=62 width=62 alt="Planet B-Ball" border=0></a>
</td>
<td align=center valign=bottom>
<br>
<br>
<a href="cmp/tunes/tunesframes.html"><img src="img/p-lunartunes.gif" height=77 width=95 alt="Lunar Tunes" border=0></a>
</td>
</tr>
<tr>
<td align=middle valign=top>
<br>
<br>
<a href="cmp/lineup/lineupframes.html"><img src="img/p-lineup.gif" height=52 width=63 alt="The Lineup" border=0></a>
</td>
<td colspan=3 rowspan=2 align=right valign=middle>
<img src="img/p-jamlogo.gif" height=165 width=272 alt="Space Jam" border=0>
</td>
<td align=right valign=bottom>
<a href="cmp/jump/jumpframes.html"><img src="img/p-jump.gif" height=52 width=58 alt="Jump Station" border=0></a>
</td>
</tr>
...
</table>

Это две первые строки, включая логотип. Вы уловили идею. Всё позиционируется внутри ячеек с помощью align и valign; часто применяются rowspan и colspan, есть немного <br>, чтобы отрегулировать вертикальное позиционирование на одну строку, где это нужно.

На странице можно найти и другие фантастические артефакты, включая заголовок, который содержит синтаксис Apache SSI! Должно быть, он незаметно для всех сломался, когда сайт переезжал по хостингам в течение многих лет своей жизни. Сейчас он размещается на Amazon S3. Ну знаете, Amazon? Книжный магазин?

<table border=0 cellpadding=0 cellspacing=0 width=488 height=60>
<tr>
<td align="center"><!--#include virtual="html.ng/site=spacejam&type=movie&home=no&size=234&page.allowcompete=no"--></td>
<td align="center" width="20"></td>
<td align="center"><!--#include virtual="html.ng/site=spacejam&type=movie&home=no&size=234"--></td>
</tr>
</table>

Ладно, посмотрим страницу Jam Central. Для аутентичности я уменьшила разрешение в браузере до 640?480 (хотя для полного погружения следовало зарезервировать ещё немного вертикального пространства под строку заголовка, панель задач и пять-шесть панелей инструментов IE).

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



Также обратите внимание на совершенно нечитаемый красный текст на текстурированном фоне, один из самых верных признаков веб-дизайна 90-х. Ты спросишь, почему не использовать нормальный фон для текста? Ты идиот. Как это сделать? Ведь атрибут background есть только у <body>! Можно поставить таблицу, но таблицы поддерживают только сплошной фон, это будет выглядеть скучно!

Но подождите, что это за новый навигационный виджет? Как удалось так развесить все ссылки? Ещё одна таблица? Ну, нет, хотя нередко дизайнеры заполняли таблицу кусками нарезанного изображения. Но здесь у нас imagemap, давно забытая функция HTML. Просто покажу вам исходник:

<img src="img/m-central.jpg" height=301 width=438 border=0 alt="navigation map" usemap="#map"><br>

<map name="map">
<area shape="rect" coords="33,92,178,136" href="prodnotesframes.html" target="_top">
<area shape="rect" coords="244,111,416,152" href="photosframes.html" target="_top">
<area shape="rect" coords="104,138,229,181" href="filmmakersframes.html" target="_top">
<area shape="rect" coords="230,155,334,197" href="trailerframes.html" target="_top">
</map>

Думаю, здесь всё более или менее понятно. Атрибут usemap прикрепляет карту изображений, которая определяется как набор кликабельных областей, красиво закодированных какими-то координатами.

И оно до сих пор работает! В HTML! Вы можете использовать это прямо сейчас! Хотя, наверное, нет.

Сетка миниатюр


Рассмотрим ещё одну случайную страницу. Например, «Фото из фильма». (Подождите, фото? В то время не знали слов «кадр» и «скриншот»? Ну ладно...)



Ещё один набор фреймов, но иначе устроенный.

<body bgcolor="#7714bf" background="img/bg-jamcentral.gif" text="#ffffff" link="#edb2fc" vlink="#edb2fc" alink="#edb2fc">

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

(Ещё одно интересное отличие от современной разработки. Сегодня многие дизайнеры предполагают, что все ресурсы обязательно будут загружены, а загрузку иногда представляют как некое неудобство, которое нужно обойти. Но не все же сидят на оптоволоконном соединении из Сан-Франциско в десяти метрах от магистрального канала).

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

<table cellpadding=10>
<tr><td align=center><a href="..."><img src="..."></a></td>...</tr>
<tr>...</tr>
<tr>...</tr>
<table>

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

Таков был самый продвинутый подход к отображению миниатюр в 1996 году. К этой маленькой головоломке UI мы ещё несколько раз вернёмся; вы можете посмотреть реальные примеры (и исходный код с образцом разметки) на отдельной странице.

Давайте ради интереса посмотрим на размер «полноразмерных, полноцветных, интернет-качества» кадров из фильма.



Эй, да они меньше 16 КБ! Такая картинка загрузится быстрее, чем за девять секунд!

(Помню о проблеме со встроенным видео, её не могли решить до появления тега HTML5 <video> спустя несколько лет. До тех пор приходилось использовать какой-нибудь проприетарный плагин, а все они были ужасны).

(Да, кстати: к изображениям внутри ссылок по умолчанию добавлялась цветная рамка. Здесь наличие ссылки очевидно, поэтому рамка выглядит лишней и раздражает. До появления CSS их следовало отключать для каждого отдельного изображения с помощью атрибута <img border=0>).

Обычная вёрстка тех времён


Вот с чего мы начинали, и это был полный отстой. Если вы хотели какой-то общий стиль более чем на нескольких страницах, ваши возможности были очень ограничены, а единственным инструментом оставался копипаст. Сайт Space Jam предпочёл вообще не беспокоиться о консистентности дизайна — как и многие другие.

Потом появился CSS. Это было настоящее чудо. Все эти повторы кода на каждой странице исчезли. Хотите сделать все заголовки верхнего уровня определённого цвета? Без проблем:

H1 {
    color: #FF0000;
}

Бам! И это всё. Независимо от того, сколько заголовков <h1> в вашем документе, каждый из них будет обжигающе красным, и вам никогда не придётся снова об этом думать. Ещё лучше: вы можете поместить данный фрагмент в собственный файл и применить этот сомнительный эстетический выбор к каждой странице своего сайта почти без усилий! То же самое относится к вашему великолепному фону из плитки, цвету ссылок и размеру шрифта в таблицах.

(Просто не забудьте обернуть содержимое тегов <style> в комментарии HTML, иначе старые браузеры без поддержки CSS отобразят их в виде текста).

Не обязательно применять теги ко всему подряд. CSS ввёл понятия «классов» и «ID», так что стиль распространяется только на специально помеченные элементы. Селектор типа P.important относится только к абзацам класса <P CLASS="important">, а #header затронет только <H1 ID="header"> (разница в том, что идентификаторы должны быть уникальными в документе, а классы могут использоваться любое количество раз). С помощью этих инструментов вы эффективно создаёте собственные теги, получая индивидуальную версию HTML, уникальную для своего сайта!

Это был огромный скачок вперёд, но в то время никто (наверное) не думал о том, чтобы использовать CSS для вёрстки. Когда в декабре 96-го была опубликована рекомендация CSS 1, она вообще почти не касалась вёрстки, а только отделяла существующие функции HTML от тегов, к которым они прикреплены. У нас были цвета шрифта и фон благодаря <FONT COLOR> и <BODY BACKGROUND>. Единственным, что хотя бы отдалённо влияло на расположение объектов на странице, было свойство float, эквивалентное <IMG ALIGN>, которое оттягивало изображение в сторону и включало обтекание текстом, как в газете. Не так уж и впечатляет.

Но в этом ничего удивительного. В HTML не было никаких реальных инструментов для вёрстки, кроме таблиц, а свойства таблиц слишком сложно обобщить в CSS или связать со структурой тегов, поэтому нечего было вносить в CSS 1. Мы просто немного автоматизировали, например, использование тегов <FONT>, так что веб-дизайн стал менее утомительным делом и менее подверженным ошибкам, код страниц стал чище и гораздо проще в поддержке. Довольно хороший шаг вперёд, и все с радостью приняли его, но таблицы остались главным инструментом для вёрстки.

Впрочем, это было нормально. По большому счёту, вашему блогу нужен только заголовок и боковая панель. Таблицы отлично с этим справляются, и эта базовая структура подходит для большинства ситуаций. Не так уж сложно скопировать/вставить несколько строк <TABLE BORDER=0> и <TD WIDTH=20%>.

В течение нескольких лет это был стандарт. Таблицы для вёрстки, CSS для… ну, для стиля. Цвета, размеры, жирный шрифт, подчёркивание. Был даже такой дурацкий трюк, когда ссылка подчёркивалась только тогда, когда на неё наводился курсор мыши. Красота!

(Забавный факт: HTML-код большинства сервисов электронной почты до сих пор не вышел из той эпохи).

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

Тёмные времена


Полтора года спустя, в середине 1998 года, нам подарили CSS 2 (кстати, обожаю фон на той странице). Это было скромное обновление, которое устраняло некоторые недостатки в различных областях, но самым интересным было добавление пары примитивов позиционирования: свойство position позволяло разместить элемент по точным координатам, а режим отображения inline-block позволял расположить блоки в строке друг за другом.

Такой дразнящий плод, но недосягаемый! Использование position казалось нормальным, но точное позиционирование в пикселях серьёзно противоречило гибкому дизайну HTML, а при изменении размера экрана всё обязательно разваливалось или возникали другие серьёзные недостатки. Этот скромный inline-block казался достаточно интересным; всё-таки он решал основную проблему HTML-вёрстки, которая заключалась в размещении объектов в ряд. Но в первое время ни один браузер не реализовал это свойство, поэтому дизайнеры его игнорировали.

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

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

  • IE 3 игнорирует все теги <style> в документе, кроме последнего.
  • IE 3 игнорирует псевдоклассы, так что a:hover читается как а.
  • IE 3 и IE 4 рассматривают границы auto как нулевые. На самом деле, этот баг сохранился чуть ли не до версии IE 6. Но это было нормально, потому что IE 6 также неправильно применял text-align: center для блочных элементов.
  • Если указать абсолютный URL для фонового изображения, IE 3 попытается открыть изображение в локальной программе, как если бы вы его скачали.
  • Netscape 4 распознаёт идентификаторы селекторов, такие как #id, но игнорирует h1#id как некорректный код.
  • Netscape 4 не переносит свойства — включая шрифт и цвет текста! — в ячейки таблицы.
  • Netscape 4 применяет свойства <li> к маркеру списка, а не к содержимому.
  • Если для одного и того же элемента указаны свойства float и clear (что может иметь смысл), Netscape 4 для Mac падает с ошибкой.

Вот с чем нам пришлось работать. И люди хотели сделать макет целой страницы на CSS? Ха.

Однако популярность этой идеи росла. Это даже стало своего рода объединяющим лозунгом продвинутой части дизайнерской элиты — лучшей практикой, которая приводилась как единственно верный аргумент в спорах. Использовать для вёрстки таблицы плохо, говорили они. Таблицы путают программы чтения с экрана (скринридеры), они семантически некорректны, плохо взаимодействуют с позиционированием CSS! Всё это правда, но принять её было очень трудно.

Что ж, вернёмся к этому через минуту. А сначала рассмотрим некоторую атмосферу, в которой развивалась веб-разработка в районе 2000 года.

Конец браузерных войн и последующий застой


Краткая версия такова: компания Netscape зарабатывала на продаже браузера Navigator (платный для бизнеса, бесплатный для личного использования), а затем на рынок вышла Microsoft с полностью бесплатным Internet Explorer, а потом Microsoft имела наглость связать IE с Windows. Можете себе представить? Операционная вместе с браузером? Это было большое дело. На Microsoft подали в суд, она проиграла, но в результате практически ничего не изменилось.

Microsoft всё равно сделала то, что хотела, и это сработало. Она практически уничтожила Netscape. Оба браузера были адски глючными, но глючили по-разному. Поэтому сайт, проверенный в одном браузере, почти наверняка развалится в другом. Это означало, что, когда доля рынка Netscape упала, веб-дизайнеры уделяли ему всё меньше внимания, так что всё меньше сайтов нормально в нём открывались, в результате чего доля Netscape Navigator падала ещё больше.

Наверное, не очень приятная новость для пользователей на других операционных системах, кроме Windows. Что забавно, потому что был IE 5.5 для Mac, и он, как правило, меньше глючил, чем IE 6 (кстати, Билл Гейтс в то время был не столько блестящим гиком, сколько агрессивным и безжалостным бизнесменом, который сделал состояние на том, чтобы намеренно уничтожать любую конкуренцию, стоящую на пути, что в итоге нанесло ущерб всей отрасли, это так, к слову).

Когда в середине 2001 года вышла Windows XP со встроенным Internet Explorer 6, браузер Netscape Navigator превратился из огромного Джаггернаута в крошечного лилипута для нишевых применений.

А затем, полностью и безраздельно захватив рынок, Microsoft остановилась. С момента своего создания Internet Explorer выпускался каждый год или около того, но после IE 6 последовала задержка более чем на пять лет. Он всё ещё оставался глючным, но в отсутствие конкурентов это не бросалось в глаза. Таким образом, и Windows XP выглядела достаточно хорошо, чтобы захватить рынок десктопов, и следующая версия Windows тоже не выходила примерно столько же времени.

Также остановилась работа консорциума W3C, который принимает стандарты (не путать с W3Schools, пиявками SEO). В середине 90-х годов HTML несколько раз пересматривался, а затем был заморожен как HTML 4. CSS обновился с первой до второй версии всего через полтора года, но на этом тоже замер. Незначительное обновление CSS 2.1 не достигнет статуса «рекомендации кандидата» до начала 2004 года, и потребовалось ещё семь лет, чтобы принять финальную версию.

В этой ситуации полного доминирования IE 6 казалось, что вся Сеть словно заморожена во времени. Стандарты не имели значения, потому что фактически существовал только один браузер. Всё, что он делал, становилось стандартом де-факто. По мере роста популярности интернета удушающая хватка IE также затрудняла использование любой платформы, кроме Windows, поскольку IE выпускался только для Windows. Никогда нельзя было дать гарантию, что веб-сайт будет работать в любом другом браузере.

(Появляется мысль, что монополии — это плохо. Должен быть какой-то закон против них!)

В то же время Netscape ещё ухудшила своё положение, затеяв масштабную переделку движка. В итоге вышел значительно более соответствующий стандартам Netscape 6, а ценой стало несколько лет отсутствия на рынке, где в это время IE продолжал наращивать свою долю. Браузер Netscape 6 никогда не доберётся даже до 10%, в то время как IE достигнет пика в 96%. С другой стороны, новый движок вышел с открытыми исходниками в составе Mozilla Application Suite, что позже сыграет свою роль.

Но до этого оставалось ещё несколько лет, а пока…

Режим совместимости


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

Видите ли, у контейнера (прямоугольное пространство, занимаемое элементом) есть несколько измерений: его собственная ширина и высота, затем отступ (padding), затем необязательная граница (border), а затем поле, отделяющее его от соседних контейнеров. CSS указывает, что все эти расстояния складываются друг с другом. Например, контейнер с такими стилями:

    width: 100px;
    padding: 10px;
    border: 2px solid black;

… займёт 124 пикселя в ширину, от границы до границы.

Однако IE 4 и Netscape 4 реализовали иной подход: они рассматривали ширину и высоту как измерение от границы до границы, из которого вычитаются границы и отступы, чтобы получить ширину самого элемента. То же самое поле в этих браузерах будет иметь ширину 100 пикселей от границы до границы, а для содержимого останется 76 пикселей.

IE 6 решил исправить это противоречие со спецификацией. К сожалению, простое внесение изменений сломало бы дизайн целого ряда веб-сайтов, которые нормально работали и в IE, и в Netscape.

Поэтому команда IE пришла к очень странному компромиссу: они объявили старое поведение (наряду с несколькими другими крупными ошибками) «режимом совместимости» (quirks mode, дословно «работа с причудами») и включили его по умолчанию. Для переключения на новый «строгий» или «стандартный режим» необходимо было указать "doctype" в начале документа, перед тегом <html>. Это выглядело примерно так:

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

В течение многих лет каждый должен был вставлять эту дурацкую строку в начало каждого HTML-документа (позже HTML5 упростит её до <!DOCTYPE html>). Если подумать, это действительно странный способ выбрать правильное поведение CSS. Декларация doctype была частью спецификации HTML с середины 90-х, но никто её не использовал. Я предполагаю, что идея Microsoft заключалась в том, чтобы разрешить выбор, не вводя проприетарные расширения. С помощью такой декларации можно избежать поведения, которое было изначально неправильным. Удобный выход для команды IE!

Самое смешное, что режим совместимости с «причудами» существует до сих пор. И он по-прежнему установлен по умолчанию во всех браузерах, двадцать лет спустя! Точный список «причуд» со временем менялся. В частности, ни Chrome, ни Firefox не используют контейнерную модель IE даже в этом режиме, но эмулируется немало других ошибок.

У современных браузеров также есть «почти стандартный» режим, который эмулирует только одну причуду. Возможно, это вторая по скандальности функция: если ячейка таблицы содержит только изображение, то пространство снизу удаляется. В соответствии с обычными правилами CSS, изображение находится в (пустой) строке текста, которая требует некоторого пространства снизу — для подстрочных элементов литер, таких как «y». Ранние браузеры не могли нормально с этим справиться, однако некоторые веб-сайты, созданные примерно после 2000 года, полагались на эту функцию, хотя во всём остальном полностью соответствовали стандартам. Например, они разрезали большое изображение на куски, которые помещались в ячейках таблицы вплотную друг к другу. Если в соответствии со стандартом добавить пустое пространство, то картинка развалится.

Однако вернёмся к прошлому. Хотя стандарты формально победили, это создало новую проблему. Поскольку в Сети доминировал IE 6, а декларации DOCTYPE были необязательными, то необязательно было думать о поддержке этих стандартов в «строгом режиме» работы браузера. Другие браузеры в конечном итоге эмулировали его, а нестандартное поведение стало стандартом де-факто. Веб-дизайнеры, которые заботились о таких вещах (к нашей чести, нас было много), запустили громкую кампанию по включению строгого режима, поскольку это был абсолютно необходимый первый шаг к обеспечению совместимости с другими браузерами.

Взлёт и падение XHTML


Тем временем W3C утратила интерес к HTML в пользу XHTML. Это попытка редизайна HTML с использованием синтаксиса XML, а не SGML.

(Что такое SGML, спросите вы? Я не знаю. Никто не знает. Это грамматика, на которой построен HTML, и это единственное, что о ней известно).

К чести консорциума, в то время были достаточно веские причины для такого решения. Как правило, HTML писали вручную (как и сейчас), а это значит обязательное присутствие случайных ошибок. Браузеры не отклоняли глючный HTML, а задействовали различные методы исправления ошибок — и, как во всём остальном, разные браузеры обрабатывали ошибки по-разному. Слегка искажённый HTML вроде нормально работал в IE 6 (где «нормально работал» означает «делал то, что вы от него ожидали»), но совершенно разваливался в других браузерах.

Консорциум W3C выбрал XML, потому что в начале 2000-х они видели в XML универсальное решение всех проблем. Если вы не знаете, в XML гораздо более явный и агрессивный подход к обработке ошибок — если ваш документ содержит ошибку синтаксического анализа, то весь документ недействителен. Это означает, что если вы выбрали XHTML и сделали одну опечатку, то в браузере вообще ничего не отобразится. Просто ошибка.

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

HTML не такой. В документе HTML мало надёжной повторяющейся структуры; даже эта статья на странице форматирована в основном тегами <p>, но также содержит неожиданные <em> внутри основного текста и случайные <h3> между абзацами. Не очень прикольно кодировать такое в виде дерева. И это важно, потому что примерно в то же время набирал силу рендеринг на стороне сервера, а сгенерированный HTML тогда — и сейчас! — поставлялся вместе с шаблонами, которые рассматривают его как текстовый поток.

Если бы HTML-страницы были чисто статическими документами, то XHTML мог бы сработать — вы пишете документ, видите его в браузере и знаете, что всё работает. Никаких проблем. Но создавать документ динамически и рисковать тем, что в какой-нибудь пограничной ситуации весь сайт похерится, а посетитель увидит просто ошибку в браузере? Это отстой.

Конечно, свою роль сыграло и распространение новомодного стандарта Юникод примерно в то время. Тогда не всегда было понятно, как именно его применять, а одной плохой последовательности UTF-8 было достаточно, чтобы считать искажённым и «недействительным» весь XML-документ!

Итак, после некоторого баловства о XHTML практически забыли. Он оставил после себя только два следа:

  • Все прекратили использовать имена тегов в верхнем регистре! До свидания, <BODY>, привет, <body>! XML чувствителен к регистру, и все теги XHTML были определены в нижнем регистре, поэтому заглавные теги просто не работали (забавный факт: JavaScript API по сей день передаёт названия HTML-тегов в верхнем регистре). Вероятно, с этим связан и рост популярности подсветки синтаксиса; мы уже не пишем в «Блокноте», как в 1997 году.
  • Куча людей до сих пор ставит самозакрывающиеся теги. Видите ли, в HTML есть два вида тегов: контейнеры, как <p>...</p>, и маркеры вроде <br>. Поскольку внутри <br> ничего не может быть, то не существует закрывающего тега </br>. В универсальной грамматике XML нет таких различий: там обязательно нужно закрыть каждый тег, а в качестве сокращения можно написать <br/>, что означает <br></br>.

    XHTML мёртв уже много лет, но по какой-то причине я до сих пор вижу, как люди пишут <br/> в обычных HTML-документах. За пределами XML эта косая черта ничего не делает; HTML5 определил её по соображениям совместимости, но она тихо игнорируется. Она даже вредит, поскольку может выдать <script/> за пустой тег <script> — но в HTML это определённо не так!

Я скучаю только по одной вещи в XHTML. Там можно было использовать метаязык XSLT, чтобы сделать шаблон «внутри браузера» (то есть вставить содержимое страницы в общий макет сайта) без написания скриптов. Это был единственный возможный способ сделать такое, и это было чертовски круто, если всё работало. Но какой-нибудь маленький глюк мог всё испортить.

Появление вёрстки CSS


Вернёмся к CSS!

Вы — начинающий веб-дизайнер, и по какой-то причине хотите попробовать использовать стили CSS для вёрстки, хотя они явно предназначены только для цветов и прочего. Что делать?

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

В CSS 2 появились некоторые режимы отображения, соответствующие частям таблицы. Но чтобы их использовать, нужны те же три уровня вложенности, что и в настоящих таблицах: сама таблица, затем строка, затем ячейка. Здесь их нет, и в любом случае, IE ещё нескоро начнёт поддерживать такие режимы.

Есть ещё position, но он постоянно стремится наложить объекты друг на друга. Хмм.

Что же остаётся?

На самом деле только один инструмент: float.

Я говорила, что float позволяет сделать обтекание изображения текстом в газетном стиле, но это весьма общее описание. В принципе, его можно применить к любому элементу. Если вам нужна боковая панель, можете прислонить её к левому краю, назначить ширину 20% страницы, и получите что-то вроде этого:

+---------+
| sidebar | Hello, and welcome to my website!
|         |
+---------+

У сожалению, свойства float таковы, что текст будет его обтекать. Таким образом, если текст на странице длиннее, чем боковая панель, то появится снизу — и иллюзия разрушится. Но это можно обойти. Спецификации CSS уточняют, что содержимое float не может обтекать друг друга, поэтому достаточно просто поставить ещё один float!

+---------+ +-----------------------------------+
| sidebar | | Hello, and welcome to my website! |
|         | |                                   |
+---------+ | Here's a longer paragraph to show |
            | that my galaxy brain CSS float    |
            | nonsense prevents text wrap.      |
            +-----------------------------------+

Этот подход работал, но его ограничения были гораздо хуже, чем ограничения таблиц. Например, если добавить нижний колонтитул, то он полезет вправо от основного текста, потому что для браузера «курсор» всё ещё находится вверху, справа от блоков float. Поэтому нужно использовать clear, чтобы прибить элемент под всеми float'ами. И если вы сделали боковую панель в 20% ширины страницы, а тело в 80%, то любой пробел между ними вытолкнет страницу за пределы экрана и покажет уродливую горизонтальную полосу прокрутки. Всегда нужно помнить эту глупую арифметику. Если у вас с обеих сторон установлены границы или фон, то они будут разной высоты, так что придётся делать действительно гротескные вещи, чтобы это исправить. А скринридеры будут читать всю боковую панель, прежде чем перейти к основному тексту, что довольно грубо для пользователей. Поэтому нужно использовать ещё более сложную настройку с тремя столбцами, из которых средний первым появляется в HTML.

В результате мы получаем дизайн, который красиво выглядит, хорошо работает и правильно масштабируется, но описан крайне хаотичным кодом CSS. Ничто из того, что вы писали, на самом деле не соответствовало тому, что вы хотели — а ведь это основные части дизайна, а не второстепенные врезки! Было трудно понять, как связан код CSS и то, что появляется на экране. И дальше ситуация станет намного хуже, прежде чем наконец-то улучшится.

Сетка миниатюр?2


Вооружившись новой игрушкой, мы можем улучшить нашу сетку миниатюр. Оригинальная табличная компоновка была невероятно утомительной, даже если не обеспечивать семантику тегов. Теперь можно сделать лучше!

<ul class="thumbnail-grid">
    <li><img src="..."><br>caption</li>
    <li><img src="..."><br>caption</li>
    <li><img src="..."><br>caption</li>
    ...
</ul>

Это идеал: в HTML хранится контент страницы в некоторой разумной форме, а затем CSS описывает, как это на самом деле выглядит.

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

Вам также нужно это странное заклинание clearfix, печально известное в ту эпоху. Поскольку float не перемещает «курсор», то у <ul> с элементами float нулевая высота. Он заканчивается точно там, где начинается, а все миниатюры float высыпятся снизу. Хуже того, поскольку у всех последующих элементов нет смежных float'ов, они будут полностью игнорировать миниатюры, продолжая рендеринг под пустой «сеткой» — создавая сплошной бардак!

Решение в том, чтобы добавить в конце списка фиктивный элемент, который не занимает места, но с CSS-атрибутом clear: both, что опускает его под всеми float'ами. Это эффективно толкает последний <ul> под миниатюры, и он аккуратно прилегает к ним снизу.

Позже браузеры начнут поддерживать псевдоэлементы «сгенерированного контента» ::before и ::after, что позволит полностью отказаться от фиктивного элемента. Таблицы стилей с середины 2000-х годов частенько включали такие строки:

.thumbnail-grid::after {
    content: '';
    display: block;
    clear: both;
}

И всё же это было лучше, чем таблицы.

DHTML


В качестве краткого отступления в мир JavaScript, новомодное свойство position действительно дало возможность отчасти динамического макетирования. Я от всей души против такой ереси, не в последнюю очередь потому, что никто никогда не делал этого правильно, но поиграться было забавно.

Так началась эпоха «динамического HTML», то есть HTML с эффектами JavaScript. Сейчас этот термин полностью вышел из моды, потому сейчас мы не можем сделать без JavaScript даже грёбаный статический блог. Начиналось всё гораздо более безобидно: подростки вставляли на страничку блёстки, которые следовали за курсором мыши, или маленькие аналоговые часы, которые тикали в реальном времени.

Самой популярной коллекцией таких скриптов был Dynamic Drive — этот сайт чудесным образом существует до сих пор. На нём лежат, наверное, сотни игрушек, которые не обновлялись с начала 2000-х.

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

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

Веб 2.0


Тёмные времена не могут длиться вечно. Произошёл ряд событий, которые вытянули нас на свет.

Одним из самых главных событий стал выход Firefox — или, для самых продвинутых, первоначально Phoenix, а затем Firebird. Версия 1.0 появилась в ноябре 2004 года — и стала хорошенько покусывать IE. Браузер работал на переписанном ядре Netscape 6, который извлечён из сердца набора программ Mozilla Suite в отдельное приложение. Он был быстрый, простой и намного лучше поддерживал стандарты, хотя абсолютно ничего из этого не имело значения.

Реальное значение имело то, что у Firefox были вкладки. В IE 6 их не было. Если вы хотели открыть вторую веб-страницу, вы открывали новое окно. Это чертовский отстой, ребята. Firefox стал настоящим чудом.

Конечно, Firefox был не первым браузером с вкладками, в полном браузере из наборе Mozilla Suite они тоже имелись, а в продвинутой «Опере» они были уже целую вечность. Но по разным причинам взлетел именно Firefox, не в последнюю очередь из-за того, что у него вверху не было гигантской чёртовой рекламной панели, как у «Оперы».

Конечно, дизайнеры продвигали Firefox в связи с поддержкой стандартов, но этот аргумент привлекал только других дизайнеров, а не их родителей. Одной из самых популярных и зрелищных демонстраций стал тест Acid2, предназначенный для проверки современных веб-стандартов. Он показывал симпатичный смайлик, если стандарты правильно отрабатывались, и адскую картину в IE 6.

Результат выполнения теста Acid2 в браузере IE 6

Ранний Firefox не был совершенным. Но безусловно, он намного лучше поддерживал стандарты, и вы могли видеть прогресс вплоть до момента, пока браузер полностью не прошёл все тесты с выпуском Firefox 3.

Распространению Firefox помог и более быстрый движок JavaScript: это было ещё до JIT. Он был намного, намного быстрее IE. Для примера, насколько я помню, IE 6 реализовал getElementById путём итерации по всему документу, даже в случае уникальных идентификаторов. Взгляните на старые объявления о релизах jQuery, обычно они сопровождались графиками производительности, и там все браузеры на порядок быстрее IE 6?8.

О, и тогда IE 6 был гигантской ходячей дырой в безопасности, особенно с нативной поддержкой произвольных бинарных компонентов, которым нужно было только нажатие «Да» на заумном диалоговом окне, чтобы получить полный и неограниченный доступ к вашей системе. Вероятно, это не способствовало репутации IE.

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

(Я бы сказала, что этот эффект открыл дверь для OS X, а также для iPhone. Я не шучу! Подумайте об этом: если бы браузер iPhone на самом деле не работал ни с чем, потому что все по-прежнему делали сайты для IE 6, то он остался бы просто дорогой альтернативой Palm. Помните, что сначала Apple даже не хотела выпускать собственные приложения — она делала ставку на интернет).

(Кстати говоря, Safari был выпущен в январе 2003 года, на базе форка движка KHTML из браузера Konqueror от KDE. Думаю, что в то время я использовала KDE, так что это было очень интересно, но никто особо не думал об OS X с её смешной долей рынка 2%).

Ещё один важный фактор появился 1 апреля 2004 года, когда Google анонсировала Gmail. Ха-ха! Смешно. Удобный веб-интерфейс для почты? Хорошо пошутили, Google.

О, чёрт. Они не шутят. Как вообще работает эта интерактивная штука?

Сегодня каждый веб-разработчик знает ответ — это XMLHttpRequest, названный так потому, что никто никогда не использовал его для запросов XML. Он изобретён Microsoft для почты Exchange, а затем клонирован Mozilla (я просто цитирую из Википедии).

Важно то, что XMLHttpRequest позволяет сделать HTTP-запрос из JavaScript. Теперь вы можете обновить только часть страницы с новыми данными, полностью в фоновом режиме, без перезагрузки. Никто не слышал об этой штуке раньше, а когда Google выкатила на ней целый почтовый клиент, это была абсолютная магия.

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

Примерно в том же духе в августе 2006 года был выпущен jQuery, похожее чудо. Он не только описал различия между API-интерфейсами “JScript” IE и стандартными подходами, принятыми всеми остальными (что было сделано ранее другими библиотеками), но и очень упростил работу с целыми группами элементов одновременно, что исторически оставалось огромной занозой в заднице. Теперь стало довольно легко повсюду применять CSS прямо из JavaScript! Это плохая идея, но в той ситуации не было лучшего варианта!

Я слышу, как вы возражаете: опять JavaScript! Это же статья о CSS?

Вы абсолютно правы! Я упоминаю о росте популярности JavaScript, потому что именно он непосредственно привёл к современному состоянию CSS, благодаря ещё одному большому фактору:

Амбиции


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

И люди начали фантазировать.

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

Другая проблема заключалась в том, что CSS 2 действительно хорош только в стилизации прямоугольников. Это было прекрасно в 90-е годы, когда у каждой ОС был интерфейс в прямоугольном стиле. Но наступили времена Windows XP и OS X, где всё стало блестящим, глянцевым и закруглённым. Было немного неловко, что закруглённые углы и аккуратные галочки с тенями есть в вашем файловом браузере, но нигде в интернете.

Так вернулись тёмные времена.

Эпоха CSS-хаков


Дизайнеры хотели много такого, чего CSS просто не мог предложить.

  • Закруглённые углы. Квадратные вышли из моды, и теперь все хотели кнопочки с круглыми углами, так как «за ними будущее» (нативные кнопки тоже почему-то вышли из моды). Увы, CSS не смог этого сделать. Ваши варианты:

    1. Сделать фоновое изображение скруглённого прямоугольника фиксированного размера и поместите его на кнопку фиксированного размера. Может, вообще отказаться от текста и просто сделать всё изображением. Фу.
    2. Сделать общий фон и масштабировать его, чтобы подходил по размеру. Более умно, но углы могут оказаться не круглыми.
    3. Сделать скруглённый прямоугольник, отрезать углы и края и поместить их в таблицу 3?3 с кнопкой посередине. Ещё лучше сделать всё это на лету средствами JavaScript.
    4. К чёрту, сделать весь сайт одним большим флэш-приложением lol

    Другая проблема заключалась в том, что IE 6 не понимал PNG с 8-битным альфа-каналом прозрачности; а только с 1-битным, то есть каждый пиксель должен быть либо полностью прозрачен, либо полностью непрозрачен, как у GIF. Приходилось мириться с зазубренными краями, приклеивать к картинке фон и применять различные трюки:

    filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='bite-my-ass.png');
  • То же самое: градиенты и тени! Без них не сделаешь модные блестящие кнопочки. Но здесь вы опять застряли на уровне работы с картинками.
  • С полупрозрачностью вообще дурдом. Большинство браузеров с самого начала поддерживали свойство CSS 3 opacity… кроме IE, который требовал специальный майкрософтовский filter. А если вам нужен только полупрозрачный фон, то понадобится полупрозрачный PNG, который… ну, вы поняли.
  • С самого начала jQuery поставляется со встроенными анимационными эффектами, такими как fadeIn, и они начали появляться повсюду. Это было похоже на веб-эквивалент того, как в середине 2000-х каждый пользователь Linux (включая меня) запускал этот чёртов куб рабочего стола.

    Очевидно, чтобы вызвать исчезновение элемента, в большинстве случаев нужен JavaScript, но его использование для управления фактической анимацией было немного тяжеловато и создавало нагрузку на браузеры. Просмотр с вкладками усугублял это, поскольку браузеры были в основном однопоточными, и по разным причинам каждая открытая страница выполнялась в одном потоке.
  • О! Чередование цветов фона на строках таблицы. С тех пор это вышло из моды, но я думаю, что это позор, потому что придумавший это человек сделал таблицы более легкочитаемыми. Но CSS не давал решения, поэтому вы должны были либо написать для каждой второй строки класс типа <tr class="odd"> (надеюсь, что таблица генерируется с помощью кода!) или сделать какую-нибудь ерунду на jQuery.
  • CSS 2 ввёл дочерний селектор >, поэтому вы можете писать такие вещи, как ul.foo > li для стилизации специальных списков, не путаясь во вложенных, но IE 6 — чёрт побери — не поддерживал это!

Но всё это чисто эстетические соображения. Если вы интересовались вёрсткой, что ж, появление Firefox сразу сделало вашу жизнь одновременно и намного проще, и намного сложнее.

Помните inline-block? Firefox 2 на самом деле его поддерживает! Он был глючным и скрытым за вендорским префиксом, но он более или менее работал, что позволило дизайнерам пробовать его использовать. А потом вышел Firefox 3, который более или менее нормально его поддерживал, что казалось чудом. Третья версия нашей сетки миниатюр не сложнее, чем width и inline-block:

.thumbnails li {
    display: inline-block;
    width: 250px;
    margin: 0.5em;
    vertical-align: top;
}

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

Конечно, здесь имелись некоторые недостатки. Например, ничего нельзя сделать с оставшимся пространством, поэтому существовал риск появления большого поля справа на нестандартно больших экранах. Оставалась и проблема разрыва сетки широкой ячейкой. Но, по крайней мере, это не float.

Оставалась одна маленькая проблема: IE 6. Он технически поддерживал inline-block, но только на естественно встроенных элементах, таких как <b> и <i>, но не <li>. То есть не то, как вы на самом деле хотите (или думаете) использовать inline-block. Эх.

К счастью, в какой-то момент абсолютный гений обнаружил hasLayout, внутреннюю оптимизацию в IE, которая помечает, есть ли у элемента… э-э… разметка. Послушайте, я не знаю. В основном он изменяет путь рендеринга для элементов — так что появляются не эти, а уже другие баги, как режим совместимости на основе каждого элемента! В итоге получается, что всё вышеописанное работает в IE 6, если добавить пару строк:

.thumbnails li {
    display: inline-block;
    width: 250px;
    margin: 0.5em;
    vertical-align: top;
    *zoom: 1;
    *display: inline;
}

Звёздочки в начале делают свойство недействительным, поэтому браузеры должны игнорировать всю строку… но по какой-то непонятной причине IE 6 игнорирует звёздочки и принимает остальную часть правила (работала почти любая пунктуация, включая дефис или — мой личный фаворит — подчёркивание). Свойство zoom — это расширение Microsoft, которое всё масштабирует, с побочным эффектом постановки элементу свойства «разметки» (layout). И display: inline должен заставить каждый элемент вставить своё содержимое в одну большую строку текста, но IE обрабатывает элемент inline со свойством «разметки» примерно как inline-block.

И здесь мы видим истинный потенциал хаков CSS. Специфичные для браузера правила, с намеренно плохим синтаксисом, который один браузер проигнорировал бы, воспроизводят эффект, который по-прежнему непонятен из того, что вы пишете. Целые учебники объясняли, как сделать что-то простое, например, сетку, но чтобы это работало в большинстве браузеров того времени. Вы также увидите * html, html > /**/ body и всевозможную другую ерунду. Вот полный список! И помните хак “clearfix”? Полная версия, совместимая со всеми браузерами, немного хуже:

.clearfix:after {
  visibility: hidden;
  display: block;
  font-size: 0;
  content: " ";
  clear: both;
  height: 0;
}
.clearfix { display: inline-block; }
/* start commented backslash hack \*/
* html .clearfix { height: 1%; }
.clearfix { display: block; }
/* close commented backslash hack */

Стоит ли удивляться, что люди стали жаловаться на CSS?

Это была эпоха слепого копипаста в тщетных попытках заставить эту чёртову штуку работать. Пример: у кого-то (однажды я раскопала исходный код, но не могу найти его сейчас) была странная идея всегда устанавливать body { font-size: 62.5% }, поскольку относительные единицы — это якобы «хорошо», из желания переопределить кажущийся массивным размер шрифта браузера по умолчанию 16px (что, оказывается, правильно) и необходимости бороться с ошибками IE. Через некоторое время он перестал так делать, но ущерб был нанесён, и уже тысячи веб-сайтов поступали таким образом, считая это «лучшими практиками». Это означает, что если вы хотите изменить размер шрифта вашего браузера по умолчанию в любом направлении, то получится ерунда — если его уменьшить, и куча веб-страниц станут микроскопическими, если увеличить, то всё по-прежнему останется маленьким, если увеличить его ещё больше, то сайты, которые уважают ваше решение, станут огромными. По крайней мере, сегодня у нас лучшее масштабирование, я думаю.

Да, и помните: StackOverflow ещё не появился. Все знания передавались из уст в уста. Если вам повезло, вы знали о некоторых сайтах с такими советами, таких как QuirksMode и сайт Эрика Мейера.

На самом деле, посмотрите сайт Майера css/edge. Там есть некоторые дикие примеры, что люди делали, даже с помощью только CSS 1, ещё в 2002 году. Я по-прежнему думаю, что complexspiral — чистый гений, хотя в наши дни всё это делается с opacity и только одним изображением. Методы с сайта raggedfloat только несколько лет назад получили нативную поддержку в CSS, с появлением shape-outside! Этот автор также дал нам CSS reset, устраняющий различия между стилями браузеров по умолчанию.

(Роль Эрика Мейера в CSS сложно переоценить. Когда шесть лет назад умерла его маленькая дочь Ребекка, её увековечили собственным цветом CSS, rebeccapurple, уникальный случай. Вот как высоко ценит его интернет-сообщество! Ну вот, теперь мне придётся немного поплакать над этой историей.)

Будущее наступает, но постепенно


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

Очевидно, браузерам была нужна новая функциональность. Но просто выпустить её было недостаточно; Microsoft сделала много такого, и в основном это привело к новому беспорядку.

Но состоялось несколько отчаянных попыток. Поскольку голова W3C всё ещё сидела в собственной заднице — отвергая даже предлагаемые улучшения HTML в пользу XML — некоторые из активных браузерных разработчиков (Apple, Mozilla и Opera) решили основать собственный клуб. В июне 2004 года была сформирована рабочая группа WHATWG, и она начала работу над стандартом HTML5. В конечном итоге он полностью устранит необходимость в XHTML и устранит ряд проблем безопасности при работе с обычным HTML. Кроме того, он дал некоторые новые преимущества, такие как нативная поддержка аудио, видео и элементов управления формами для дат и цветов. И другие вещи, которые неуклюже поддерживались элементами управления на JavaScript. И, гм, до сих пор неуклюже там поддерживаются.

Затем появился CSS 3. Не знаю, в какой момент это произошло. Он появлялся медленно, изо всех сил, как цыплёнок, вылупившийся из яйца и не торопящийся, чёрт возьми, никуда идти.

Могу сделать много обоснованных предположений. Мне кажется, это началось с border-radius. Конкретно, с -moz-border-radius. Не знаю, когда он был впервые представлен, но баг-трекер Mozilla упоминает о нём ещё в 1999 году.

Смотрите, собственный пользовательский интерфейс Firefox отображается с помощью CSS. Если Mozilla хотела сделать что-то, что нельзя было сделать с помощью CSS, она добавляла своё собственное свойство с префиксом -moz, чтобы указать, что это их собственное изобретение. И если в этом нет никакого реального вреда, то делала свойство доступным для веб-сайтов.

Предполагаю, что толчок для CSS 3 действительно начался, когда Firefox взлетел — и дизайнеры обнаружили свойство -moz-border-radius. Внезапно появились встроенные закругленные углы! Больше никакой возни в Фотошопе, достаточно написать всего одну строчку! Практически в одночасье у всего и всюду были припилены круглые углы.

И оттуда всё покатилось как снежный ком. Общие проблемы по одной решались с помощью новых функций CSS, которые были объединены в новую версию CSS — CSS 3. Главные из них решали проблемы дизайна, упомянутые ранее:

  • Закруглённые углы с помощью border-radius.
  • Градиенты с помощью linear-gradient() и др.
  • Множественный фон сам по себе не был проблемой, но облегчал некоторые другие вещи.
  • Прозрачность с помощью opacity и альфа-канала в цветах.
  • Тени у контейнеров.
  • Тени у текста, которые были в CSS 2, но пропали в 2.1 и так и не появились.
  • Изображения для границ (border image), так что вы можете делать даже более причудливые вещи, чем просто закруглённые границы.
  • Переходы и анимации теперь выполняются с лёгкостью без необходимости использовать jQuery (или любой JS вообще).
  • :nth-child(), который решил проблему чередования строк с помощью чистого CSS.
  • Преобразования. Подожди, что? Это как бы просочилось из SVG, который браузеры также должны были реализовать, и который построен в значительной степени вокруг преобразований. Код уже был там, так что, эй, теперь мы можем вращать вещи с помощью CSS! Раньше не могли. Круто.
  • Веб-шрифты, которые были в CSS в течение некоторого времени, но реализованные только в IE и только с некоторыми тупыми DRM-загруженными шрифтами. Теперь мы не ограничивались четырьмя плохими шрифтами, которые поставляются с Windows и которые больше ни у кого нет!

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

Большая ирония заключается в том, что эти дизайнерские эффекты почти сразу вышли из моды, и теперь мы снова возвращаемся к плоским прямоугольникам.

Ад вендорных префиксов в браузерах


Увы! В мире по-прежнему было не всё в порядке.

Некоторые из этих новых штуковин были первоначально разработаны производителями браузеров и снабжены префиксами. Некоторые более поздние разработаны комитетом CSS, затем реализованы браузерами, когда дизайн всё ещё находился в процессе разработки. Таким образом, здесь тоже были префиксы.

И начался ад префиксов, который продолжается по сей день.

В Mozilla были -moz-border-radius, поэтому, когда Safari его реализовал, то назвал -webkit-border-radius (“WebKit” — это название эппловского форка KHTML). Затем спецификация CSS 3 стандартизировала его и назвала просто border-radius. Это означало, что если вы хотите использовать закруглённые границы, вам на самом деле нужно прописать три правила:

element {
    -moz-border-radius: 1em;
    -webkit-border-radius: 1em;
    border-radius: 1em;
}

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

Вы должны были делать так каждый чёртовый раз, потому что CSS не является языком программирования и не имеет макросов, функций и тому подобного. Иногда Opera и IE вводили собственные реализации с префиксами -o- и -ms-, в результате чего общее число строк достигало пяти. С градиентами стало намного хуже; синтаксис прошёл ряд серьёзных несовместимых ревизий, так что вы даже не могли полагаться на копирование/вставку и изменение имени свойства!

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

Хуже того, некоторые будут использовать только ту форму, которая работает в их любимом браузере. Всё стало особенно плохо с ростом мобильных веб-браузеров. Встроенные браузеры на iOS и Android — Safari (WebKit) и Chrome (первоначально WebKit, теперь форк), поэтому вам «нужен» только префикс -webkit-. Что затруднило работу Mozilla, когда она выпустила Firefox для Android.

Помните тот провал с IE 6? Вот мы и снова здесь! Ситуация была настолько дрянной, что Mozilla в конечном итоге решила реализовать ряд свойств -webkit-, которые по сей день поддерживаются даже в десктопном Firefox. Ситуация настолько глупая, что Firefox теперь поддерживает некоторые эффекты только через эти свойства, такие как -webkit-text-stroke, который не стандартизирован.

Более того, текущий форкнутый движок Chrome называется Blink, поэтому технически он не должен использовать свойства -webkit-. И всё же они есть. По крайней мере, это не так плохо, как путаница со строками user agent.

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

Вероятно, весь этот беспорядок стал огромным мотивирующим фактором для развития Sass и LESS, двух языков, которые производят код CSS (препроцессоров). У них очень похожие цели: оба добавляют в CSS переменные, функции и некоторые формы макросов, что позволяет исключить из вашего кода множество повторений, браузерных хаков и другой ерунды. Чёрт, да я сама всё ещё применяю SCSS, хотя в целом по индустрии его использование постепенно уменьшается.

Flexbox


Но потом словно ангел с небес спустился… flexbox.

Flexbox существует уже очень давно — частичная поддержка якобы была ещё в Firefox 2, аж в 2006 году! Он прошёл через несколько несовместимых ревизий и ему потребовалась целая вечность, чтобы стабилизироваться. Затем IE годами не мог внедрить поддержку, а вы же не хотите полагаться на вёрстку, которая работает только для половины вашей аудитории. Лишь только относительно недавно (2015? позже?) flexbox получил достаточно широкую поддержку для безопасного использования. И могу поклясться, что до сих пор сталкиваюсь с людьми, у которых Safari вообще не распознает его без префиксов, хотя Safari вроде бы отбросила префиксы пять лет назад…

Во всяком случае, flexbox — это CSS-реализация довольно распространённого инструмента компоновки GUI: у вас есть родитель с несколькими дочерними элементами, и у родителя есть некоторое количество свободного пространства, и оно автоматически разделяется между дочерними элементами. И это помещает объекты рядом друг с другом.

Общая идея заключается в том, что браузер вычисляет, сколько свободного места у родителя и «начальный размер» каждого ребёнка, вычисляет, сколько есть дополнительного пространства — и распределяет его в соответствии с гибкостью (flex) каждого ребёнка. Представьте панель инструментов: вы можете задать каждой кнопке фиксированный размер (flex 0), но добавить распорки, которые разделяют оставшееся пространство поровну, поэтому задаёте им flex 1.

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

С помощью этого мы можем ещё больше оптимизировать нашу сетку миниатюр:

.thumbnail-grid {
    display: flex;
    flex-wrap: wrap;
}
.thumbnail-grid li {
    flex: 1 0 250px;
}

Это просто чудо. Сразу можно забыть inline-block. Этот код очень ясно выражает то, что нам нужно.

…почти. У него по-прежнему проблема, что слишком широкие ячейки разорвут сетку, так как это всё ещё горизонтальный ряд, перенесённый на несколько независимых строк. Но это всё равно довольно круто и решает ряд других проблем вёрстки. Наверное, этого достаточно. Если только…

Я бы сказала, что массовое внедрение flexbox положило начало современной эре CSS. Оставалась только одна нерешённая проблема.…

Медленная, мучительная смерть IE


IE 6 очень долго уходил с рынка. До начала 2010 года или около того он никак не мог опуститься ниже 10% рынка (всё еще огромный кусок).

Firefox достиг версии 1.0 в конце 2004 года. IE 7 вышел только два года спустя, он предлагал лишь скромные улучшения, страдал от проблем совместимости с сайтами для IE 6, а многие пользователи IE 6 (преимущественно неопытные пользователи) вообще не видели причин для обновления. Vista поставляется с IE 7, но Vista оказалась своего рода провалом — я не верю, что когда-либо за всю свою жизнь она была близка к тому, чтобы обогнать XP.

Другие факторы включали корпоративные IT-политики, которые часто принимают форму «никогда ничего не обновляйте» — и часто по уважительной причине, поскольку я слышала бесконечные рассказы о внутренних приложениях, которые работали только в IE 6 по всевозможным ужасающим причинам. Затем была вся Южная Корея, которая по закону должна была использовать IE 6, потому что они закрепили в законе некоторые требования безопасности, которые могли быть реализованы только с помощью элемента управления ActiveX в IE 6.

Поэтому, если вы поддерживали веб-сайт, который использовался — или, хуже того, требовался для использования — людьми из бизнеса или из других стран, вы в значительной степени застряли с поддержкой IE 6. Люди, делающие маленькие личные инструменты и веб-сайты, сразу отказались от совместимости IE 6 и выставляли на сайты всё более неприятные баннеры для пользователей IE 6… Но если вы бизнесмен, как объяснить мгновенную потерю 20% потенциальной аудитории? Просто работай усерднее!

С годами напряжение росло, поскольку CSS становился всё более функциональным, а IE 6 оставался якорем. Он по-прежнему не понимал PNG alpha без обходных путей, а у нас тем временем появлялись всё более важные функции, такие как нативное видео в HTML5. Обходные пути становились всё более запутанными, а список функций, которые вы просто не могли использовать, становился всё длиннее. Я бы показала, как выглядит мой блог в IE 6, но вряд ли вы даже подключитесь к нему — поддерживаемый им TLS настолько древний и сломанный, что уже отключён на большинстве серверов!

Отдельные просьбы шли от отдельных разработчиков из команды YouTube. Ни у кого не спрашивая разрешения, они в июле 2009 года добавили предупреждающий баннер, умоляющий пользователей IE 6 переключиться на что-нибудь другое, поскольку поддержка устаревшего браузера скоро прекратится. В течение одного месяца глобальная доля трафика IE6 упала более чем на 10%. Не все герои носят плащи.

Я бы отметила начало конца IE6 тем днём, когда YouTube реально отключил поддержку IE 6. Это случилось 13 марта 2010 года, почти через девять лет после выпуска этой версии браузера. Не знаю, насколько YouTube влияет на корпоративных пользователей или южнокорейское правительство, но отказ крупной веб-компании от поддержки целого браузера посылает довольно сильное сообщение.

Конечно, существовали и другие версии IE, и многие из них были сами по себе различной головной болью. Но каждая следующая становилась менее болезненной, и теперь вам не нужно слишком много думать о тестировании в IE (теперь Edge). Как раз время для Microsoft отказаться от собственного движка рендеринга и перейти на клон Chrome.

Сейчас


CSS сейчас очень хорош. Вам не нужны странные хаки, чтобы просто разместить объекты рядом. Инструменты для разработки браузеров теперь встроены и чертовски удивительны — Firefox начал специально предупреждать вас, когда некоторые свойства CSS не вступают в силу из-за значений других свойств! Неясные неявные побочные эффекты вроде «контекстов укладки» (stacking contexts) теперь можно установить явно — свойствами вроде isolation: isolate.

На самом деле, позвольте мне просто перечислить всё, что приходит в голову насчёт современных возможностей CSS. Это не руководство по всем возможным видам использования стилей, но если ваши знания CSS не обновлялись с 2008 года, я надеюсь, что это разожжёт ваш аппетит. И всё это — просто CSS! Столько всего, что раньше было невозможно, болезненно или требовало неуклюжих плагинов, теперь поддерживается изначально — аудио, видео, произвольное рисование, 3D-рендеринг… не говоря уже об огромных эргономических улучшениях JavaScript.

Вёрстка


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

Контейнер flexbox раскладывает свои дочерние элементы в строку или столбец, позволяя каждому объявить свой размер «по умолчанию» и какую долю оставшегося пространства он хочет использовать. Эти контейнеры можно обернуть, переставить дочерние элементы без изменения порядка источника и выровнять дочерние элементы несколькими способами.

Столбцы могут разбить текст, ну, на несколько столбцов.

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

display: contents сбрасывает содержимое элемента в его родительский элемент, как будто его там вообще не было. display: flow-root — это, в основном, автоматический clearfix, только на десятилетие позже.

width теперь можно установить в min-content, max-content или функцию fit-content() для более гибкого поведения.

white-space: pre-wrap сохраняет пробелы, но разрывает линии там, где это необходимо, чтобы избежать переполнения. Также полезна pre-line, которая сворачивает последовательности пробелов до одного, но сохраняет литеральные новые строки.

text-overflow отсекает многословный текст с помощью многоточия (или пользовательского символа) при превышении лимита, а не просто усекает его. Также в спецификациях функция плавного скрытия текста (fade out), но она пока не реализована.

shape-outside изменяет форму обтекания текста. Может использовать даже альфа-канал изображения в качестве формы.

resize даёт произвольному элементу дескриптор resize (если у него есть overflow).

writing-mode задаёт направление письма. Если ваш дизайн должен работать в нескольких режимах, то некоторые свойства CSS поддерживают это, их можно использовать в качестве альтернативы стандартным свойствам: inset-block и inset-inline для позиционирования, block-size и inline-size для ширины/высоты, border-block и border-inlineдля границ, и похожие свойства для отступов.

Эстетика


CSS Transitions плавно интерполируют значение всякий раз, когда оно изменяется, будь то из-за эффекта типа :hover или, например, класса, добавляемого из JavaScript. CSS Animations похожи, но воспроизводят предзаданную анимацию автоматически. Оба могут применять ряд различных функций «плавности».

border-radius округляет углы контейнера. Все углы могут быть разных размеров, а также могут быть круглыми или эллиптическими. Кривая применяется также к границе, фону и любым теням прямоугольника.

Тени контейнеров можно использовать для очевидного эффекта создания тени. Вы также можете использовать несколько теней и тени inset для различных умных эффектов.

text-shadow делает то, что и говорит, хотя вы также можете сложить несколько теней для создания некоего подобия контура текста.

transform позволяет применить к элементу произвольное многоступенчатое преобразование — то есть масштабировать, поворачивать, наклонять, перемещать и/или выполнять преобразование перспективы, не затрагивая вёрстку.

filter (отличный от того, что в IE 6) предлагает несколько специальных визуальных фильтров, которые можно применить к элементу. Большинство из них изменяют цвет, но есть также blur() и drop-shadow() (в отличие от box-shadow, он применяется к внешнему виду элемента, а не к его контейнеру).

linear-gradient(), radial-gradient(), новый и менее поддерживаемый conic-gradient(), их варианты repeating-* — все они создают градиентные изображения и могут использоваться в любом месте CSS, где ожидается изображение, обычно как background-image.

scrollbar-color изменяет цвет полосы прокрутки, с неприятным побочным эффектом значительного снижения скорости прокрутки в нынешних браузерах.

background-size: cover и contain будут пропорционально масштабировать фоновое изображение, чтобы оно стало либо достаточно большим для полностью покрытия элемента (даже если он обрезан), либо достаточно маленьким, чтобы точно поместиться внутри (даже если элемент не покрывает весь фон).

object-fit — аналогичная идея, но для других объектов, таких как <img>. Соответствующее object-position работает как background-position.

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

text-decoration стал более причудливым, чем раньше; теперь вы можете задать цвет линии и использовать несколько различных типов линий, включая пунктирные, точками и волнистые.

Счётчики CSS можно использовать для произвольного нумерования произвольных элементов, предоставляя возможность использования <ol> на любом наборе элементов.

Псевдоэлемент ::marker позволяет стилизовать контейнер маркера элемента списка или даже полностью заменить его пользовательским счётчиком. Поддержка браузерами неполная, но улучшается. Аналогично, правило @counter-style реализует совершенно новый стиль счётчика (например, 1 2 3, i ii iii, A B C и т. д.) который вы можете использовать в любом месте, хотя пока его поддерживает только Firefox.

image-set() предоставляет список возможных изображений и позволяет браузеру выбрать наиболее подходящее из них на основе плотности пикселей экрана пользователя.

@font-face определяет шрифт, который можно загрузить с внешнего источника, хотя можно использовать Google Fonts.

pointer-events: none заставляет элемент полностью игнорировать мышь; он не реагирует на наведение, а щелчки проходят прямо через него к элементу ниже.

image-rendering может изменить метод интерполяции изображения на nearest-neighbor, хотя поддержка браузерами по-прежнему неоднородна, и вам может потребоваться также включить некоторые свойства, специфические для конкретного браузера.

clip-path обрезает элемент до произвольной формы. Есть также mask для произвольной альфа-маски, но поддержка браузерами неоднородна, и это вообще довольно сложная процедура.

Синтаксис и прочее


@supports позволяет прописывать разный CSS-код в зависимости от того, что поддерживает браузер, хотя в настоящее время это далеко не так полезно, как было бы в 2004 году.

A > B выбирает непосредственные дочерние элементы. A + B выбирает братьев и сестёр. A ~ B выбирает непосредственных (по элементу) братьев и сестёр. Квадратные скобки могут делать кучу вещей, чтобы выбирать на основе атрибутов; наиболее очевидным является input[type=checkbox], хотя можно делать интересные вещи и с соответствующими частями <a href>.

Сейчас существует целая куча псевдоклассов. Многие из них для элементов формы: :enabled и :disabled; :checked и :indeterminate (также применяется к <option>); :required и :optional; :read-write и :read-only; :in-range/:out-of-range и :valid/:invalid (для использования с HTML5 проверкой форм на стороне клиента); :focus и :focus-within; и :default (который выбирает кнопку формы по умолчанию и любые предустановленные флажки, радиокнопки и <option>'ы).

Для применения к конкретным элементам внутри набора родственных элементов есть :first-child, :last-child, а также :only-child; :first-of-type, :last-of-type и :only-of-type (где “type” означает название тега); есть :nth-child(), :nth-last-child(), :nth-of-type() и :nth-last-of-type() (для выбора каждого второго, третьего и так далее элементов).

:not() инвертирует селектор. :empty выделяет элементы без дочерних элементов и без текста. :target выбирает элемент, к которому перескочил фрагмент URL (например, если в адресной строке отображается index.html#foo, при этом выбирается элемент, идентификатор которого равен foo).

::before и ::after теперь с двумя двоеточиями для указания, что они создают псевдоэлементы, а не просто определяют область селектора, к которому они прикреплены. ::selection настраивает, как отобразится выделенный текст; ::placeholder изменяет, как должен выглядеть замещающий текст (в текстовых полях).

Медиазапросы делают просто целую кучу вещей, чтобы ваша страница могла адаптироваться в зависимости от того, как она просматривается. Медиазапрос prefers-color-scheme сообщает, установлена ли система пользователя на светлую или тёмную тему, поэтому вы можете автоматически настроить её соответствующим образом.

Вы можете записать полупрозрачные цвета как #rrggbbaa или #rgba, а также с помощью функций rgba() и hsla().

Углы можно описать как доли полного круга с помощью turn. Разумеется, deg и radgrad) также доступны.

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

calc() вычисляет произвольное выражение и автоматически обновляет его (хотя необходимость таких вычислений частично устраняет box-sizing).

Юниты vw, vh, vmin, and vmax позволяют задать длину в виде доли ширины или высоты окна просмотра, или в зависимости от того, что больше/меньше.

Фух! Я уверена, что многое забыла, и коллеги дополнят список в комментариях. Теперь я могу отвлечься от просмотра MDN и перейти к последней, забавной части статьи.

Современная сетка миниатюр


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

И вот как это просто:

.thumbnail-grid {
    display: grid;
    grid: auto-flow / repeat(auto-fit, minmax(250px, 1fr));
}

Готово! Это даёт нам сетку. И у вас мириады других опций, чтобы поиграть с ними, как и с flexbox, но это основная идея. Вам даже не нужно стилизовать сами элементы; бoльшая часть работы по компоновке выполняется в контейнере.

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

CSS-сетки также удобны для размещения <dl>'ов, что исторически было огромной головной болью: один <dl> содержит любое количество <dt>, за которым следует любое количество <dd> (включая ноль). Раньше единственным способом стилизовать это был float, что означало фиксированную ширину. Теперь вы можете просто указать <dt> в первой колонке и <dd> во второй, и CSS grid позаботится об остальном.

Как это выглядит на реальной страничке? Та история с боковой панелью? Посмотрите, насколько просто:

body {
    display: grid;
    grid-template:
        "header         header          header"
        "left-sidebar   main-content    right-sidebar"
        "footer         footer          footer"
        / 1fr           6fr             1fr
    ;
}
body > header {
    grid-area: header;
}
#left-sidebar {
    grid-area: left-sidebar;
}
/* ... etc ... */

Сделано. Легко. Также не имеет значения, в каком порядке перечислять детали в разметке.

С другой стороны


Веб — это всё ещё немножко катастрофа. Многие даже не знают, что flexbox и grid теперь поддерживаются почти повсеместно; но учитывая, сколько времени потребовалось, чтобы перейти от ранней спецификации к широкой реализации, я не могу их винить. Я только вчера видела совершенно новый маленький сайт, который состоял в основном из огромного списка «миниатюр» различной ширины, и он использовал float'ы! Даже inline-block нет! Я не знаю, кто научил их этим хитрым хакам и почему он не сказал ни слова о flexbox.

Но гораздо хуже то, что я до сих пор регулярно сталкиваюсь с сайтами, которые делают весь макет с помощью JavaScript. Если вы используете блокировщик скриптов uMatrix, ваш первый опыт — это куча текста, перекрывающая другую кучу текста. Неужели это шаг назад? Что там такого, что заголовок и боковая панель правильно располагаются только при выполнении скрипта? Это не похоже на загрузку страницы без CSS — в обычном HTML ничто не может перекрываться по умолчанию! Вы должны намеренно указать делать так!

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

Даже в версиях Google Docs/Sheets/etc. под Android, например, всего 5% возможностей веб-версий. Не знаю, что с этим делать.

Несбывшиеся варианты будущего


Не знаю, как дальше будет развиваться CSS, особенно теперь, когда flexbox и grid решили все наши проблемы. Смутно осознаю, что ведутся некоторые работы над более обширной математической поддержкой, и, возможно, некоторыми функциями для изменения цветов, как в Sass. Есть Painting API, который позволяет генерировать бэкграунд на лету с помощью JavaScript, используя Canvas API, что… довольно классно. Видимо, в спецификации уже попал attr() для вычисления значения любого свойства. Это кажется классным и может даже позволить вам реализовать HTML-таблицы полностью на CSS, но вы можете сделать то же самое с переменными. Я имею в виду, ну, «пользовательские свойства» (официальное название). Меня больше волнует :is() для соотнесения списков селекторов, и subgrid для вложенных подсеток.

Гораздо проще перечислить вещи, которые были в планах, но так и не реализовались.

  • display: run-in был частью CSS с версии 2 (еще в 98-м), но он в основном не поддерживается. Идея заключается в том, что один блок вставляется в следующий. Например, этот код:

    <h2 style="display: run-in;">Title</h2>
    <p>Paragraph</p>
    <p>Paragraph</p>

    Соответствует такой выдаче:

    Title Paragraph
    Paragraph

    И, хм, я начинаю понимать, почему это не поддерживается. Раньше он существовал в WebKit, но, вероятно, был настолько неработоспособен, что его удалили шесть лет назад.

  • «Альтернативные таблицы стилей» были популярны в начале 2000-х, по крайней мере, на нескольких сайтах моих друзей. Идея заключалась в том, что вы могли перечислить для своего сайта более одной таблицы стилей (предположительно для разных тем), и браузер выдаст пользователю их список. Увы, этот список всегда был скрыт в меню, поэтому в конце концов все, кто хотел несколько тем, просто реализовали переключатель тем на странице.

    Эта функция ещё поддерживается, но тот же Chrome никогда не беспокоился о её реализации, поэтому она фактически мертва.

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

    … у читателя может быть личная таблица стилей, чтобы приспособиться к индивидуальным человеческим или технологическим особенностям.

    Эй, звучит круто. Но этот пункт никогда не материализовался в качестве функции браузера. В Firefox есть userContent.css и URL-селекторы для написания правил по каждому сайту, но это не совсем понятная штука.

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

  • Распространённой проблемой (ну, для меня) является стилизация метки флажка в зависимости от его состояния. Стилизация самого флажка достаточно проста с помощью псевдоселектора :checked. Но если расположить флажок и его метку очевидным образом:

    <label><input type="checkbox"> Description of what this does</label>

    … то CSS не сможет обработать ни элемент <label>, ни текстовый блок. Оригинальный (сначала) селекторный движок jQuery предложил нестандартный псевдокласс :has():

    /* checkbox label turns bold when checked */
    label:has(input:checked) {
        font-weight: bold;
    }

    Ранние обсуждения по селекторам в CSS 3, видимо, стремились избежать этой темы, возможно, по причинам производительности. Несколько новая альтернатива состояла в том, чтобы выписать весь селектор, но иметь возможность изменить, к какой его части применяются правила, с помощью индикатора “субъект”. Поначалу это был псевдокласс:

    label:subject input:checked {
        font-weight: bold;
    }

    Позже они заменили индикатор на префикс !:

    !label input:checked {
        font-weight: bold;
    }

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

  • <style scoped> был атрибутом, который сделал бы правила CSS элемента <style> применимыми только к элементам в пределах родительского. Это означает, что вы могли бы отбросить произвольный (возможно, написанный пользователем) CSS вообще без риска для остальной части страницы. Увы, некоторое время назад этот атрибут тихо выбросили, предложив теневой DOM в качестве дико неуместной замены.

  • Кажется, когда я впервые услышала о веб-компонентах, они были шаблонами, которые можно было использовать для уменьшения дублирования в чистом HTML… Но не могу найти никаких следов этой концепции сейчас, и текущие реализации требуют JavaScript для определения, поэтому нет ничего декларативного, связывающего новый тег с его реализацией. Что делает их совершенно непригодными без JS. Увы.

  • <blink> и <marquee>. RIP. Хотя и то, и другое можно легко воспроизвести с помощью CSS-анимаций.

Вот и всё


Вы ещё здесь? Всё уже закончилось. Пора идти домой.

И, может, внесите свой вклад в противостояние монокультуре Blink, используя Firefox, в том числе на телефоне, если по какой-то причине вы не используете iPhone, который вообще запрещает другие браузерные движки. Это намного хуже, чем всё, что когда-либо делала Microsoft, но мы просто принимаем это по какой-то причине…