Создаём веб-сайт, как будто сейчас 1999 год

Kate

Administrator
Команда форума

Раньше веб был более странным местом​


В прошлом году я поставила перед собой цель вернуть дух старого веба, креативность и шарм конца 90-х и начала 2000-х. В те времена не было правил, ты ставил на веб-страницу что угодно, потому что это было твоё пространство, в котором можно делать всё, что пожелаешь.

И для целого поколения Интернет-пользователей наличие собственного веб-сайта было признаком крутости. Именно так обстояли дела тогда, в эпоху до появления социальных сетей и web 2.0, о старых добрых статических личных страничках.

Сайты наподобие Geocities, Angelfire, Tripod и Expage предлагали для всех услуги бесплатного статического хостинга, поэтому произошёл бум количества личных веб-сайтов. У некоторых хостов даже были конструкторы веб-сайтов в стиле drag-and-drop, так что вам даже не нужно было изучать HTML.

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

4pskbzm13pijyoky0on8jcnxoqa.png

Страница гордых дедушки Тома и бабушки Шерри (The Proud Grandparents Page)

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

oj7kcobjg-hfvuxfaqwuhufatce.png

Графика Лизы (Lisa's Graphics)

… а некоторые были фан-сайтами. Посмотрите на эти фреймы! Я сделала этот скриншот посередине прокрутки <marquee>.

dgnklror-7xyshnpegvhy5rrn84.png

Страница фаната Final Fantasy (Mognet Central)

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

q0huzlce2riby7kuwwfqyj_3p5q.png

Hypnospace Outlaw

Вернём себе эту чудаковатость​


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

Поэтому, естественно, я создала веб-сайт в стиле 90-х, использующий некоторые из моих любимых веб-тропов. Я по максимуму использовала современный HTML, CSS и JS. Давайте изучим некоторые из особенностей и посмотрим, как можно их воссоздать!

_ehrosuubl4kknspp0ih1bgqp4u.png

Домашняя страничка Софи (Sophie's Homepage)

Анимированные GIF​


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

k6puv9ktjyahasocmhj39vku0uq.png

Это скриншот cameronsworld.net, прекрасного архива гифок GeoCities, который сам по себе является произведением искусства.

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

Стандартный код добавления изображения с тех времён не особо изменился:

<IMG SRC="flames.gif">

gb2zi5c3cwmf-fqja0horj849qy.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. Магия!

ftic4luk0tdxc1jg2q4mavjcxla.gif


Эффекты текста​


Помните <marquee>? Этот тэг заставлял текст скроллиться по экрану подобно бегущей строке.

А те, кто пользовался Netscape, должны помнить печально известный тэг <blink>, заставлявший текст мерцать…

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

Я подумала, почему бы вместо них не побаловаться с заголовками? В былые дни мы делали крутые текстовые заголовки в любых графических программах, до которых могли добраться, даже в MS Word: тексты с пламенем, радужные шрифты и так далее.

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

Источником вдохновения для моего следующего трюка стала классика 90-х: Microsoft WordArt.

-p-rkypy2dnx4mhawj5hxyiq2kq.jpeg


▍ WordArt, но на CSS​


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

Я покажу вам, как воссоздать два классических стиля WordArt при помощи современного CSS.

whptosc6_fbapb-dmkb8kzham8y.png


▍ Заливка градиента текстом при помощи 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';

j-1yg-mlnxiioo1pfd0lwyseiqi.png

Красота!

Теперь давайте добавим свойство transform, чтобы текст ещё больше походил на реальный WordArt.

transform: skewY(-8deg) scaleY(1.3) scaleX(0.8);

h-3q6h3vl1nrsk0dl_bzzwqo1lw.png


▍ Добавляем тень​


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

wfhf5djxego0ocqjwqgxqhfgwb4.png


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

jwbr2yk4wmx5qd8k1u9xfdicigs.png


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

<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));
}

Результат:

szfq6o9ammuvisntriewd_uf9um.png


Невероятно!

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

0ipptk5ltx7sd2ubzp0outkpq1w.png


Здесь используется ещё одна градиентная заливка, поэтому мы снова воспользуемся 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;

mzyymxdmqxegjbhyypgg7tsfz4a.png


Ещё раз применим элемент-обёртку, но на этот раз немного иначе. Эта графика имеет больше 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>

И теперь мы можем писать разные слова!

062tnqm3qydxrigmyv0ypjeu1gs.png

Код на 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). Веб-кольцо — это сборник веб-сайтов, объединённых общим интересом или темой. Веб-кольца создавали ощущение причастности к сообществу, позволяли поместить на свой веб-сайт особую плашку.

fbernxsfxrdlu4czm-4eqsjqfji.png


Каждый сайт в веб-кольце имел подобную плашку, чтобы пользователь мог перемещаться по кольцу, и где-то находился бэкенд (вероятно, написанный на 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!

elqlqwnobxl_yjdargq7ymtdll4.png

Посмотреть гостевую книгу

Я использовала технологию под названием webmentions: протокол, уведомляющий веб-сайт, когда кто-то ссылается на него на своём собственном веб-сайте или в Twitter. Webmentions (упоминания в вебе) собираются как фид (немного напоминающий RSS) и ассоциируются с доменным именем или хостом. Я поместила метатэги в head своего сайта, чтобы указать, что отслеживаю webmentions.

Для сбора webmentions я использую webmention.io, хотя для этого вполне можно настроить и собственный сервер. На моём веб-сайте (localghost) я собираю webmentions во время сборки и публикую их под страницами, но для демо веб-сайта своего доклада я написала клиентский скрипт, получающий уведомления, потому что хотела показывать их в демо в прямом эфире.

Я использую brid.gy для сбора упоминаний из Twitter и отправляю их webmention.io, а затем мой сайт опрашивает webmention.io, чтобы получить фид упоминаний.

Вперёд, создавайте свои странные штуки!​


Веб — потрясающая платформа с огромными возможностями для творчества и экспериментов.


 
Сверху