Привет, представляю твоему вниманию перевод статьи Моники Динкулеску '<input> I ? you, but you're bringing me down'. Художественный перевод с английского не является моей основной специализацией, поэтому в тексте возможны неточности. Правки призываю отправлять личным сообщением, а если есть что сказать, велкам в комментарии. Отдельное спасибо @Kt за редакторские правки. Приятного чтения.


Некоторые люди делают мебель. Некоторые люди вяжут. Некоторые люди имеют хобби, которые никак не пересекаются с HTML спецификациям из 90-х. Но я не из таких. И, вот история о том, как <input> стал той хренью, которой он является, и почему его надо сжечь


Ранние годы



1995 был клевым годом. Друзья, Скорая Помощь, Зена по телеку. TLC занимали верхушки чартов с хитом "Waterfalls". С браузерами было нормуль, потому что HTML было все очень нормуль. У нас были Mosaic, Netscape и IE1, а при утверждении спеков HTML 2, наконец, выкроили время для стандартизации форм. Девяносто пятый был годом рождения <input>, и теперь, когда он достаточно взрослый, чтобы покупать в магазине алкоголь, нам нужно поговорить.

Изначально <input> пришел к нам в восьми видах: text, password, checkbox, radio, image, hidden, submit и reset, а так же с отдельном последующим RFC, file.

Подожди, ты сказал image? Да, давай я расскажу о нем.

<input type='image' src='cat.png'> выглядит как обычное изображение, но на самом деле это изображение-кнопка, которая при нажатии также передает x и y координаты того места, в котором на нее нажали. При этом, если не указано изображение для атрибута src, «изображение-кнопка» станет кнопкой с надписью «Submit». А если дело будет происходить Firefox, то текст кнопки изменится на «Submit Query» и кнопка будет выглядеть как обычный текст. А если открыть пример в IE, в этом случае ты не увидишь ничего.



А вот вопрос, достойный вашего местного клуба «Что? Где? Когда?», если тип элемента = 'file', то текст который будет отображаться на месте этого элемента, когда не выбран ни один из файлов: «No file chosen», «no file selected», «No file selected», и просто пустой текстовый блок в Chrome, Safari, Firefox и IE соответственно.

Ладно, хорошо.


А вот, тирада в честь <textarea>



Я всегда думала, что input и textarea были придуманы в разное время, и это объясняет, почему они так безумно отличаются. Это в целом так, input был частью браузера Mosaic по крайней мере с 1993, и он был, по сути, исправленной имплементацией ISINDEX. Тем не менее, официально, они оба были детьми HTML2, который решил, что <input> это самозакрывающийся тег в котором значение тега помещаяется в атрибут value, в то время как для тега <textarea> нужен закрывающий тег, а его значение хранится в его содержимом, даже если они оба тега используются только для хранения простого текста, который кто-то ввел:

<input value="batman">
<textarea rows="1">batman</textarea>


Небольшой апдейт: некто подсказывает, что <textarea> должен поддерживать ввод многострочного текста, а символы переноса строки не допускаются внутри значений атрибутов, вот почему мы должны использовать содержимое тега. А это имеет смысл!


1995-2011, средние года



В 1999 году, в HTML4 добавили только один новый тип тега = 'button'. Что мне в этом особенно нравится, что без каких-либо дополнительных пользовательских стилей, <input type='button'> и <input type='button' value='Submit'> помещенные в одну и ту же строку, не совпадают по вертикали в Chrome/Safari/Edge.




Все становится еще хуже



Позже, в 2011 году, спецификация HTML5 добавила тысячи новых типов для <input>. И на сегодняшний день, большинство из них не реализовано. Вот краткий перечень неработающих фич: type=color работает только в Firefox/Chrome, date/time работает только в Chrome/EDGE/iOS, и все, что работает в Chrome работает в Opera. Вот сравнение всех доступных типов input'ов на сегодня, так что ты можешь сравнить и поплакать наедине.

Давай поговорим о некоторых интересных фактах.

<input type='search'> имеет странные случайно выбранные отступы между текстом и границей, а так же популярные в середине 2000-х закругленные углы, внешний вид которых отличается от браузера к браузеру и от которых почти невозможно избавиться.



А если твоему браузеру повезло поддерживать тип = 'date', не волнуйся о стилизации элемента выбора даты – у нас есть 8 чудесных ::webkit псевдо-селекторов, которые помогут настроить стиль текстового блока, но ни одного для стилизации выпадающего блока выбора даты! В любом случае, знай, CSS вреден для твоего здоровья.


И в тот момент, когда ты подумал, что хуже уже не будет: JavaScript



Видите ли, я могу оправдать причуды CSS. Я работала над браузером Chrome в течение 2 лет, сейчас я работаю с командой Blink, я понимаю, что мы все пишем разные рендеры и что для них свойственны свои собственные баги CSS. Тем не менее, <input> API даже нельзя назвать странным – он буквально как банка пауков, и в тот момент, когда ты открываешь банку, уже слишком поздно. Ты весь в пауках. Даже твоя кошка стала пауком. Лучше сжечь тут всё.

Начиная с 1995 года, элементы формы с типами radio и checkbox имеет дополнительный атрибут 'checked' который позволяет определить состояние элемента. Поскольку HTMLInputElement это HTMLInputElement и это HTMLInputElement, выходит, что во всех остальных типах элемента <input> этот атрибут также присутствует, но его просто игнорируют. Да, даже если это и не имеет смысла, это восхитительно:

var textInput = document.querySelector('input[type="text"]');
console.log(textInput.checked);  // prints false.
textInput.checked = true;
console.log(textInput.checked);  // prints true.
// did not open the hellmouth.

Круто. Круто-круто-круто!

<input> содержит текст, текст может быть выделен, а в прототипе HTMLInputElement определенны два свойства: selectionStart и selectionEnd – два числа которые определяют диапазон выбора. Таким образом, ты можешь сделать:

document.querySelector('input').selectionStart += 2;


И продвинуться на 2 символа вперед от начала выделения текста. Мега-заурядное исключение из этого факта то, что selectionStart – атрибут который доступен только для input'ов c типами text, url и password. А еще он доступен для вызова (это даже не настраивается) бросая исключение так же для всех остальных типов элемента :

Uncaught DOMException: Failed to read the 'selectionStart'
property from 'HTMLInputElement': The input elements type ('number')
does not support selection.

Даже если я могу вручную выделить этот текст:



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




К сожалению, это еще не все. Я уверена, что это еще не все. Дело в том, у разработчиков браузеров был 21 год, чтобы починить отображение input'ов, но им даже не удалось договориться о том, как писать «you haven't picked a file».

Теперь представь будущее, в котором веб-компоненты поддерживаются нативно, кто угодно может написать свой <better-input> – реальный инкапсулированный DOM элемент, а не просто лапшу из DIV'ов. Представь, как ты используешь этот <better-input>, что его реализация не отличается от браузера к браузеру, он выглядит одинаково везде, и что, вероятно, он знает, как испечь тебе вишневый торт. Только представь.

Комментарии (51)


  1. aml
    27.10.2015 11:54
    +6

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


    1. AreD
      27.10.2015 14:04
      +1

      Да, но какие то легаси проблемы, например, решаются. Те же флекс блоки позволяют вертикальное позиционирование делать. А тут казалось бы простая вещь – стандартизация и возможность широкой настройки стилей элементов форм. Веб состоит из дизайна/верстки и пользовательского взаимодействия с сайтом. Вот когда верстаешь, делаешь красоту и душа прям радуется, вот тебе веб инспектор, вот тебе и инструменты для оптимизации CSS, вот тебе удобные медиа-запросы. Но как только ты доходишь до пользовательского взаимодействия – боль.


  1. Hint
    27.10.2015 12:36
    +2

    Как-то установил на проекте тип email для всех полей, предназначенных для ввода почты. Сначала радовался (автоматическое добавление нужных символов на клавиатурах мобильных устройств), а потом вернул тип text. Почему? Потому что если случайно добавить лишний пробел (перед адресом или после), то браузеры считают значение неверным и не дают отправить форму. А ведь это происходит очень часто и вводит пользователей в заблуждение (особенно при copy-paste). В итоге, бесполезный тип без костылей на JavaScript, хотя при отправке достаточно было бы сделать trim. Возникает еще проблема с доступом к value из скрипта, но могли бы что-нибудь придумать.


    1. AreD
      27.10.2015 14:18
      +1

      Возникает еще проблема с доступом к value из скрипта, но могли бы что-нибудь придумать.

      А о какой проблеме идет речь?


      1. Hint
        27.10.2015 14:32

        Я имею в виду, что если делать trim при отправке формы, то как быть, например, в случае ajax (когда скрипт сам берет значение из поля)? Как быть с псевдоклассами валидации? Т. е. визуально значение одно (с пробелом), а фактически для скриптов другое?


        1. jrip
          27.10.2015 15:32
          +1

          Ну в идеале в такое поле не должен просто никак попасть пробел и не надо тогда никаких неожиданных trim`ов.


      1. kykint
        27.10.2015 14:37
        +1

        Кстати с value действительно был косяк, однажды столкнулся. Если в number поле было вбить невалидное значение, то value говорит, что там пусто


      1. Hint
        27.10.2015 14:44

        На самом деле проблема не только с email. Например, тип url. Значение www.ya.ru по сути неверное, но браузер может преобразовать в www.ya.ru и отправлять именно это значение (и предоставлять его скриптам).


        1. WaveCut
          27.10.2015 16:16

          В помощь призывается pattern!


          1. Hint
            27.10.2015 17:00

            И он воспринимается мобильными устройствами? Они добавляют на клавиатуру все нужные спец. символы?


            1. WaveCut
              27.10.2015 17:04

              Когда я последний раз тестировал — судя по поведению типизированные поля вроде url, email, tel просто используют некий pattern «по-умолчанию». Если его переписать — валидация будет плностью своя. При этом поле не теряло своих новых качеств на клавиатуре.
              Но конечно, все может меняться от платформы к платформе. У меня яблоко.


              1. SelenIT2
                28.10.2015 12:51

                Для url и email паттерны описаны в самом стандарте (для второго — явно в виде регулярки, для первого — в виде ссылки на отдельный стандарт WHATWG).


              1. demimurych
                28.10.2015 13:22

                Так и есть.


  1. Methos
    27.10.2015 14:43
    -5

    Вы просто не умеете это готовить


  1. volk0ff
    27.10.2015 14:44
    +1

    Интересно мнение экспертов: если по аналогии с ВК, вместо инпутов использовать повсеместно дивы с атрибутом contenteditable="true" , ничего страшного не произойдет? (там то со стилями все менее плачевно)


    1. trikadin
      27.10.2015 15:23
      +1

      Придётся писать апи самому, хех. И насколько я помню (давно таким не занимался) — там далеко не нулевое количество кроссбраузерных несовместимостей.


      1. volk0ff
        27.10.2015 15:29

        Стоит ли так все усложнять? (Я, например, просто брал яваскриптом содержимое этих div-ов и отправлял на сервер аяксом)


        1. trikadin
          27.10.2015 15:32

          Ну это же в первую очередь от задачи зависит О_о

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

          Нет, конечно, наверняка есть фреймворки, которые такое делают… Но в таком случае ты просто променяешь одно АПИ на другое.


          1. volk0ff
            27.10.2015 15:45

            Не исключаю, что у меня имеются пробелы в знаниях JS, но какая разница, куда, например, выводить сообщение об ошибке, которое пришло от сервака — под соответствующий инпут, или под такой же див? :)


            1. jrip
              27.10.2015 15:55
              +1

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


            1. trikadin
              27.10.2015 16:07
              +5

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

              • Типы форм. Придётся делать проверку на ввод только чисел для чисельного ввода, отображение календарика для ввода даты, проверку ввода корректной даты и времени для соотв. типов, цветовой ввод для color, ползунок для rangе… Да и что я вам перечисляю, вот тут всё есть. Это уж не говоря про всякие радиобаттоны и флажки.
              • Перехватывать нажатия таба для нормального перехода по элементам формы, и вообще разные сочетания клавиш для accesskey.
              • Модификаторы поведения — disabled, readonly, checked, autofocus...
              • Валидация. Это поля pattern, min, max, minlength, maxlength, step, встроенная регулярка для урлов, емейлов, телефонов...
              • Разные другие плюшки — placeholder, list.
              • Связь с формой отправки на сервер.
              • Событийная система.

              Наконец, есть вещи, которые вы никак не сможете эмулировать — автозаполнение, переключение видов клавиатуры на телефонах в зависимости от типа инпута, выбор файла (это можно кое-где, но тоже очень геморройно). Смекаете? Чтобы реально замениить инпуты чем-то другим, надо проделать огромную работу.


              1. Zibx
                27.10.2015 17:47

                А в случае инпутов в вебприложении приходится всё равно это делать, но и попутно рубить дефолтное поведение не совпадающее между браузерами.


                1. trikadin
                  27.10.2015 18:11

                  В случае contenteditable некроссбраузерного поведения гораздо больше, а фичей — меньше.


    1. jrip
      27.10.2015 15:35
      +4

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


    1. dshster
      27.10.2015 16:40
      +3

      Придётся очень дико обрабатывать событие copy/paste потому что в contenteditable вставляется текст в формате text/html со всеми вытекающими. Но это еще не всё — так же придётся обрабатывать события перетаскивания в это поле и (внимание!) событие document.execCommand из консоли, через которое в contenteditable можно вставить всё что угодно. А это уже довольно объёмная портянка кода.


    1. Ohar
      27.10.2015 18:32
      +3

      ничего страшного не произойдет?

      Нет, ничего. Просто отдельный котёл в аду.


  1. Meklon
    27.10.2015 14:49

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


    1. AreD
      27.10.2015 16:01
      +2

      Ответил в личку


      1. Meklon
        27.10.2015 16:02

        Спасибо большое. Только, видимо, не мне в личку)


        1. AreD
          27.10.2015 16:04
          +3

          Вам, вам, проверьте)


          1. Meklon
            27.10.2015 16:09

            Протупил мессенджер местный) Теперь оба сообщения пришло. Спасибо.


          1. Newbilius
            28.10.2015 08:09

            А можно и мне в личку? :-)


            1. AreD
              28.10.2015 09:45
              +2

              Можно и вам) Отправил


      1. Sild
        28.10.2015 16:45
        +2

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


        1. AreD
          28.10.2015 16:51

          О сколько нам открытий чудных гототовят хаброредактор.


  1. Ohar
    27.10.2015 18:27

    Госпожа Динкулеску написала поток нытья вместо статьи.
    Из перечисленных проблем реальная только одна — ограничение для selectionStart.

    если тип элемента = 'file', то текст который будет отображаться на месте этого элемента, когда не выбран ни один из файлов: «No file chosen», «no file selected», «No file selected», и просто пустой текстовый блок в Chrome, Safari, Firefox и IE соответственно.
    он выглядит одинаково везде

    Почему это вообще кого-то беспокоит? Это нативные элементы браузера и пользователь этого конкретного браузера узнаёт их и понимает что от него в этом месте хотят.


    1. AreD
      27.10.2015 21:14
      +3

      да, статья написана в достаточно ироничном ключе, но скажите, вас устраивает, например, отсутсвие возможности стилизировать выпадающий список тега select с помощью css?


      1. Ohar
        27.10.2015 21:25
        +2

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


        1. Drag13
          27.10.2015 21:55

          Это вы шутите так?
          Когда код уходит на продакшн он тоже теоретически может не работать. Но никого это не останавливает почему-то…


          1. Ohar
            27.10.2015 22:03
            +4

            Нет, я не шучу.
            Просто я ставлю интересы пользователя выше интересов дизайнера.


            1. Drag13
              27.10.2015 22:04
              -4

              Вы ставите свое умение ниже интересов пользователя.


        1. AreD
          28.10.2015 00:52
          +7

          На современном мобильном селект выглядит как часть интерфеса операционной системы, все ок, я не вижу проблемы.
          Проблема с моей стороны с десктопными браузерами. Да, я знаю доводы за нативное отображение системных элементов и отчасти поддерживаю их, но вот нифигаж оно не работает, посмотрите на «нативный» селект фаерфокса под OS X. И как написал Drag13 ниже, мы за то, что бы мы могли выбирать, сделать веб приложение как нативное под ОС, или сделать дизайнерский сайт с теми формами которые мне надо. Да посмотрите же, никого это ограничение не останавливает и появляются монстры написанные на jQuery которые эмулируют селект, но с настраиваемым внешним видом, но вот не задача, то он криво под старыми бразуерами отобразиться, то он с помощью клавиатуры не выделяется, и прочие баги. Печальное это, 21 год уже как печально. Что касаемо вашего мнения, я его понимаю и принимаю, но спорить с вами не буду.


    1. SelenIT2
      28.10.2015 12:59
      +2

      Загадочность и нелогичность дефолтных стилей контролов форм — тоже проблема. Другой вопрос, стандарта или браузеров (в первую очередь всякие ::-moz-focus-innerы и их друзья, без которых нормально не сбросить отступов кнопке). Скорее всего, и того и другого).


      1. Ohar
        28.10.2015 13:04

        Совершенно с вами согласен.


  1. jorgen
    27.10.2015 21:29
    +1

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


  1. bolk
    28.10.2015 07:43
    +1

    У четвёртого «Нетскейка» была тогда масса странных типов тега INPUT. Например, TYPE=OBJECT, TYPE=READONLY или TYPE=JOT.


  1. fetis26
    28.10.2015 09:59
    +3

    Хаха, детка. Это все ерунда. Вот попробуй застайлить дропдаун, вот где БОЛЬ. Причем дизайнеры этой проблемы не замечают и год из года рисуют всякое безумие в виде дропдаунов


    1. AreD
      28.10.2015 12:43

      Ты про <select>?


      1. SelenIT2
        28.10.2015 12:55
        +1

        Да про любой из них. <datalist> тоже тот еще проказник)


      1. fetis26
        28.10.2015 13:42

        да, конечно.


  1. Eefrit
    28.10.2015 16:58
    -3

    Что касается <better-input>… что тут скажешь.

    Старо как мир
    Собрались как-то инженеры и говорят — что-то у нас слишком много стандартов для проводов, передающих данные от устройства к устройству. Тут тебе и USB, и COM, и LPT, и FireWire, и ThunderBolt, и так далее. Аж 14 штук насчитали. А давайте, говорят, придумаем единый стандарт, который будет удовлетворять всем условиям, будет максимально универсальным, самым гибким и широкораспространённым? «Хорошая идея,» — поддержали все. И теперь у нас 15 стандартов.