
Раньше веб был более странным местом
В прошлом году я поставила перед собой цель вернуть дух старого веба, креативность и шарм конца 90-х и начала 2000-х. В те времена не было правил, ты ставил на веб-страницу что угодно, потому что это было твоё пространство, в котором можно делать всё, что пожелаешь.
И для целого поколения Интернет-пользователей наличие собственного веб-сайта было признаком крутости. Именно так обстояли дела тогда, в эпоху до появления социальных сетей и web 2.0, о старых добрых статических личных страничках.
Сайты наподобие Geocities, Angelfire, Tripod и Expage предлагали для всех услуги бесплатного статического хостинга, поэтому произошёл бум количества личных веб-сайтов. У некоторых хостов даже были конструкторы веб-сайтов в стиле drag-and-drop, так что вам даже не нужно было изучать HTML.
Сегодня мы можем посмеяться над этими веб-сайтами, по сравнению с современными изящными и минималистическими сайтами они выглядят карикатурно. Но я считаю, что мы слишком далеко ушли в другом направлении, и сегодня многие веб-сайты выглядят одинаково. Те старые личные веб-сайты были отражением вашей личности.
Некоторые из них создавались семьями, где они делились фотографиями и новостями…

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

… а некоторые были фан-сайтами. Посмотрите на эти фреймы! Я сделала этот скриншот посередине прокрутки
<marquee>
.
Пару лет назад я играла в игру под названием Hypnospace Outlaw — совершенно безумный проект, в котором игрок является модератором разновидности веба 90-х, доступ к которому получаешь во сне. Источником вдохновения для домашних страниц в этой игре послужили веб-сайты Geocities (об игре есть очень хороший эпизод Noclip), и они вызвали у меня сильную ностальгию. Если вы в неё ещё не играли, крайне рекомендую! Она по-настоящему передаёт дух времени — индивидуальность и чудаковатость, делавшие эти сайты такими особенными.

Вернём себе эту чудаковатость
Мне бы хотелось, чтобы этот дух, эта экспериментальная и забавная сторона веба вернулись. Моя задача — показать вам, как мы можем быть столь же креативными, но пользуясь современными способами, обеспечивающими доступность пользования. Потому что какими бы интересными ни были старые веб-сайты, с точки зрения удобства они были кошмаром. Мы не пользовались семантическим HTML, применяли таблицы для создания структуры (вместо табличных данных), всё постоянно мерцало и двигалось. К счастью для нас, современный веб позволяет нам быть такими же творческими, в то же время учитывая удобство пользователя на другой стороне браузера.
Поэтому, естественно, я создала веб-сайт в стиле 90-х, использующий некоторые из моих любимых веб-тропов. Я по максимуму использовала современный HTML, CSS и JS. Давайте изучим некоторые из особенностей и посмотрим, как можно их воссоздать!

Анимированные GIF
Сайты GeoCities были полностью замусорены гифками. Горящее пламя, строительные рабочие, разделители, даже анимированные маркеры списков. Анимации были очень забавными, и способность уместить так много в такой маленький размер файла была своего рода искусством.

Сегодня размещать анимации на сайтах проще простого, будь то скромные GIF (Интернет сегодня стал намного быстрее), более современные форматы наподобие
webm
и gifv
, или даже SVG-анимации, реализованные при помощи CSS или библиотек типа GreenSock. Однако мы можем сделать нечто большее.Стандартный код добавления изображения с тех времён не особо изменился:
<IMG SRC="flames.gif">

Разумеется, в те времена мы писали весь HTML заглавными, потому что на то была какая-то причина. Возможно, XHTML? Как бы то ни было, в конечном итоге все посетители видели GIF, хотели они того, или нет. Для людей с эпилепсией, вестибулярными нарушениями и другими заболеваниями, при которых движение вызывает тошноту, автоматическое воспроизведение GIF — это большая проблема. К счастью, сегодня мы можем это исправить при помощи того, чего в старые времена у нас не было!
▍ Медиа-запрос prefers-reduced-motion
Благодаря этому медиа-запросу мы можем воспроизводить GIF, если у пользователя на компьютере не включено снижение подвижности (reduced motion), чтобы нашим трэшовым веб-сайтом мог насладиться любой, вне зависимости от его состояния здоровья.
▍ Обуздываем медиа-запросы при помощи элемента picture
Элемент HTML5
picture
позволяет нам указать изображение и потенциальные альтернативные источники для него.<picture>
<source srcset="underconstruction.gif"
media="(prefers-reduced-motion: no-preference)">
<img src="underconstruction.png"
alt="Under construction" />
</picture>
В приведённом выше фрагменте кода, как и раньше, есть тэг
img
, но на этот раз он демонстрирует неподвижную версию GIF, которую я создала, открыв GIF в режиме предварительного просмотра, вытащив первый кадр и сохранив его как PNG. Тэг source
содержит URL файла GIF, он срабатывает, только когда удовлетворено требование его атрибута media
. Поэтому если у вас не включено reduced motion, то источник изображения будет заменён анимированной версией GIF. Магия!
Эффекты текста
Помните
<marquee>
? Этот тэг заставлял текст скроллиться по экрану подобно бегущей строке.А те, кто пользовался Netscape, должны помнить печально известный тэг
<blink>
, заставлявший текст мерцать…Подобные эффекты текста не должны присутствовать в текстовых блоках. Даже если вам не нужно адаптировать сайт под людей с ограниченными возможностями, это сильно усложняет чтение текста. Есть веские причины для того, что оба этих тэга перестали поддерживать.
Я подумала, почему бы вместо них не побаловаться с заголовками? В былые дни мы делали крутые текстовые заголовки в любых графических программах, до которых могли добраться, даже в MS Word: тексты с пламенем, радужные шрифты и так далее.
В наши дни можно воссоздать эту магию при помощи CSS вместо изображения! И здорово то, что поскольку это обычный текст, всю обработку которого выполняет CSS, он остаётся доступным для людей с ограниченными возможностями.
Источником вдохновения для моего следующего трюка стала классика 90-х: Microsoft WordArt.

▍ WordArt, но на CSS
Хотя WordArt пришёл к нам не конкретно из веба 90-х, он возвращает меня к эстетике максимализма 90-х и определённо эстетически подходит к тому, что я пытаюсь создать.
Я покажу вам, как воссоздать два классических стиля WordArt при помощи современного CSS.

▍ Заливка градиента текстом при помощи background-clip
Мы не можем раскрашивать текст при помощи градиента в CSS (пока), но можем придать элементу градиентную заливку фона. При помощи свойства
background-clip
мы можем управлять тем, где отображается фон. В частности, мы можем указать background-clip: text
, чтобы фон отображался только там, где в элементе есть текст.Тогда если мы сделаем сам текст прозрачным, то через него будет виден градиентный фон.
background: linear-gradient(183deg, #6000CA 10%, #CA00CD 70%);
background-clip: text;
-webkit-background-clip: text;
color: transparent;
font-family: 'Impact';

Теперь давайте добавим свойство
transform
, чтобы текст ещё больше походил на реальный WordArt.transform: skewY(-8deg) scaleY(1.3) scaleX(0.8);

▍ Добавляем тень
Теперь нам нужно добавить светло-фиолетовую отбрасываемую тень. Но если мы попробуем использовать свойство
text-shadow
, она отобразится поверх текста!
Так происходит потому, что на самом деле мы видим фон, а реальный текст прозрачен и расположен выше. Если я изменю цвет текста на цвет body, то вы увидите, что я имею в виду:

Чтобы решить эту проблему, нам нужен элемент-обёртка, содержащий тень, чтобы он отображался за градиентным фоном, имеющим форму текста.
<span class="purple-wordart-wrapper">
<span class="purple-wordart">WordArt</span>
</span>
Мы добавим элементу-обёртке фильтр drop-shadow. Он добавляет drop-shadow той же формы, что у дочернего элемента, а поскольку фон обрезан до текста в дочернем
span
, drop-shadow тоже будет повторять эту форму!.wordart-wrapper {
filter: drop-shadow(2px 2px 0px rgba(130, 140, 251, 0.8));
}
Результат:

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

Здесь используется ещё одна градиентная заливка, поэтому мы снова воспользуемся
background-clip: text
, чтобы получить тот же эффект, а затем применим transform
, чтобы получить нужную форму.background: linear-gradient(
90deg,
#9c00ff,
#ff0000,
#ff8800,
#ffff00,
#02be02,
#0000ff,
#4f00ff,
#9c00ff
);
background-clip: text;
-webkit-background-clip: text;
color: transparent;
font-family: 'Arial Black', sans-serif;
font-weight: bold;
transform: scaleY(1.5) scaleX(0.6);
transform-origin: left;

Ещё раз применим элемент-обёртку, но на этот раз немного иначе. Эта графика имеет больше 3D-эффекта, тень становится более плоской и уходит влево, как будто мы смотрим на стоящий WordArt.
CSS способен это сделать!
▍ Создаём перспективу
.wrapper {
font-family: 'Arial Black', sans-serif;
font-weight: bold;
display: inline-block;
position: relative;
perspective: 150px;
perspective-origin: bottom center;
}
Можно использовать свойство
perspective
, чтобы перейти в своего рода «3D-режим». Он приказывает браузеру: «действуй так, как будто я нахожусь вот на таком расстоянии от элемента». В нашем случае это 150px.Затем мы задаём свойство
perspective-origin
, чтобы определить позицию, с которой мы смотрим на элемент. Я хочу, чтобы казалось, что мы перед ним, снизу.Таким образом мы изменяем то, как к элементу применяются преобразования с учётом перспективы, для манипулирования ею не только по осям X и Y, но и по Z.
Для создания тени я воспользуюсь псевдоэлементом
wrapper::before
, и присвою его содержанию значение «WordArt», чтобы отзеркалить текст. Благодаря этому «теневой» текст будет отображаться за радужным градиентом. Затем я применю преобразования, чтобы наклонить «тень»; свойство perspective
в элементе wrapper
будет изменять то, как он поворачивается и наклоняется..wrapper::before {
position: absolute;
content: 'WordArt';
color: #000;
opacity: 0.2;
bottom: -2rem;
left:35%;
transform: rotateX(60deg) skewX(65deg)
scaleY(2.8) scaleX(0.9);
transform-origin: bottom right;
}
Пока в CSS жёстко прописано, что тень имеет текст «WordArt». Если я захочу использовать этот стиль текста для других вещей, то мне как-то придётся динамически задавать содержимое текста тени. И это возможно при помощи функции CSS
attr()
!attr()
получает содержимое указанного атрибута элемента. Я назвала свой data-content
. Поэтому в нашем правиле wrapper::before
значение content: 'WordArt'
превращается в content: attr(data-content)
:.wrapper::before {
position: absolute;
content: attr(data-content);
color: #000;
opacity: 0.2;
bottom: -1rem;
transform: rotateX(60deg) skewX(60deg)
scaleY(2.8) scaleX(0.8);
transform-origin: bottom right;
}
Далее мы рендерим HTML с атрибутом:
<span class="rainbow-wrapper" data-content="Rainbow">
<span class="rainbow">Rainbow</span>
</span>
И теперь мы можем писать разные слова!

Код на Codepen
Неидеально, но мне кажется, выглядит вполне неплохо для заголовка ретро-сайта!
Музыка
В 2001 году у меня был магазин NeoPets. Сразу после загрузки его посетителя встречали нежные звуки песни Teenage Dirtbag в формате MIDI.
<EMBED SRC="mysong.mid" HIDDEN="true"
loop="yes" volume="10" autostart="true">
Естественно, с автоматическим и зацикленным воспроизведением. Никаких элементов не отображалось, музыка просто была. Но она сильно отвлекала, сбивала с толку и её невозможно было выключить.
Современные браузеры по вполне логичным причинам блокируют аудио с автовоспроизвединием. Оно чрезвычайно раздражает. К счастью, элемент HTML5
audio
даёт нам чуть больше контроля. <audio aria-label="Play music" controls
src="/soundtrack.webm"></audio>
Вы всё равно можете встраивать звук в свой веб-сайт! Просто сделать его выбираемым. Если это часть впечатления, которое вы хотите создать, то это вполне нормально, если пользователя устраивает музыка.
Также стоит добавить метку, внешнюю или
aria-label
, чтобы сообщить пользователю, что делает этот элемент.Элементы управления в браузере отображаются по умолчанию — то, что вы видите выше, будет выглядеть по-разному в Chrome, Firefox и так далее. Но можно использовать Web Audio API для настройки элементов управления, чтобы рендерить красивые кнопки и использовать JavaScript для управления воспроизведением этими кнопками.
Следы от курсора
▍ Раньше: Dynamic HTML
В старые времена след от курсора был очень крутой фишкой. Он говорил: «посмотри, что я могу делать при помощи JavaScript!». (А в моём случае, что мог делать с JavaScript сайт dynamicdrive.com.)
Это называлось Dynamic HTML: не технология сама по себе, а коллекция технологий (немного похоже на то, как мы сегодня используем термин JAMstack). HTML, CSS и JavaScript, только очень старая версия JavaScript. В то время всё выполнялось на стороне клиента, потому что ещё не существовало AJAX/клиентских HTTP-запросов. И реализации для двух главных браузеров того времени (Internet Explorer и Netscape) существенно различались. (Этот период называли «браузерными войнами», на сайте History Of The Web есть его хорошее описание.)
Это привело к появлению вещей наподобие анимированного следа курсора Dancing Stars. Этот курсор добавляет след из семи жёлтых «звёздочек» (крошечных квадратов) шириной в 3px, которые как будто следуют за курсором. Я не могу показать превью, потому что скрипт больше не работает.
Сначала нужно было проверить, работает ли скрипт в IE или Netscape, потому что реализация должна быть совершенно разной. В IE мы проверяли наличие
document.all
— функции, возвращавшей все элементы в DOM.Если она присутствовала, мы вызывали
document.write
(функцию, которую тоже нельзя больше использовать), вставляющую в DOM множество мелких квадратиков <div>
по 3px.if (document.all) {
document.write('<div id="starsDiv"
style="position:absolute;top:0px;left:0px">')
for (xy = 0; xy < 7; xy++)
document.write('<div style="position:relative;
width:3px;height:3px;background:#FFFF00;
font-size:2px;visibility:visible"></div>')
document.write('</div>')
}
В Netscape не было
div
, зато существовали LAYER
. По сути, это то же самое, но под другим названием, потому что разработчики браузеров в то время любили причинять боль.(Примечание: именно поэтому некоторые люди называли элементы
div
«div layers» — это название включает в себя оба элемента.)<LAYER NAME="a0"
LEFT=10 TOP=10
VISIBILITY=SHOW
BGCOLOR="#FFFF00"
CLIP="0,0,3,3">
</LAYER>
}
Если
document.layers
что-то возвращал, то мы знали, что находимся в Netscape, и можем делать то, что позволяет Netscape. В данном случае следующее:if (document.layers) {
window.captureEvents(Event.MOUSEMOVE);
}
Полный скрипт выложен на DynamicDrive.com.
▍ Сейчас: Canvas и requestAnimationFrame
Здесь основной труд за нас проделал Тим Холман, воссоздавший эффекты курсоров в стиле 90-х на современном JavaScript и HTML.
Курсоры Тима используют canvas, и это гораздо производительнее, чем рендеринг отдельных элементов в DOM. Также вы получаете гораздо более точный контроль над расположением элементов. Можете представить, как бы в старом скрипте мы пытались отрисовать такое количество звёздочек в DOM? При помощи canvas API и
requestAnimationFrame
(функции, позволяющей группировать анимации и эффективно обновлять их до следующей перерисовки браузера) мы можем рендерить множество мелких звёздочек, и чтобы при этом они красиво разгорались или затухали.▍ Медиа-запросы работают и в JavaScript!
Разумеется, следы курсора — это анимации, но не все хотят их видеть. Хорошо то, что мы можем использовать медиа-запросы в JS, как мы это делали в тэгах
<source>
CSS и HTML.const prefersReducedMotionQuery =
window.matchMedia('prefers-reduced-motion')
if (!prefersReducedMotionQuery.matches) {
cursor.init()
}
Вызывая
window.matchMedia
с именем запроса, который нам нужен (prefers-reduced-motion
), мы можем проверить указанное пользователем значение параметров подвижности, и инициализировать курсор, только если reduced motion не включено.Мы даже можем добавить к медиа-запросу event listener, чтобы при изменении его значения можно было динамически инициализировать или уничтожать курсор.
prefersReducedMotionQuery.addEventListener('change', () => {
if (prefersReducedMotionQuery.matches) {
cursor.destroy()
} else {
cursor.init()
}
})
Веб-кольца
Как можно было находить похожие сайты, когда поисковые движки ещё не обладали особыми возможностями? Разумеется, при помощи веб-колец (webring). Веб-кольцо — это сборник веб-сайтов, объединённых общим интересом или темой. Веб-кольца создавали ощущение причастности к сообществу, позволяли поместить на свой веб-сайт особую плашку.

Каждый сайт в веб-кольце имел подобную плашку, чтобы пользователь мог перемещаться по кольцу, и где-то находился бэкенд (вероятно, написанный на Perl), выполнявший всю работу по вычислению, где какой сайт должен быть в кольце.
Я создала собственное веб-кольцо для посетителей конференции State of the Browser 2022 с бэкендом в Google Sheets (для экономии времени и живой демонстрации) и Cloudflare Worker поверх них, чтобы выяснять, на какой сайт направлять пользователей. Он проверяет значение
request.referrer
, чтобы узнать, откуда пришёл вызов, ищет этот URL в списке сайтов и возвращает, соответственно, следующий или предыдущий.async function handleRequest(request) {
const { pathname } = new URL(request.url)
const data = await fetchAndParseCsv()
const referrer = request.referrer
[...]
Чтобы реализовать что-то более надёжное/профессиональное, рекомендую изучить комплект для создания веб-колец Макса Бёка.
Гостевые книги
И последнее по списку, но не по важности — это скромные гостевые книги! В те времена, когда ещё не существовало соцсетей, именно с помощью них мы выказывали свою признательность веб-мастерам. Я подумала, что для общения стоит создать не просто гостевую книгу, а что-то немного иное. Да, это гостевая книга, но в её основе лежит Twitter!

Я использовала технологию под названием webmentions: протокол, уведомляющий веб-сайт, когда кто-то ссылается на него на своём собственном веб-сайте или в Twitter. Webmentions (упоминания в вебе) собираются как фид (немного напоминающий RSS) и ассоциируются с доменным именем или хостом. Я поместила метатэги в
head
своего сайта, чтобы указать, что отслеживаю webmentions.Для сбора webmentions я использую webmention.io, хотя для этого вполне можно настроить и собственный сервер. На моём веб-сайте (localghost) я собираю webmentions во время сборки и публикую их под страницами, но для демо веб-сайта своего доклада я написала клиентский скрипт, получающий уведомления, потому что хотела показывать их в демо в прямом эфире.
Я использую brid.gy для сбора упоминаний из Twitter и отправляю их webmention.io, а затем мой сайт опрашивает webmention.io, чтобы получить фид упоминаний.
Вперёд, создавайте свои странные штуки!
Веб — потрясающая платформа с огромными возможностями для творчества и экспериментов. Мне бы хотелось увидеть, что вы будете создавать — если вы упомянете страницу этого поста на своём сайте или в Twitter, то ниже отобразятся webmentions.
Играй в нашу новую игру прямо в Telegram!
