<i is="морж">
Перевод статьи <i is="the walrus">
с сайта bkardell.com для CSS-live.ru, автор — Брайан Карделл
В последнее время я с завидной регулярностью наблюдаю в соцсетях, как люди выражают недовольство кастомными элементами. Поскольку я сам — ярый их поклонник, и к тому же участвовал во многих обсуждениях при их создании и развитии, мне тоже очень хотелось бы, чтобы они были лучше. Но я часто замечаю, что обсуждать это с недовольными бывает трудно. Вот я и подумал, что стоит сесть и написать об этом. И о моржах.
Пришла пора…
И молвил Морж: «Пришла пора
Подумать о делах:
О башмаках и сургуче,
Капусте, королях,
И почему, как суп в котле,
Кипит вода в морях»
За последние несколько лет я несколько раз замечал, как возникают нападки и критика в адрес кастомных элементов. Всё начинается (по-моему) с того, как кто-то указал, что в текущей спецификации описана возможность расширять «родные» элементы с помощью атрибута is=""
. Далее следует аргумент, что расширение позарез необходимо ради доступности. Но по какой-то причине его так и не реализовали. Так начинается немало обсуждений, часто сводящихся к поиску виноватых в том, что веб тормозится, а кастомные элементы оказались неполноценными. На эту основную предпосылку нанизываются другие аргументы, чем еще это было бы хорошо: если будет X, то будет и Y, если будет Y, то будет и Z. И кажется, что в совокупности все эти простые замечания и аргументы подводят к простому и обоснованному «общему решению», которое было бы просто замечательным… Если бы браузеры просто перестали жевать сопли и реализовали эту штуку из спецификации. Многих это бесит. И я могу это понять.
Но я хочу уделить немного времени и показать, что не всё не так просто…
Магия доступности
Эту чудесную майку с моржинорогом можно, пожалуй, даже нужно, купить на Амазоне
Давайте начнем вот с чего: с расхожего представления, что если расширить встроенный элемент, он будет «доступным автоматически» просто в силу наследования. Я думаю, что важно объяснить, почему оно почти полностью неверно. Увы, в действительности волшебный моржинорог не подарит каждому элементику, который использует is="…"
, доступности чудом даже на Всемирный день моржа (24 ноября).
И вот почему: на текущий момент, все блага доступности, которых мы так жаждем, неразрывно связаны с нативной DOM. К сожалению, в подавляющем большинстве ситуаций, где нужно «улучшение» нативного элемента, на самом деле речь идет об улучшении самой DOM, и это вызывает существенное несоответствие. В реальности (не в представлении о ней), как только мы создает новый корень теневого DOM-дерева, скрываем существующий элемент или делаем чуть ли не что угодно полезное для пользовательского опыта, все эти блага доступности по большому счету попросту исчезают.
Заметьте: я сказал почти полностью неверно, потому что есть на самом деле несколько задач, в которых никакая новая DOM не задействована.Но с точки зрения доступности у многих из них есть и одинаково элементарные решения, которые можно применить уже сейчас, а также другие предложения из числа еще обсуждаемых, которые должны лучше подойти для решения этих задач.
Так что все соображения, будто is="…"
сделает все компоненты доступнее, увы, попросту сбивают с толку. У расширения нет никакой магической способности, позволяющей привязывать «любую ерунду, что я только что придумал» к «известной штуковине со всеми правильными характеристиками доступности». Вам всё равно придется изрядно потрудиться.
Больше того, это не такое уж спорное утверждение в мире стандартов. Снимаю шляпу перед Гуглом за старание решить множество проблем. На краткий миг у некоторых людей появились большие надежды в связи с is="…"
. Другие видели слишком много проблем и слишком мало плюсов. Тот миг прошел и, если смотреть реалистично, похоже, никто больше не верит, будто в is="…"
сокрыто много ответов. Встречные предложения с тех пор бродят в умах и, кажется, на сегодня находят больше поддержки (я упомяну некоторые из них позже).
Прогрессивное улучшение
Морж extends Животное
Хотя обычно говорят о доступности, я думаю, что на самом деле именно прогрессивное улучшение (Progressive Enhancement, далее сокращенно PE), которое вроде бы дает нам is="…"
, и есть та ключевая фича, из-за которой люди так цепляются за эту идею. Я полностью это понимаю: на словах всё так здорово. Увы, я считаю, что это тоже сбивает с толку.
Вот тонкий момент, о котором стоит подумать: действительно ли is="…"
— это PE в традиционном смысле? Что ж, нет. И не может им быть, поскольку возможности расширения никогда прежде не было. Традиционно PE никогда не представляло собой отношения «является» (is-a).
Представьте типичный пример, на котором объясняют PE: в дизайне есть кнопка с надписью «Нажмите, чтобы распечатать», клик по которой должен вызывать window.print()
. PE требует брать за основу что-то, что будет работать для каждого. В нашем случае это может быть абзац с текстом «Распечатайте эту страницу на память». Это по силам любому браузеру. Пользователи часто могут сами разобраться, как распечатать страницу на своем компьютере. Затем, если браузер отвечает необходимым критериям (он понимает, что такое кнопка, поддерживает JavaScript и метод window.print()
в нем определен), то этот абзац улучшается. Звучит хорошо.
Но теперь присмотритесь повнимательнее: становится ли он абзацем, содержащим работающую кнопку, или же он вместо этого сам превращается в кнопку печати. Разве это одно и то же?
человек is=”морж”
Ни превращение чего-либо во что-то другое, ни изменение строения чего-либо — не то же самое, что расширение. Традиционно «природа» или «суть» экземпляра этого элемента никогда не менялась. Никогда, ни в какой ситуации, один и тот же элемент не был абзацем и кнопкой одновременно. Вот почему нельзя написать, например, <p is="button">
— это бессмыслица. Но само то, что этот атрибут позволит разработчику выразить такое желание (т.е. кто-то захочет и сможет так написать), означает, что придется ввести много добавочной сложности и кучу всего написать с нуля, чтобы учесть все новые случаи.
И всё же еще раз повторим, абзац и кнопка — вещи, совершенно разные с точки зрения иерархии наследования, и это важно, вот почему…
Метафорические моржи
Если вы подумали, что пример «абзаца, который кнопка» выше выглядит «совсем не похожим на то, о чем вы просите» и это лишь мой надуманный пример, чтобы убедить вас в чем-то неважном — это не так. Я сказал бы, что в данный момент это именно то, о чем мы часто просим, даже не сознавая того. Почему? Что ж, опять же, это потому что на самом деле мы хотим того, в чем замешана новая DOM. В терминах, доступных нам на сегодня, это вовсе не специализированная версия чего-либо или что-то в этом духе. Очень часто то, что мы описываем — другой, более сложный тип отношения. Отношение «является» (is-a) совершенно точно говорит о расширении, а расширение относится к описанию иерархии сущностей (таксономии), как, скажем, у Линнея.
Понимать основные идеи линнеевской классификации очевидно необходимо, если вы работаете, скажем, морским биологом или палеонтологом. Но многие люди не осознают, что в отличие от многих других ненужных знаний, которыми вас пичкали в школе — вроде всякой там алгебры — понимать это бывает крайне полезно в повседневной взрослой жизни. Например, чтобы помочь моей хорошей подруге Саре Дрэснер выиграть спор в баре о том, знают ли люди, что это…
Ладно, помогите нам, «ботаникам», поспорить на выпивку. Знаете ли вы, что такое линнеевская система классификации? (Не гуглить!)
Или — что, наверное, ближе к делу — если вы моделируете программный продукт, как мы с вами сейчас. Так что поговорим об этом на минутку.
Заметка на полях: в западной науке весьма существенное внимание уделялось попыткам классифицировать всё на свете в подобные хрупкие и произвольные таксономии. Об этой склонности и ее истории много писал Дэвид Вайнбергер, и его доклад «Всё входит в категорию “разное”» по-настоящему увлекателен и не перегружен техническими подробностями, так что стоит найти время и посмотреть его.
Барбара Лисков
В 1987 г. Барбара Лисков представила доклад «Абстракция и иерархия данных», где говорится о том, как мы моделируем сущности, и о нашем стремлении организовать их в иерархии, умеющие расширять и наследовать. Далее Лисков иллюстрирует, как это порой приводит к множеству проблем. Что важнее, она затем разъясняет, как можно избежать этих проблем, и основное понятие, которое она описывает, известно многим как «принцип подстановки Лисков» (Liskov substitution principle, сокращенно «LSP»), или даже просто как «замещаемость». В 2008 г. она получила за эту работу премию Тьюринга.
В некотором смысле, она говорит вот о чем: метафора способствует тому, что вместо модели получается черт-те что. Наши мозги на деле в совершенстве справляются с дичайшими связями любого типа, аналогиями и смыслами, скорее метафорическими, нежели буквальными — в общем, можно сказать, они созданы находить связи и закономерности, даже тогда, когда их в помине нет.
Автор фото — Джейни
Языки программирования, с другой стороны, склонны воспринимать всё весьма буквально. Из-за этого наш мозг может сбить нас с толку и из-за этого наша модель чего-либо окажется неадекватной. Расширение полезно и нужно, не поймите меня превратно. Но если использовать его неудачно, а не как действительно полезную абстракцию, то мы обнаружим, что система стала бороться против нас.
Еще раз, вот что здесь происходит: сейчас всё то «хорошее», что нам нужно, крепко привязано к DOM, и поэтому многие случаи, когда на наш взгляд что-то «является» чем-то другим (т.е. между ними отношение is-a), к сожалению, это скорее метафорически так, а не буквально. В доступных нам на сегодня терминах, такого отношения между ними попросту нет — а значит, мы запутались в неудачной модели.
Возможность расширять input «как это делал HTML» — один из чаще всего приводимых жизненных примеров для расширения, что я слышал. Но даже в самой платформе, где технически расширение возможно, сегодня оно тут ни при чем. Есть только input. Стоит отметить, что очень многое в устройстве <input>
-а разработчики реализаций сейчас считают существенной проблемой. Почему? Ну, полагаю, легче всего это осознать, послушав этот доклад Моники Динкулеску. Вкратце же, он был порожден как раз тем несоответствием модели, что мы тут обсуждаем. Вместо того, чтобы помогать, модель начинает с нами бороться. Мы замечаем дыры и нестыковки в том, как смоделировали нашу метафору, и что на самом деле всё не совсем так.
Это несоответствие всё чаще признается реальной проблемой, которую надо решать. В понятиях расширяемого веба, в нынешнюю DOM пока еще вплетено слишком много магии, требующей объяснения. Чтобы действительно решить множество типов задач, которые люди пытаются описывать, нам нужно выделить конкретные функции и научиться объяснять в этих терминах и существующую платформу, и новинки. Сейчас в самом разгаре несколько обсуждений, цель которых — помочь нам сделать именно это, и ни одно из них не сводится к наследованию либо к is="…"
в его теперешнем виде. О них я напишу отдельно, но перед нами остается очень важная проблема: что нам делать до тех пор?
Что ж, занятно, но при всём при этом «является» (is-a) — не единственный тип отношения, определяемый нами при моделировании задач. В часто цитируемой книге «Паттерны проектирования» так называемой «банды четырех» есть простое наблюдение «композиция превыше наследования», основанное на работе Лисков. А именно: объединение функций с помощью отношения «включает в себя» (has-a) часто всё равно оказывается лучшим решением в долгосрочной перспективе.
Наш опыт включает в себя решение…
Что самое интересное, нам не нужно абсолютно ничего нового, чтобы и следовать тем же самым паттернам прогрессивного улучшения, что до сих пор, и получить почти все ожидаемые плюсы от is="…"
, причем без какого-либо нового усложнения самой платформы. Как? С помощью композиции вместо наследования. А конкретнее:
<!-- вместо этого --> <input type="radio" is="x-radio"> <!-- пишем это --> <x-radio> <input type="radio"> </x-radio>
Благодарю за это моего приятеля Брюса Лоусона, можете и посмотреть видео этого реального выступления с участием веселого моржа-саксофониста
Да, это не идеально. Да, соответствие не полное. Бывают случаи, когда вам приходится прогрессивно улучшить родительский элемент, чтобы повлиять на дочерний, например. Но если вы найдете время и рассмотрите их тщательно, то обнаружите, что фактически они функционально эквивалентны в каждом полезном аспекте: сериализация форм, валидация и т.д. Оба декларативны, в паттерны обоих встроена примерно та же устойчивость к ошибкам. И самое важное: вам, как создателю компонента, использующего такой паттерн, придется изменять и проксировать ради доступности ровно столько же всего в каждой из моделей, это зависит лишь от той DOM, которую вы меняете. В силу этого «крайнего сходства» стоит отметить, что если какой-то из этих аспектов вас раздражает, то is="…"
(в его сегодняшнем виде) скорее всего вызовет у вас немало тех же самых раздражений. Признаю, что это может показаться слегка неинтуитивным, наверное, я расскажу о типах возражений на мои наблюдения в другой заметке.
Итак, подведем итог: наш опыт включает в себя (отношение has-a!) решение через композицию. Весьма неплохое. Вполне мощное и удачное. Не идеальное. Не исчерпывающее. Но с ним нам доступна куча всего полезного и это Действительно Хорошая Штука™. То, что мы во многом перестали гнаться за is="…"
— не результат бойкота его кем-то из браузеров и не чистая потеря. Идеям нужно распространяться и просачиваться сквозь множество умов. Если оригинальные идеи оказываются неприспособленными, они должны уступать место другим, чтобы идеи могли смешиваться, мутировать, и в конечном счете смогли появиться лучшие идеи. Именно этот процесс я вижу здесь. В ближайших следующих частях я расскажу о том, что за идеи сейчас вовсю прорабатываются ему на смену, чтобы помочь нам лучше решить эти проблемы.
Гу-гу, гу-джуб… (прим. перев.: это строчка из песни Джона Леннона «Я — морж»)
Особые благодарности моим друзьям, Алексу Расселу и Питеру Рашфорту, за вычитку/комментирование ранних черновиков этой заметки и помощь в том, чтобы она стала короче и менее путанной.
P.S. Это тоже может быть интересно:
Читал в надежде увидеть описание этих самых новых идей, но статья закончилась. :o
Насколько я сам понял, в основном тут Брайан ратует за внедрение нативной функциональности в кастомные контролы с помощью композиции, вместо того, чтобы как-то хитро наследоваться от нее (а по факту — и от нее, и от чего-то еще, получая на выходе противоестественные гибриды вроде того комиксного персонажа:). Но да, будет интересно прочитать обещанное продолжение!
Как то и без кастомных тегов отлично верстается.