Языки, чуть было не ставшие CSS

Перевод статьи The Languages Which Almost Became CSS с сайта eager.io, опубликовано на css-live.ru с разрешения автора — Зака Блума

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

Марк Андрессен, 1994

Когда в 1991-м Тим Бернерс-Ли объявил о создании HTML, оформлять страницы было просто нечем. То, как отображались те или иные HTML-теги, определялось браузером, часто под существенным влиянием пользовательских настроек. Хотя казалось заманчивым придумать стандартный способ, чтобы странички сами «предлагали», в каком виде их лучше отобразить.

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

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

Первое предложение

В начале 1993-го браузер Mosaic не дошел еще даже до версии 1.0, и тогдашние браузеры имели дело исключительно с HTML. Способов указать для HTML стиль не было вообще, то есть как браузер решит отобразить, скажем, <h1>, так оно и выходило.

В июне того года Роберт Райш в рассылке www-talk предложил создать «простой для разбора формат для передачи стилевой информации вместе с веб-документами», назвав его RRP.

@BODY fo(fa=he,si=18)

Если вы так и не поняли, что делает этот код — не страшно. В эпоху до gzip-сжатия, при типичных скоростях соединения порядка 14.4k, ужимать до предела содержимое этого формата имело смысл. Это конкретное правило задает шрифту (fa) значение «helvetica» (he), а размеру (si) шрифта — значение 18 пунктов.

Занятно, что в этом предложении совсем не упоминались единицы измерения, а все числа интерпретировались по контексту (например, размеры шрифтов всегда были в пунктах). Это можно объяснить тем, что RRP создавался скорее как «набор ПОДСКАЗОК или РЕКОМЕНДАЦИЙ для движка отрисовки», а не как конкретные указания. А это считалось необходимым, ведь одни и те же стили должны были работать как в типичных консольных браузерах (вроде Lynx), так и в стремительно набиравших популярность графических.

lynxЧто интересно, в RRP уже входил метод для задания колоночной раскладки, без чего CSS поневоле обходился вплоть до 2011-го. Например, три колонки по «80 единиц» каждая, выглядели бы примерно так:

@P co(nu=3,wi=80)

Разобрать трудновато, но, пожалуй, не особо хуже того же white-space: nowrap.

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

Марк Андрессен (создатель Mosaic, которому предстояло стать самым популярным браузером) знал о предложении RRP, но в Mosaic его так и не реализовали. Вместо этого Mosaic быстро перешел (как ни прискорбно) на определение стилей HTML-тегами, вводя теги типа <FONT> и <CENTER>.

Viola и войны первобраузеров

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

И тут я могу всласть наобъясняться: «Ну, сначала вам доведется изучить один язык, чтобы написать сам документ, а потом — еще другой язык, чтоб наконец заставить документ выглядеть как надо». О да, люди ну просто в восторге от такой перспективы.

Марк Андрессен, 1994

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

violaПэй-Юан придумал язык стилей с поддержкой вложенных структур наподобие тех, что мы сегодня привыкли видеть в CSS:

(BODY fontSize=normal
      BGColor=white
      FGColor=black
  (H1   fontSize=largest
        BGColor=red
        FGColor=white)
)

Здесь мы применяем выбранные цвета к body и по-особому оформляем заголовки H1, оказавшиеся в body. PWP работает со вложенностью не повторами селекторов, а системой скобок, напоминающей систему отступов из языков типа Stylus и SASS, что многие современные разработчики предпочитают чистому CSS. Так что синтаксис PWP уже как минимум в одном мог бы превзойти CSS, которому оказалось суждено стать всеобщим языком, лингва франка для веба.

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

<LINK REL="STYLE" HREF="URL_to_a_stylesheet">

Увы, ViolaWWW была написана лишь под оконный менеджер X Windowing, а тот был популярен лишь на Unix-системах. Едва Mosaic портировали на Windows, как он быстро отнял у Виолы последние шансы..

Таблицы стилей довебских времен

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

Рой Смит, 1993

Язык для описания стиля документа был нужен еще задолго до Интернета.

Как вы, возможно, в курсе, известный нам HTML изначально был основан на доинтернетном языке под названием SGML. В 1987-м в министерстве обороны США решили выяснить, можно ли с помощью SGML упростить хранение и передачу колоссальных объемов документации, с которыми им приходилось иметь дело. Как во всяком уважающем себя правительственном проекте, первым делом они стали придумывать название. Сперва команда называлась «Computer-Aided Logistics Support» (поддержка логистики с компьютерной помощью), затем «Computer-aided Acquisition and Logistics Support» (поддержка учета новых поступлений и логистики с помощью компьютеров) и наконец «Continuous Acquisition and Life-cycle Support initiative» (проект по непрерывному учету новых поступлений и поддержке жизненного цикла). Но первые буквы в любом случае были CALS.

Команда CALS создала язык для оформления SGML, названный FOSI, что тоже наверняка расшифровывается каким-то сочетанием четырех слов. Они опубликовали спецификацию языка, столь же всеобъемлющую, сколь и непонятную. А еще в ней была одна из моих любимейших бредовых инфографик за всю историю веба.

Одно из непреложных правил Интернета гласит: всегда добиваешься большего, если в ходе работы удастся доказать, что кто-то неправ. В 1993-м, всего через четыре дня после предложения Пэй-Юана, Стивен Хини предложил, что лучше не «изобретать велосипед», а применить для оформления веба вариант FOSI.

Сами FOSI-документы писались на SGML, что было даже в чем-то вполне логичным, учитывая, что веб-разработчики уже знали другой вариант SGML — HTML. Вот пример такого документа:

<outspec>
  <docdesc>
    <charlist>
      <font size="12pt" bckcol="white" fontcol="black">
    </charlist>
  </docdesc>
  <e-i-c gi="h1"><font size="24pt" bckcol="red", fontcol="white"></e-i-c>
  <e-i-c gi="h2"><font size="20pt" bckcol="red", fgcol="white"></e-i-c>
  <e-i-c gi="a"><font fgcol="red"></e-i-c>
  <e-i-c gi="cmd kbd screen listing example"><font style="monoser"></e-i-c>
</outspec>

Если вы слегка недоумеваете, что такое docdesc или charlist, то участники переписки в www-talk чувствовали то же самое. Про контекст всего этого им сообщили лишь то, что e-i-c означает «элемент в контексте». Однако именно FOSI впервые ввел единицу em, которая сегодня стала любимым средством для оформления у тех, кто знает CSS получше вашего.

Противостояние языков, что разворачивалось в ту пору, по сути тянется с самого начала программирования. Это была борьба функционального синтаксиса в духе LISP с синтаксисом более декларативных языков. Сам Пэй-Юан описывал свой синтаксис как «LISP-образный», но оставалось ждать совсем немного, пока на сцену выйдет настоящий вариант LISP-а.

Тьюринг-полный язык стилей

При всей своей сложности, FOSI рассматривался всего лишь как временное средство для оформления документов. На будущее планировалось создать язык на основе Scheme, функционального языка программирования, который позволял бы самые мощные трансформации документа, что только можно себе представить. Назывался этот язык DSSSL. Как сказал один из его разработчиков Джон Босак:

Неправильно ставить DSSSL в один ряд со скриптовыми языками. Да, DSSSL тьюринг-полный; да, это язык программирования. Но скриптовые языки (по крайней мере, в моем понимании термина) — процедурные; DSSSL — однозначно нет. DSSSL полностью функциональный, без каких-либо побочных эффектов. В самой таблице стилей DSSSL никогда ничего не происходит. Таблица стилей — одна гигантская функция, и ее значение — абстрактное, аппаратно-независимое, непроцедурное описание форматированного документа, которое передается нисходящим процессам отрисовки в виде указания (объявления, если угодно) экранных областей.

В своем простейшем виде, DSSSL — вполне понятный язык оформления:

(element H1
  (make paragraph
    font-size: 14pt
    font-weight: 'bold'))

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

(define (create-heading heading-font-size)
  (make paragraph
    font-size: heading-font-size
    font-weight: 'bold))

(element h1 (create-heading 24pt))
(element h2 (create-heading 18pt))

И пользоваться математическими конструкциями при оформлении, например, чтобы раскрасить таблицу «зеброй»:

(element TR
  (if (= (modulo (child-number) 2)
        0)
    ...   ;четная строка
    ...)) ;нечетная строка

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

(element H1
  (make paragraph
    font-size: (+ 4pt (inherited-font-size))))

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

Та же команда в дальнейшем разрабатывала XSL, язык для преобразования документов, не менее запутанный, но явно оказавшийся более популярным.

Почему CSS выиграл в гонке

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

Родительский селектор означал бы, что придется обновлять стили по мере загрузки страницы. Языки вроде DSSSL тут полностью «пролетали», потому что могли производить операции с самим документом, а к моменту, когда пора начинать что-то отображать, он еще не был полностью доступен.

Первым, кто обратил на это внимание и предложил работоспособный язык, был Берт Бос, в марте 1995-го. Кстати, в его предложении была еще и первая редакция смайлика :-)

Синтаксис самого языка в какой-то мере «объектно-ориентирован»:

*LI.prebreak: 0.5
*LI.postbreak: 0.5
*OL.LI.label: 1
*OL*OL.LI.label: A

Точка . служила для обозначения непосредственных потомков, а звездочка * — для указания предков.

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

*A.anchor: !HREF

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

В одном из функциональных предложений, которое представил джентльмен с инициалами «C.M.» и фамилией Спирберг-МакКуин в 1994 г., это же поведение описывалось по-функциональному:

(style a
  (block #f)     ; форматировать как строчный фрагмент текста
  (color blue)   ; синим цветом, если экран у вас цветной
  (click (follow (attval 'href')))  ; а по клику — переходить по адресу

Его язык также ввел ключевое слово content как способ управлять содержимым HTML-элемента из таблицы стилей, позже это понятие ввели в CSS2.1

Как могло бы быть

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

PSL96, по тогдашней традиции именования, был «Языком указания представления» в редакции 1996 года. В своей основе, PSL выглядит как CSS:

H1 {
  fontSize: 20;
}

Но дальше всё интереснее и интереснее. Например, можно было выражать положение элемента, основываясь не только на указанных для него размерах (Width), но и на фактических (Actual Width) размерах, с которыми браузер его отобразил:

LI {
  VertPos: Top = LeftSib . Actual Bottom;
}

Вы наверняка заметили, что «сосед слева» нашего элемента может служить как точка отсчета.

А еще можно добавлять в стили логические выражения. Например, чтобы оформить только те элементы <a>, у которых есть href:

A {
  if (getAttribute(self, "href") != "") then
    fgColor = "blue";
    underlineNumber = 1;
  endif
}

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

LI {
  if (ChildNum(Self) == round(NumChildren(Parent) / 2 + 1)) then
    VertPos: Top = Parent.Top;
    HorizPos: Left = LeftSib.Left + Self.Width;
  else
    VertPos: Top = LeftSib.Actual Bottom;
    HorizPos: Left = LeftSib.Left;
  endif
}

Если бы подобная функциональность поддерживалась, мечта об отделении оформления от содержания вполне могла бы стать явью. К сожалению, на свою беду этот язык был слегка чересчур расширяемым, а это значило, что его реализации запросто могли заметно различаться от браузера к браузеру. Кроме того, он публиковался в виде серии научных статей, а не в рассылке www-talk, где велась основная работа по функциональным языкам. И его так и не встроили ни в один массовый браузер.

Призрак CSS-овского прошлого

Язык, от которого — как минимум названием — напрямую произошел CSS, назывался CHSS (каскадные таблицы HTML-стилей), а предложил его в 1994 г. Хокон Виум Ли.

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

h1.font.size = 24pt 100%
h2.font.size = 20pt 40%

Обратите внимание на проценты в конце правил. Они указывали, сколько «власти» над этим значением получала текущая таблица стилей. Например, если предыдущая таблица стилей определяла размер шрифта заголовка h2 как 30pt, с 60-процентным влиянием, а в новой таблице заголовки h2 описывались как 20px 40%, оба значения объединялись в одно с учетом их «процентов влияния», и итоговое значение выходило где-то около 26pt.

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

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

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

       Пользователь          Автор
Шрифт    o-----x--------------o 64%
Цвет     o-x------------------o 90%
Отступ   o-------------x------o 37%
Громкость o---------x----------o 50%

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

AGE > 3d ? background.color = pale_yellow : background.color = white
DISPLAY_HEIGHT > 30cm ? http://NYT.com/style : http://LeMonde.fr/style

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

RELEVANCE > 80 ? h1.font.size *= 1.5

Вы знаете, что было дальше

Microsoft всецело привержен открытым стандартам, особенно в Интернете.

Джон Людман, 1994

Хокон Ли продолжал упрощать своё предложение, и в декабре 1996 г. они вдвоем с Бертом Босом опубликовали первую версию спецификации CSS. В дальнейшем ему предстояло написать свою докторскую диссертацию о создании CSS — документ, без которого я вряд ли смог бы написать эту статью.

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

CSS сам по себе служит напоминанием о том, как много в новых технологиях зависит от случая. Например, поддержку контекстных селекторов (body ol li) добавили лишь потому, что у Netscape уже был способ убрать рамки у картинок-ссылок, и казалось необходимым реализовать всё, что популярный браузер уже умел. А эта функциональность сама по себе заметно задержала внедрение CSS, поскольку большинство браузеров той поры при разборе HTML не сохраняли «стек» родительских тегов. И это значило, что ради полной поддержки CSS пришлось переделывать парсеры.

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

Последний главный соперник

Если Netscape 4 игнорировал CSS-правила для элемента <body> и добавлял каждому структурному элементу на странице пустое пространство «от балды», а IE4 понимал код для <body>, но путался в отступах, то какой же CSS можно было писать без опаски? Кто-то из разработчиков вообще отказался писать его. Другие писали одну таблицу стилей, чтобы поправить огрехи IE4, и другую, чтобы прикрыть ляпы Netscape 4.

Джефри Зельдман

В небезызвестном Internet Explorer 3 с самого начала была (довольно жутковатая) поддержка CSS. Чтобы не отставать, в Netscape 4 решили тоже добавить поддержку этого языка. Но чем рисковать с уже третьим (учитывая HTML и JavaScript) по счету языком, эту поддержку предпочли реализовать, преобразуя CSS в JavaScript и исполняя его. Мало того, этот промежуточный язык «JavaScript Style Sheet» решили открыть для веб-разработчиков.

Синтаксис — обычный JavaScript, с добавлением нескольких специфических API для оформления:

tags.H1.color = "blue";
tags.p.fontSize = "14pt";
with (tags.H3) {
  color = "green";
}

classes.punk.all.color = "#00FF00"
ids.z098y.letterSpacing = "0.3em"

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

evaluate_style() {
  if (color == "red"){
    fontStyle = "italic";
  } else {
    fontWeight = "bold";
  }
}

tag.UL.apply = evaluate_style();

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

JavaScript и сам был еще совсем новинкой, но Internet Explorer уже успел «расковырять» его и добавить поддержку в IE3 (под видом «JScript»). Хуже было то, что сообщество уже успело сплотиться вокруг CSS, и многие стандартисты тогда считали Netscape источником угрозы. Когда Netscape наконец передал JSSS комиссии по стандартизации, все пропустили его мимо ушей. Три года спустя Netscape 6 убрал поддержку JSSS, и этот язык тихо (по большей части) загнулся.

Как могло бы быть

Благодаря некоторым живительным пинкам от W3C, Internet Explorer 5.5 в 2000 г. вышел с почти полной поддержкой CSS1. Конечно, как все мы знаем, браузерные реализации CSS отчаянно глючили, и работать с ними было тяжеловато как минимум еще десятилетие. К счастью, сейчас положение дел разительно улучшилось, и мечты разработчиков, что однажды можно будет написать код и он будет работать (почти) одинаково во всех браузерах, начинают сбываться.

Лично мне вся эта история помогла осознать, до чего же произвольны и ситуативны были многие из решений, определявших судьбу наших нынешних инструментов. Если наш CSS был задуман таким лишь в угоду ограничениям 1996 года, то, пожалуй, 20 лет спустя мы вправе действовать немножко иначе.

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

P.S. Это тоже может быть интересно:

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

  1. Мата

    Статья очень интересная! Историю css скоро можно будет изучать как отдельную дисциплину. Это придает величественность css-у :)

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

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