html

'

Сегодня с дочкой ходили по магазинам и в одном из них я обратил внимание на надпись на упаковке, которая меня сильно озадачила. Думаю, веб-разработчики меня хорошо поймут.
В надписи используется ' — это специальный технический код для апострофа. Он иногда проникает в обычную жизнь из-за бага, и я не могу понять — это как раз такой случай или специфическая ирония, понятная только в профессиональной среде? Если второе, то что за ниша такая у этой игрушки?
Three Mr. PA blind box toy packs are displayed side-by-side, each featuring six different panda designs and priced at NT$160.
Надпись «'» — это такая ирония?

9 комментариев

«Виола»: тег CHANGED

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

В «Виоле» я часто нахожу начатые и неоконченные части реализации какой-нибудь неизвестной сейчас спецификации. Если каким-то образом становится понятно как это должно работать, я стараюсь эти места дописать.

Так случилось и с тегом CHANGED. Я давно заметил его в коде, но не понимал как он должен работать. По коду про него было известно, что он должен был выделять часть текста оттенком жёлтого (точнее — цветом LemonChiffon1), имел два атрибута ID и IDREF и при этом был не блочным.

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

Тогда я решил, что это просто ошибка в коде и реализовал тег так как я его понимаю. Но было непонятно что делать с атрибутами, особенно с IDREF. По имени понятно, что это какая-то ссылка на ID, но как это должно работать? В общем, реализацию я просто выкинул, так как она точно не соответствовала тому как это задумывалось.

Я записал себе в список дел когда-нибудь разобраться с этим тегом и пошёл дальше. Прошло несколько недель и на днях мне повезло.

В архивах начала 90-х почтовой рассылки WWW-Talk, я неожиданно обнаружил ссылки на DTD (это специальный формат в котором описывается как браузер должен парсить теги) стандарта HTML+. Я знал, что это название одного из ранних стандартов HTML и подумал, что там могло оказаться упоминание CHANGED с, чем чёрт не шутит, каким-то подробностями.

Ни одна ссылка не работала, зато по имени htmlplus.dtd нашлось несколько уцелевших спецификаций, где, как я и надеялся, упоминался искомый тег с небольшим описанием:

<!-- change bars defined by a matched pair of CHANGED elements:

        <changed id=z34> changed text <changed idref=z34>

 This tag can't act as a container, since changes don't respect
 the nesting implied by paragraphs, headers, lists etc.
-->

<!ELEMENT CHANGED - O EMPTY>

<!ATTLIST CHANGED -- one of id and idref is always required --
    id      ID      #IMPLIED -- signals start of changes --
    idref   IDREF   #IMPLIED -- signals end of changes -->

Собственно, из этого кусочка всё стало ясно. Тег задуман таким образом, чтобы как бы «выпадать» из обычной логики вложенности тегов — так как выделение текста может пересекать границы других тегов.

Вместо открывающего и закрывающих тегов тут применяется тег с атрибутом ID для обозначения начала участка и тег с тем же значением в атрибуте IDREF для определения места, где участок заканчивается.

Этот тег не дожил до нашего времени, потому что его было предложено заменить на два других — ADDED и REMOVED, которые позже превратились в более привычные нам INS и DEL.

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

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

Скриншот веб-страницы «Test CHANGED Tag - HTML+ Change Bars» с примерами выделения изменённых фрагментов текста жёлтым фоном и заголовками разделов.

3 комментария

«Виола»: предок VRML ★

Недавно завершил в «Виоле» большую работу: реализацию раннего черновика стандарта VRML. VRML когда-то широко использовался в вебе для создания трёхмерных игр, да и просто для того, чтобы рассматривать с разных сторон какие-либо объекты в объёме.

Началось всё с того, что я заметил в браузере едва начатую реализацию тегов, помеченную комментариями как /* vr exp */. В исходном коде нашлась целая группа таких тегов. Назначение некоторых из них, например OVAL или LINE, было вполне очевидным, тогда как то, что в точности могли бы делать некоторые другие теги, например ACTION или BUTTON, было не вполне ясно.

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

Шло время, и вдруг, копаясь в каталогах старого сайта, посвящённого «Виоле», я неожиданно нашёл черновик письма, в котором автор «Виолы» описывал своё видение того, как должен выглядеть VRML.

Скриншот веб-страницы «Proto-VRML Graphics Demo» с примерами: жёлтые фигуры на розовом фоне, треугольник и пятиугольник, простая красная домик с солнцем.
Готовая реализация графики, которая сейчас работает в браузере

Там раскрывалось значение всех ключевых тегов из вышеуказанной группы, их атрибутов, а также интерактивная часть — причём в двух вариантах: декларативном (через теги) и скриптовом (через язык «Виолы»).

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

Вот, например, как на этом языке рисуется синий квадрат с тёмно-синим бордюром на светло-сером фоне в координатах x=10, y=20, повёрнутый на 45°:

<GRAPHICS WIDTH=400 HEIGHT=120>
<BGCOLOR NAME="lightgray"></BGCOLOR>
<RECT ID="rect1">
<POS X=10 Y=20></POS>
<SIZE X=70 Y=70></SIZE>
<FGCOLOR NAME="blue"></FGCOLOR>
<BDCOLOR NAME="navy"></BDCOLOR>
<ROT Z=45>
</RECT>

Особенно меня почему-то зацепил атрибут SC о роли которого я бы никогда самостоятельно не догадался. Автор описывал его так:

The SC attribute says that whenever the attributes in this object changes, relay the change to a server that broadcasts the change to all other browsers looking at this object… Have to think about this more…

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

В итоге эту часть я сначала пытался сделать через маковский сервис «Бонжур», но позже переделал на мультикастовый UDP — так работало гораздо быстрее и надёжнее.

Скриншот веб-страницы «ACTION Script Demo - Clickable Shapes» с цветными геометрическими фигурами и описанием их интерактивных свойств (вращение, масштабирование, смена цвета).
Активные объекты, содержащие атрибут SC рассылают свои изменения по локальной сети

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

Пришлось делать специальный таймер, который будит приложение, если ему адресованы интерактивные UDP-пакеты.

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

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

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

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

Скриншот окна браузера ViolaWWW с заголовком «Geometric Art - ViolaWWW Graphics Demo» и геометрической композицией из разноцветных фигур на сером фоне.
Пример с узорами, нарисованный при помощи реализованных графических примитивов

2 комментария

Как мы видим старый веб

Я часто пишу, что считаю проект «Веб-архива» самым важным в интернете. Пользуюсь им постоянно и большинство ссылок за четверть века ведения своего сайта во временем стали вести туда. Особенно интересно на «Веб-архиве» смотреть на то, как начинался веб, времени прошло немного, но изменилось всё самым радикальным образом.

И вот интересная штука, я ведь начал заниматься вебом в 90-е, свой первый в жизни сайт сделал в начале 1998-го, отлично помню, что браузеры того времени имели много нестандартных тегов, которые сейчас не отображаются — тот же мегапопулярный в те времена «Нетскейп» имел теги LAYER и ILAYER, вместо современных DIV и IFRAME.

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

Мало беды, если не видно какого-то оформления, типа мигания (BLINK) или бегущей строки (MARQUEE), неприятно, если поедет оформление из-за отсутствия поддержки старого тега многоколоночности (MULTICOL) или тех же тегов-контейнеров (LAYER), но по-настоящему плохо, если не видна часть важного контента.

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

Часть картинок, которые там использованы в оформлении, в ничем сейчас не поддерживаемом формате XPM, а другая часть вставлена при помощи тега FIG, поддержки которого сейчас тоже нигде нет.

На скриншоте — слайд про виртуальную среду, про который я писал вчера вечером, со всеми картинками, которые должны там отображаться. Тут, конечно, можно и без них обойтись, в этом смысле более показательный пример, как я уже упоминал выше, — сайт «Виолы».

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

Оставить комментарий

HTML 3.0 и VR

Пока искал в интернете информацию по тегу FIGURE, набрёл на какую-то недоделанную, но очень интересную презентацию «A Quick Review of HTML 3.0». Судя по версии HTML, это должно быть в районе 1995 года.

Под подзаголовком «Figures with local event processing» скрывается видение того как в будущем будет выглядеть веб в виртуальной реальности. Причём автор считал, что это будет ближайшее будущее:

К концу этого десятилетия дальнейший рост соотношения цена/производительность позволит доступным настольным системам запускать высокореалистичные модели виртуальной реальности. […] сейчас самое подходящее время для разработки механизмов, позволяющих людям делиться VR-моделями в глобальном масштабе.

Я и не знал, что первый коммерческий наголовный дисплей был выпущен в 1994-м году, думал в 90-е такое только в фантастических фильмах встречалось:

Джойстики и устройства типа «SpaceBall» улучшают управление, но не могут конкурировать с полной «погружённостью», которую обеспечивают наголовные дисплеи. Системы премиум-класса используют магнитное отслеживание положения головы и конечностей пользователя, а также устройства вроде трёхмерных мышей и киберперчаток, ещё больше усиливающие иллюзию.

Автор соврешенно справедливо полагал, что звук тоже важен, не только изображение:

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

Можно подумать что тут написано про какие-то приспособления, которые позволяют почувствовать виртуальную гравитацию:

Виртуальная среда может накладывать те же ограничения, что и реальный мир, например силу тяжести или ограничение движения ходьбой, подъёмом/спуском по лестнице, поднятием и опусканием предметов. Либо, наоборот, пользователи могут «обзавестись суперсилами» и с лёгкостью летать по воздуху или даже проходить сквозь стены!

…но на деле речь просто реализацию физики на экране:

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

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

Возможно, мы сможем опереться на опыт конвертации документов и SGML и задавать VR-среды на логическом уровне, предоставив браузерам заполнять детали в соответствии с возможностями каждой платформы.

Базовая идея заключается в том, чтобы составлять VR-среды из ограниченного набора логических элементов, например стул, дверь, пол. Размеры некоторых элементов можно брать по умолчанию. Для других, например размеров комнаты, требуются списки точек — скажем, для описания многоугольника, задающего план пола. Дополнительные параметры задают цвет и текстуру поверхностей. Рамка картины, висящей на стене, может быть описана с помощью растрового изображения.

Я немного сократил статью, она чуть больше, но, к сожалению, не дописана, кончается в неожиданном месте:

Хранение таких подробностей в отдельных файлах даёт несколько преимуществ:

10 комментариев

Атрибут LANGUAGE

Просматривал тут публичные репозитории некого соискателя одной из наших вакансий, обратил внимание, что у него там, помимо всего прочего, лежат решённые задания со «Стэпика». Заглянул из любопытства, никаких особенных выводов не сделал, но удивился, что в тегах одного задания у него script содержит атрибут language. Это что же, его до сих пор учат писать?

Мне стало любопытно — он вообще сейчас какое-то значение имеет? Браузеры на него ориентируются? Когда-то он вполне имел смысл — у «Эксплорера», например, там мог стоять VBScript или, например, JScript.Encode — зашифрованный текст программы на ДжейСкрипте, это такой диалект ДжаваСкрипта от Микрософта.

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

А что же считается верным значением для ДжаваСкрипта? В угадайку играть не хотелось, скачал исходники «Хромиума», посмотрел что там используется. Как оказалось, подставить можно следующие значения (регистр значения не имеет):

  • javascript или x-javascript — это понятно, единственный сюрприз, что можно поставить «экс» перед словом;
  • ecmascript или x-ecmascript — тоже понятно, ДжаваСкрипт — расширение этого языка;
  • jscript — диалект языка в «Эксплорере», считается, что другие браузеры сейчас его тоже «знают», хотя на деле есть нюансы, но всем уже всё равно;
  • от javascript1.0 до javascript1.5 — когда-то указанием версии можно было разделять скрипты по уровню поддержки языка в браузере;
  • livescript — старое название языка «ДжаваСкрипта», я ещё помню времена, когда это значение использовалось, хотя и редко.

Сейчас, конечно, это скорее археология, чем какое-то нужное знание.

Углеродно-кремниевая сегрегация

Когда-то в Америке висели таблички, запрещающие неграм входить в бары «для белых», а сейчас иллюстраторы используют специальные метки, предписывающие искусственному интеллекту не заходить на их сайты:

<meta name="robots" content="noai, noimageai">

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

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

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

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

Объяснение того как это работает на самом деле сложнее и, такое ощущение, что большинству недоступно. Простому же объяснению на понятных метафорах ещё предстоит родиться, но не факт, что оно не устареет ко времени своего рождения.

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

2 комментария

AVIF в «Эгее»!

Как говорится, если нельзя, но очень хочется, то можно. «Эгея», как я писал не понимает формат AVIF, но мне его удалось всё-таки в неё вставить, причём даже малой кровью.

Изображение ниже я взял из своей заметки про Красную площадь в коронавирусный период. В оригинале оно весит 1,1 мегабайт в формате JPEG, в этой заметке используется сконвертированное изображение размером в 179 килобайт. Почувствуйте разницу.

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

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

Красно-белая церковь с разноцветными луковичными куполами и золотыми крестами на фоне голубого неба с белыми облаками, вид снизу через каменную стену и металлический забор.
Моя фотография храма Василия Блаженного (1555—1561 гг.) из заметки «Красная площадь без людей»

Итак, «Эгея» не поддерживает AVIF, но я её в «Эгею» вставил. Как же мне это удалось?

Дело в том, что «Эгея» поддерживает формат SVG, а SVG поддерживает внутри себя растровую графику, в том числе вставленную через протокол «data». Протокол «data» — это картинка, закодированная в текстовую строку, вида data:mime/type;encoding,encoded_data.

Вообще, SVG поддерживает и внешние ресурсы (то есть в теории способен подгрузить картинку снаружи), но при вставке через тег img (как в «Эгее») в нём это запрещено по соображениям безопасности.

Поэтому мысль такая — переводим графику в AVIF, кодируем в base64 («data» так умеет, а иначе бинарные данные не вставить), из-за кодирования они увеличатся на 33%, но даже при этом овчинка выделки стоит, а потом получившееся запихиваем в SVG.

Для конвертации я написал вот такой небольшой bash-скрипт (для работы требуется пакет ImageMagick):

#!/bin/bash

if [ -z "$1" ]; then
    echo "Usage: $0 <picturename>"
    exit 1
fi

NAME="$1"
NEWNAME="${NAME%.*}.svg"
WH=( $(identify -ping -format '%w %h' "$NAME") )

if [[ "$NAME" == *@2x* ]]; then
    WH=( $(( ${WH[0]} / 2 )) $(( ${WH[1]} / 2 )) )
fi

cat<<XML > "$NEWNAME"
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 ${WH[*]}" width="${WH[0]}" height="${WH[1]}">
<image width="${WH[0]}" height="${WH[1]}"
href="data:image/avif;base64,$(convert "$NAME" "avif:-" | base64)"/>
</svg>
XML

echo "$NAME" to "$NEWNAME" was converted.

Последовательность теперь у меня такая — готовлю графику в более привычном формате, запускаю скрипт, получаю файл SVG, вставляю его драг-н-дропом в редактор «Эгеи». Не знаю насколько у меня такой способ приживётся, буду пока считать эту запись тестовой.

Дополнение: уже сообщают, что в 15-й и ниже Айос ничего не видно.

13 комментариев

Какие ещё графические форматы поддерживает ваш браузер?

Переложил на хостинг «Гитхаба» свой проект семилетней давности — «Какие графические форматы поддерживает ваш браузер?». Я его иногда обновляю и мне было бы проще это делать через репозиторий.

Из всего, что я там проверяю, сразу не сработала только проверка на AVIF — это новейший формат, у меня на компьютере его поддерживает пока только «Файерфокс», ему важно указание типа содержимого, а «Гитхаб» передаёт неправильное значение.

Скриншоты браузеров: список поддерживаемых форматов изображений (JPEG, PNG, SVG, WEBP, BMP, GIF, TIFF, ICO, AVIF и др.).
Браузеры (сверху вниз): «Сафари» 13, «Файерфокс» 78 и «Опера» 69

Я подумал, что наверняка есть какой-то способ указать правильный тип в файле конфигурации сайта, но нет, так это не работает, такой настройки в нём нет. В принципе, известно откуда «Гитхаб» берёт свою базу типов содержимого — из проекта mime-db. Но этот путь тоже не сработал — я добавил туда тип для AVIF больше недели назад, но ничего не изменилось. Видимо синхронизация изменений происходит нечасто.

Пришлось идти другим путём — вместо того, чтобы загружать файл картинки, внедрил его внутрь при помощи протокола data:, это позволило обойти проблему. Можете протестировать на своём браузере.

Ссылка на проект: https://bolknote.github.io/detect-browser-graphics-formats/
Ссылка не репозиторий проекта: https://github.com/bolknote/detect-browser-graphics-formats

7 комментариев

«Магический шар» ★

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

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

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

Использование его в те годы могло бы выглядеть как-то так:

<A HREF=/cgi-bin/action.pl><IMG SRC=/i/pict.gif WIDTH=200 HEIGHT=100 ISMAP></A>

Чтобы вы прочувствовали дух времени, специально пишу большими буквами (так было принято) и без кавычек (экономили и на этом тоже).

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

На тёмном фоне фиолетовый круг с надписью «My sources say no» (Мои источники говорят «нет»).
«Магический шар» из прекрасного фильма «Трасса 60»; с отрисовкой деталей я не стал заморачиваться

Я уже несколько лет как не верстаю, но почему-то этот атрибут ISMAP мне всё никак не давал покоя. Как будто брошенная на последней странице книга — всё тянуло найти ему какое-то применение.

И вот два года назад меня осенило использовать его в вёрстке «магического шара» из фильма «Трасса 60». Если не смотрели, там у главного героя был шар, который давал ответы на заданные вопросы, если его потрясти.

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

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

HTML с таким подходом становится довольно жирным — у меня получился 1,2 мегабайта, но по нынешним временам это не объём.

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

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

11 комментариев

Тег HYPE (Netscape HYPE tag sound)

Скриншот интерфейса SheepShaver с запущенной Netscape Navigator 2.01, окном Unix с папками и файлами, панелью Launcher с приложениями и рабочим столом Mac OS.
Скриншот MacOS 9 с открытым окном браузера

Пятнадцать лет назад, ковыряя исходники браузера «Нетскейп», я наткнулся, в частности, на тег HYPE — в интернете того времени писали, что он воспроизводит какой-то звук, но только в старых версиях браузера и не под «Виндоуз». «Мака» у меня тогда не было, как и доступа к «Линуксу» с графическим интерфейсом, поэтому безуспешно поискав по интернету подробности, я исследование забросил.

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

Но времена же изменились! Теперь у нас есть виртуализация, образы виртуальных машин и быстрый интернет! Где-то полчаса ушло на поиск и скачивание второй версии «Нетскейпа», готовой виртуалки с девятой «МакОСью», установку всего найденного, разбирательство как всё запускается. Но при вводе заветного тега меня ждало препятствие, к счастью, устранимое — виртуалка заявила, что у меня нехватает какой-то Sound Machine и, вместо проигрывания звука, предложила скачать звуковой файл.

Файл оказался в формате .snd, который нормально открылся и проигрался уже в современном «Маке». Его содержимое — фраза «What is global hypermedia?» (из документа NCSA Mosaic Demo 1993 года, как объясняется на одной из страниц в интернете).

Я сконвертировал его в обычный МП3 и, если ваш браузер достаточно современный, можете послушать как звучит тот самый секретный тег:

Кстати, жаль, что я не догадался проиграть его на оригинальном «Макинтоше» в музее Эпл, в Москве. Если представиться случай, обязательно попробую!

2 комментария

IE9 и таблицы

IE9 и таблица (18.31КиБ)

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

Наткнулись на странную проблему в этой версии Эксплорера — некоторые таблицы выглядят как на снимке выше — ячейки в строках иногда выпирают вправо безо всякой видимой причины.

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

Я выбрал второй путь. Пусть лучше шаблон выглядит читаемо, а костыль для девятого Эксплорера всегда можно будет убрать лёгким движением руки. Выглядит он вот так, кстати (используется jQuery, само собой):

$("table tr").contents().filter(function() {
    return this.nodeType == 3;
}).remove();

16 комментариев

Свёртка в вебе

Я как-то пропустил момент, когда фильтры SVG стало можно накладывать на обычный тег IMG, а не на изображения внутри SVG же. Любопытные эффекты можно делать, например, можно наложить свёртку для выделения краёв и это будет работать:

<style>
    .edge {
        -webkit-filter: url(#edge);
        filter: url(#edge);
    }
</style>

<svg style="width: 0; height: 0">
<filter id="edge">
<feConvolveMatrix kernelMatrix="-1 -1 -1 -1  9  -1 -1  -1  -1" />
</filter>
</svg>

<image src="sample.jpg" class="edge">

Магические числа в матрице — специальное ядро.

Впрочем, и раньше можно было внедрить в ХТМЛ СВГ-картинку и наложить сверху фильтр, ничего особенного, но мороки чуть больше. При желании этот фильтр можно унести прямо в ЦСС при помощи data URI, но тогда он продублируется два раза — для префиксной и безпрефиксной формы (несмотря на уверения «Кэнайюз», «Хром» и «Сафари» отказались работать без префикса).

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

var arr = document.getElementById('edge').childNodes;

for (var i = 0; i < arr.length; i++) {
    if (arr[i].kernelMatrix) {
        arr[i].kernelMatrix.baseVal.getItem(4).value = newvalue;
        break;
    }
}

Осталось только соединить этот код с «крутилкой» и готов онлайн-фильтр «выделение краёв».

10 комментариев

Ленивая загрузка в ИЕ11

В IE11 интересную штуку сделали — ленивую загрузку. Можно пометить картинку (включая внедрённые тегом SVG), теги для воспроизведения видео и аудио, скрипты и многое другое специальным атрибутом lazyload, который означает «начать загружать, когда загрузится всё важное».

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

<img src="avatar-3132.png" width="200" height="200" lazyload="1">

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

9 комментариев

SVG с fallback на не векторные форматы

Нравятся мне такие вещи. Алексей Тен из Яндекса придумал очень изящный способ внедрения СВГ в код с возвратом к растровому формату, если браузер не поддерживает СВГ:

<svg width="96" height="96">
    <image xlink:href="svg.svg" src="svg.png" width="96" height="96"/>
</svg>

Принцип виден из кода, я думаю, но я всё же расшифрую. Если браузеры поддерживают внедрение СВГ в ХТМЛ, то почти весь выше приведённый код будет для них значимым: кроме атрибута «src», его у тега СВГешного image не бывает и он будет отброшен. Соответственно, картинка загрузится из файла svg.svg.

Если же браузер СВГ в таком виде не понимает, то будет отброшен тег svg и атрибут «xlink:href», а тег image будет преобразован в img — это старая особенность браузеров, которой я тщетно пытался придумать применение. В этом случае будет загружен svg.png.

Я уже на сайте в одном месте использую этот трюк.

4 комментария

SVG-спрайты

Вчера ночью, эксперементируя с различными способами внедрения картинок в ХТМЛ, я понял, что уже все браузеры (кроме «Оперы Мини»), понимают СВГ прямо в коде страницы. А это значит, можно отказаться от CSS-спрайтов в пользу того, что можно назвать «SVG-спрайтами»:

SVG-спрайты (162.51КиБ)

Принцип, в общем-то, тот же: большая картинка, из которой показывается фрагмент, только фрагмент задаётся не через ЦСС, а прямо в ХТМЛе.

Думаю, всем понятен код: в теге svg задаются размеры кусочка спрайта, в image обязательно нужно указать полные размеры картинки (для Ретины можно указать их в два раза меньше, если спрайт подготовлен к этому типу экранов), при помощи параметров x и y позиционируем в каком именно месте спрайта расположена наша картинка.

В комментариях спрашивают зачём это всё надо, чем это лучшее спрайтов в ЦСС.

Ну, во-первых, это семантичнее. Понимаю, для многих это не аргумент, поэтому у меня есть два других. Итак, во-вторых, браузеры стараются фоновые картинки (в спрайтах ЦСС используются именно они) грузить в последнюю очередь, это логично — как правило, они менее важны. В-третьих, фоновые картинки часто не отображаются при печати (у некоторых браузеров в настройках печати есть возможность вывести на печать с фоном, но по-умолчанию это отключено).

14 комментариев

Обнаружение Ретины

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

Наиболее животрепещущий вопрос — подготовка изображений для Ретины.

Напомню, что Ретина — технология Эпл, ставшая уже нарицательной, заключающаяся в примерении экранов высокого разрешения (например, на моём ноуте это 2560×1600) с отображением на нём обычной графики так, как бы это выглядело на экранах вдвое низкого разрешения. При этом шрифт смотрится просто великолепно, как на бумаге, а вот с картинками беда.

В вебе бо́льшая часть графики выглядит не очень (хотя масса сайтов уже подготовилась). Для того, чтобы стало хорошо, все изображения надо готовить вдвое большего размера, при этом указывая для них в коде вдвое меньший размер, тогда проявляется вся мощь Ретины — будет видно самые мелкие детали изображения и пропадёт размытие.

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

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

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

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

А пока, у меня такое решение. Используем старые-добрые «печеньки» и mod_rewrite.

На стороне клиента первой строкой каждой нашей страницы ставим проверку по «ретиновые» экраны с установкой «печенья»:

<script>if(window.devicePixelRatio>=2)document.cookie='retina=1'</script>

Этот скрипт выполнится первым и все дальнейшие запросы на сервер будут содержать строку «retina=1», если мы имеем дело с Ретиной. Все изображения, для которых у нас есть две копии — обычная и «ретиновая» (в два раза большая) называем одинаково, но с постфиксом «@2x» для большей, при этом в коде указываем данные разрешения для более мелкой картинки:

<img src="/images/owl@2x.jpg" width="400" height="560" alt="Совушка">

Сейчас, конечно, Апач теряет популярность, но я воспользуюсь синтаксисом mod_rewrite, желающие могут переделать в Энжин Икс или какой-то другой синтакис:

RewriteEngine On

RewriteCond %{HTTP_COOKIE} !retina=1
RewriteRule (.*)@2x\.(gif|jpe?g|png|webp) $1.$2 [L,NC]

Этот код означает, что если не установлено «печенье» «retina=1», то нужно убрать постфикс «@2x» из имени картинки.

В итоге, если у нас Ретина, «печенька» ставится в самом начале, все дальнейшие запросы к серверу идут с ней и картинки грузятся как указано в коде — например, если указано «owl@2x.jpg», то эта картинка и грузится.

Если у нас обычный экран, «печеньки» нет, запросы к серверу идут без неё и из картинок вырезается постфикс «@2x», т. е. картинка «cat.jpg» грузится по своему имени, а вместо «owl@2x.jpg» загрузится «owl.jpg».

Voilà!

66 комментариев

Инвертирование в CSS без фильтров

Немногие знают, что инвертирование части ХТМЛ-страницы можно и без новомодных ЦСС-фильтров. Правда, количество браузеров, где это можно сделать, всё уменьшается. В данный момент такая возможность всё ещё остаётся в Эксплорере (версия 8 и выше) и «Опере» (7.0 и выше). Так как «Опера» скоро перейдёт на Вебкит, где этой возможности нет и не было, останется один Эксплорер. Файэрфокс лишился поддержки этой функции в версии 3.0 и возвращать её пока не планирует.

Я говорю о поддержке значения invert свойства outline-color. Это значение говорит браузеру, что нужно инвертировать всё, что лежит ниже. Пользоваться не очень-то удобно, но сойдёт при необходимости, результат может выглядеть, например, так:

Инвертирование при помощи outline-color (33.90КиБ)

Наложить сверху элемент с аутлайном можно любым способом, я использовал position: absolute:

<style>
.invert {
    outline: invert solid 75px;
    position: absolute;

    width: 50px; height: 0;
    margin: 75px 0 0 75px;
}
.content {
    width: 200px;
    height: 150px;
    position: absolute;
    left: 200px;
    top: 200px;
    text-align: center;
}
</style>

<div class="content">
    <div class="invert"></div>
    <img src="/i/foto.jpg">
</div>

Для того, чтобы высчитать размеры накрывающего блока, нужно немного арифметики. У меня большую размерность имеет ширина (накрываемый блок размером 200×150), поэтому будем плясать от неё. Высота накрывающего блока должна быть в этом случае равна нулю, ширина — разности между шириной и высотой накрываемого блока, outline-width, margin-top и margin-left — половине высоты накрываемого блока.

Думаю, ни для кого не составит труда самостоятельно провести вычисления для обратного случая — когда высота больше ширины.

1 комментарий

Какие графические форматы поддерживает ваш браузер?

Скриншоты браузеров Opera, Chrome, IE, Safari, Firefox и IE на Nokia Lumia 920: список поддерживаемых форматов изображений (JPEG, PNG, GIF и др.) с пометкой «Done».
Форматы, поддерживаемые браузерами

Я тут скрипт накидал, который проверяет какие графические форматы поддерживает ваш браузер. Проверяется JPEG, GIF, PNG, XMB, WebP, BMP, SVG, JPEG XR, TIFF, PDF, EMF, WMF, WBMP (Wireless BMP), JPEG-2000, ICO, APNG и MNG.

Тестируется поддержка в теге IMG.

Любопытно, что «Сафари» до сих пор поддерживает JPEG-2000, а «Опера» — WBMP (как единственный десктопный браузер, поддерживающий WAP, где WBMP и применяется).

Дополнение: оказывается, SVG в моем тесте был не до конца верный (я его просто сконвертировал из гифа 1×1 какой-то программой), так что скриншоты теста в браузерах верны не до конца, «Хром» и «Сафари» (т. е. браузеры на вебките) не поняли мой SVG.

19 комментариев

Тег шаблона (NOEMBED?)

Где-то видел спецификацию на тег TEMPLATE, для шаблонов в HTML. Его смысл в том, что содержимое не добавляется в DOM (дерево) документа, не засоряет дерево, что может быть очень полезно, если шаблонов много и веб-приложение активно работает с деревом. Работа с DOM одна из ресурсоёмких операций, ни к чему нагружать браузер ещё и шаблонами.

Традиционно в HTML4 для этого используют тег SCRIPT у указанием какого-нибудь несуществующего языка:

<script type="text/x-template" id="template-ok">
<div><div class="button">OK</div></div>
</script>

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

Был раньше такой нестандартный тег COMMENT, но его сейчас никто не понимает, даже Эксплорер прекратил его поддержку, в данном случае он бы пригодился.

Мне вчера ночью подумалось, что можно использовать и более лаконичные теги — NOFRAMES или NOSCRIPT. Первый показывает своё содержимое, если браузер не поддерживает фреймы, второй, если выключены скрипты. Если выключенные скрипты ещё встречаются у сетевых параноиков, то браузера без поддержки фреймов сейчас и не встретишь, а если таковые и есть, то веб-приложения им не понянуть.

Особенность же тегов в том, что они в нормальных условиях являются аналогом комментария, то есть не добавляют своё содержимое в DOM, поэтому они вполне пригоды на роль шаблонного тега.

<noframes id="template-ok">
<div><div class="button">OK</div></div>
</noframes>

<script>
alert(document.getElementById('template-ok').innerText); // содержимое шаблона
</script>

Не сказать, что это как-то по-особенному семантично или чем-то лучше тега SCRIPT (разве что короче), просто ещё один вариант.

Когда я уже дописал эту заметку, мне пришла в голову мысль, что а) тег NOEMBED был бы, наверное, более семантичем, чем NOFRAMES, он имеет отношение к встраиванию контента, а я совсем про него забыл, б) тег EMBED был бы, наверное, ещё более семантичен, но, к сожалению, он слишком тяжёл для браузера, надо испытывать, но я предполагаю, что даже если контент явно незнакомый, браузер всё равно попытается угадать что это. Но надо провести испытания, конечно же.

Так что, я бы остановился бы на NOEMBED. Во-первых, это тег ещё короче, во-вторых, обладает хоть какой-то семантикой, которую можно трактовать как не вставлять (no-embed) содержимое в дерево документа.

5 комментариев

← 1 2 3 →