Произвольный вид поля file в html-форме, одинаковый во всех браузерах

    Не смотря на развитие, внедрение новых стандартов и плюшек в браузерах, у нет единых стандартов, как отображать элемент /> по умолчанию. Более того, у этого элемента нет атрибутов, позволяющих его в какой-то мере стилизовать.
    Из-за необходимости привести это поле формы к единому виду во всех браузерах и «вписать» в разработанный дизайн, после поисков и анализа материалов в интернете был разработан метод замены вида поля формы на html+css, и js для расширения функциональности.

    Как по умолчанию выглядит это поле?


    <input id="upload" type="file" name="upload" />
    

    Так он выглядит в Internet Explorer 9:
    image

    А так — в Firefox:
    image

    В Google Chrome:
    image

    В Opera:
    image

    В Safari:
    image

    Стилизация поля file

    В то место, где должно быть поле выбора файла, вставим следующий код:
    <div class="fileform">
    <div class="selectbutton">Обзор</div>
    <input id="upload" type="file" name="upload" />
    </div>
    

    В файл стилей добавим такие блоки:
    .fileform { 
        background-color: #FFFFFF;
        border: 1px solid #CCCCCC;
        border-radius: 2px;
        cursor: pointer;
        height: 26px;
        overflow: hidden;
        padding: 2px;
        position: relative;
        text-align: left;
        vertical-align: middle;
        width: 230px;
    }
     
    .fileform .selectbutton { 
        background-color: #A2A3A3;
        border: 1px solid #939494;
        border-radius: 2px;
        color: #FFFFFF;
        float: right;
        font-size: 16px;
        height: 20px;
        line-height: 20px;
        overflow: hidden;
        padding: 2px 6px;
        text-align: center;
        vertical-align: middle;
        width: 50px;
    }
     
    .fileform #upload{
        position:absolute; 
        top:0; 
        left:0; 
        width:100%; 
        -moz-opacity: 0; 
        filter: alpha(opacity=0); 
        opacity: 0; 
        font-size: 150px; 
        height: 30px; 
        z-index:20;
    }
    

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

    Главный недостаток полученного решения от стандартной формы — оно никак визуально не сигнализирует о том, что файл был выбран. Эта проблема решается с использованием javascript.

    Добавление подписи о выбранном файле

    Добавим к полю функцию-обработчик событий, а к блоку — еще один блок-заголовок и, конечно, его стиль:
    <div class="fileform">
    <div id="fileformlabel"></div>
    <div class="selectbutton">Обзор</div>
    <input type="file" name="upload" id="upload" onchange="getName(this.value);" />
    </div>
    

    .fileform #fileformlabel { 
    background-color: #FFFFFF;
    float: left;
    height: 22px;
    line-height: 22px;
    overflow: hidden;
    padding: 2px;
    text-align: left;
    vertical-align: middle;
    width:160px;
    }
    

    Сама функция-обработчик получает полное имя выбранного файла, отбрасывает путь (с проверкойдля разных файловых систем), сохраняет имя с расширением в переменную filename и записывает его в блок fileformlabel.
    function getName (str){
        if (str.lastIndexOf('\\')){
            var i = str.lastIndexOf('\\')+1;
        }
        else{
            var i = str.lastIndexOf('/')+1;
        }						
        var filename = str.slice(i);			
        var uploaded = document.getElementById("fileformlabel");
        uploaded.innerHTML = filename;
    }
    

    Теперь поле формы выглядит так (при этом можно менять его размер, цвет, шрифт и выравнивание):

    image

    Данная заметка — реализация метода, предложенного в статье «Кастомизация input type=”file” с помощью CSS»
    Share post

    Similar posts

    Comments 56

    • UFO just landed and posted this here
        +21
        В условиях, когда всё стилизовано, использовать обычный файл-селект просто ужасно.
          –5
          не ужасно
            +3
            Сразу виден «программист» а не дизайнер или обычный пользователь.
              0
              Если этот человек вобще имеет отношение к разработке…
              Я как программист люблю кастомные текстовые поля, селекты и прочие елементы.
                0
                *(одев маску пользователя) мне нравится, когда одни и те же элементы/контролы выглядят и работают одинаково. Меньше уходит времени на привыкание к новой программе/сайту. Особенно эта проблема проявляется у людей в возрасте.

                *(меняем на дизайнера) хочу, чтобы у продукта был единый и лаконичный стиль.

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

                А вообще — это тот ещё холивар.
          0
          Ну и сделайте его (скорее всего вы захотите только кнопку сделать стандартной?) тоже нативно выглядящим в своей теме. Для этого Вам выдали CSS-свойства -webkit-appearance & -moz-appearance.
            +1
            Тогда непонятно, что делать с Opera и Chrome, а тем более IE, под которые (оказывается!) тоже надо затачивать кроссбраузерный сайт.
            Более nого, Input type=text в отличие от файла стилизуется, и когда у вас форма с тремя текстовыми полями и файлом, файл выглядит будто прилепленный.

            А еще в процессе работы над дизайном обнаружилось, что текст на кнопке в Chrome не убирается стандартными способами, и при ширине поля меньше 120px безобразно ломает форматирование.
              +2
              Ну, с оперой проблемы скоро не будет
              0
              кстати в хроме кроме того есть псевдокласс для стилизации конкретно кнопки файл-инпута. точно не помню, нужно в инспекторе смотреть
            0
            А почему нельзя использовать нативно оформленный input и button?
            Остальное на js повесить
              –2
              потому что это запрещено политиками безопасности
                –3
                В каком это смысле? Каким образом политика безопасности это запрещает?

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

                Может быть более логичным будет решение совсем всё же спрятать нативное поле (CSS: display: none;), а вместо блоков под наименование и кнопку использовать соответствующие HTML-элементы. Собственно события onclick и onchange просто пробрасывать между полями скриптом (проброс — это например onclick="document.getElementById('elementId').click();"). В этом случае логичнее получается реализации элементов относительно типа, и отсутствуют полностью проблемы со стилями — CSS можно пользоваться в полной мере. Кстати JavaScript тогда сводится до пары коротких строчек полностью помещаемых в значения атрибутов onclick и onchange элементов полей.
                  0
                  Продемонстрирую предложенное мной выше решение:
                  <input type="file" name="upload" id="upload_hidden" style="display: none;"
                          onchange="document.getElementById('upload_visible').value = this.value;" />
                  <input type="text" readonly="1" id="upload_visible"
                          onclick="document.getElementById('upload_hidden').click();" />
                  <button onclick="document.getElementById('upload_hidden').click();">Обзор</button>
                  

                  Соль, перец, специи CSS, как говорится, — по вкусу.
                    0
                    И даже если уж будут проблемы с передачей события полю с установленными display: none, то всегда найдутся способы скрыть его, пусть даже и чуть менее элегантно, но совершенно не нарушая общий принцип.

                    За 10 минут подбора варианта, спокойно «съедаемого» всеми подручными мне на текущий момент браузерами, получилось найти такую комбинацию:
                    <input type="file" name="upload" id="upload_hidden"
                            style="position: absolute; display: block; overflow: hidden; width: 0; height: 0; border: 0; padding: 0;"
                            onchange="document.getElementById('upload_visible').value = this.value;" />
                    <input type="text" readonly="1" id="upload_visible"
                            onclick="document.getElementById('upload_hidden').click();" />
                    <button onclick="document.getElementById('upload_hidden').click();">Обзор</button>
                    
              +3
              Было уже habrahabr.ru/post/30560/. Тут хотя бы расписаны размеры кликабельной области.
                +1
                Забавно, тот пост настолько старый, что там хрома нет. :)
                Ну, это просто к слову. Само собой, подхода мало изменились (что очень печалит).
                +11
                ".fileform #upload, .fileform #fileformlabel" — я бы за такое уволил
                  +2
                  Поймите меня правильно, я разделяю вашу точку зрения, но на половину. Пускай уже хоть так, зато без таблиц :)
                  • UFO just landed and posted this here
                    0
                    С точки зрения производительности это то же самое, что и "#upload, #fileformlabel". Descendant селекторы читаются справа налево, ЕМНИП, а #id-селекторы работают до первого совпадения.
                    • UFO just landed and posted this here
                        0
                        Вы определенно правы. Каюсь, ошибся.
                    +4
                    Все в этом решении хорошо. Кроме того, что оно не работает. С клавиатуры никак нельзя переключиться на это поле.
                      0
                      Только что проверила на готовом проекте.
                      В целях эксперимента: выделяем предыдущий input, жмем Tab, жмем Enter. Появляется окно выбора файла. Выбираем, закрываем — имя файла в блоке. (Браузер Opera)
                      0
                      Боян Боянович Боянов :)

                      Сам когда-то искал способ замены input[type="file"], этот способ не понравился тем, что:
                      • во первых: нельзя изменить на тот-же pointer
                      • во вторых: это неполный адрес до файла, точнее его отсутствие.

                      Впрочем, вот полная кастомизация загрузчика: jsfiddle.net/gKVKm/36/ (хотя «во-вторых» присуща всем кастомизациям)
                      А вот ваш пример: jsfiddle.net/6rL4j/
                        +1
                        А зачем вам cursor: pointer на элементе, который не перезагружает страницу?
                          +1
                          Затем, чтобы было понятно, что сюда можно тыкнуть.
                            +1
                            Т.е. просто изображения кнопки и ховера уже недостаточно?
                              +3
                              Вы явно пользователь Linux :)
                              Моё убеждение таково: чем лучше, приятней, удобней и проще интерфейс — тем больше шансов на получение профита от юзера.
                              И раз уж это кнопка (т.к. мы её нажимаем), то курсор должен выглядеть как pointer, или default, но никак не text.
                                +2
                                Не угадали :)

                                Хороший интерфейс — это простой интерфейс. А лучший — это интерфейс, который не требуется.
                                Подумайте вот над чем: <button>, <input> по-умолчанию не случайно показывают default, а ссылки (кстати, можете проверить, без атрибута href <a> даже не подчёркивается) — не случайно pointer. Переопределяя курсор, вы ломаете устоявшуюся логику его поведения, пусть незначительно, но ухудшая восприятие интерфейса.
                                  +1
                                  Ссылки без атрибута href не подчеркиваются потому что, предполагается, они будут служить якорями (в моем понимании).

                                  Давайте также порассуждаем о input'ах. Ясное дело, что по дефолту они изменяют своё визуальное состояние при получении и утрате фокуса, но не изменяют состояние курсора. Добавим рядом с элементом input элемент a с ссылкой (назад например). Что получится: ссылка изменяет стиль курсора, а кнопка нет. Смотреться будет не лаконично и сбивать столку.
                                  Вспомним о том, что кнопки могут быть со статусом disabled, Т.е. отключены. Но так же вспомним, что у кнопок может быть не стандартный стиль, а, например, стиль под серый сайт. Как мне понять, выключена ли кнопка или нет, если курсор при наведении не изменяется?
                                  Спецификация спецификацией, но в ней не указано, что курсор нельзя использовать для других вещей.
                                  А лучший — это интерфейс, который не требуется

                                  Утопия :) Хотя может быть когда-нибудь сделают так, что компьютер уже будет думать за вас и вам останется только подойти и взять. Но в этом попике же не об этом?)
                                    +1
                                    Что получится: ссылка изменяет стиль курсора, а кнопка нет. Смотреться будет не лаконично и сбивать столку.

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

                                    Ок, без примеров, возможно, сложно понять, о чём я говорю.

                                    Что будет при клике на этом текстовом блоке?
                                    Скрытый текст
                                    image


                                    Присутствуют ли на изображении кнопки и если да, то на какую можно нажать?
                                    Скрытый текст
                                    image


                                    Какой блок текста является интерактивным и что произойдёт при клике на него?
                                    Скрытый текст
                                    image


                                    А теперь, внимание, сложный вопрос без однозначного правильного ответа:
                                    Обе кнопки при наведении идентичны (курсор так же одинаков). Какая из них, по завершению работы, обновляет страницу?
                                    Скрытый текст
                                    image


                                    Утопия :)

                                    Может, для кого-то, к примеру, автосохранение — это утопия =)
                                      0
                                      Логично, что у двух разных элементов, с совершенно разным поведением, будет разное отображение, не правда ли?

                                      Вы ошиблись, зачастую кнопка «Сохранить» и ссылка перезагружают страницу, либо ссылаются на другую страницу.

                                      И вы сами привели пример, когда у нас имеется 2 кнопки, которые при наведении изменяют стиль курсора.
                                      В этом случае даже при неизменном стиле при фокусе было бы понятно, что это кнопка, что кнопка «рабочая» и что её можно нажать.

                                      Вот вам кнопки в вакууме: jsfiddle.net/ESME5/ я уверен, что большинство пользователей бы выбрали кнопку с идентификатором #3.
                                        0
                                        я уверен, что большинство пользователей бы выбрали кнопку с идентификатором #3.

                                        Что значит выбрали? Мы же не предлагаем пользователю нажать на любую понравившуюся кнопку.

                                        На базе вашего же примера: какая из кнопок сохраняет данные без перезагрузки страницы?
                                        http://jsfiddle.net/ESME5/1/
                                          0
                                          Что значит выбрали? Мы же не предлагаем пользователю нажать на любую понравившуюся кнопку.

                                          Это значит, что мы бы предложили сделать выбор пользователю, какая, по их мнению, кнопка наиболее удобная. Проще: сделали бы опрос.

                                          На базе вашего же примера: какая из кнопок сохраняет данные без перезагрузки страницы?

                                          Скорее всего первые 3, т.к. они как-то реагируют на изменение фокуса. Но изменение фона далеко не всегда обозначает, что нажатие на элемент приведет к какому-нибудь действию.
                                            0
                                            Проще: сделали бы опрос.

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

                                            Скорее всего первые 3, т.к. они как-то реагируют на изменение фокуса

                                            Если первые 3 — то такому дизайнеру интерфейсов нужно съездить по морде, поучиться у более профессиональных товарищей.
                                            И завязывайте уже называть «наведение» «фокусом».
                                              0
                                              Если первые 3 — то такому дизайнеру интерфейсов нужно съездить по морде, поучиться у более профессиональных товарищей.

                                              А если последние 2 — добро пожаловать в проектирование интерфейсов билайна.

                                              У вас просто фокус на данную проблему с другой стороны наводится :) Да и не спроста эти стандарты с 1997 года не изменялись. Видимо, не мы первые ведем такую дискуссию.
                                                0
                                                Чушь. Некоторым дизайнерам просто надо чуточку отдохнуть, у них замылились мозги от стандартов, спецификаций и проч. +)) Иногда стоит подумать о пользователе, а не о том, как выглядеть умней, стильней и современней среди своих.
                                                Кнопка с указателем в виде пальца ясно дает понять, что на нее можно нажать. И мне абсолютно сиренево перезагрузит она страницу или нет. Pointer на кнопке ломает шаблон только у супер-пупер-дизайнеров интерфейсов, остальным все вполне понятно. +))
                                                • UFO just landed and posted this here
                                                    0
                                                    Согласен во всем. Но twenty утверждал, что при наведении на кнопку обязательно курсор должен быть в виде стрелки. +)) Аргумент — веб-стандарт.
                                                    Но очевидно же, что для пользователя курсор пальцем более понятен там, где в интерфейсе ничего не понятно. И так же понятен там, где дизайн интерфейса понятней понятного.
                                                    А курсор в виде стрелки виден на любом месте страницы, где нет элементов. С чего вдруг пользователю должно быть понятно, что кнопка нажимается, если при наведении вообще ничего не меняется, ни цветом, ни курсором. +))

                                                    ЗЫ. Даже здесь, в форме ответа, кнопки имеют курсор в виде пальца. +))
                                                    • UFO just landed and posted this here
                                                        0
                                                        Не хочу сказать, что курсор-палец однозначно плох или курсор-стрелка однозначно хорош. [...] разным людям «очевидно» совершенно разное, совсем как с тем платьем:). [...] дизайнеры игнорировали стандарты в угоду своим собственным «очевидным» привычкам…


                                                        Вот мы и приходим к тому, что стандарты не всегда соответствуют желанию потребителя. Дизайнеры тоже потребители. И судя по количеству дизайнеров, которые игнорировали стандарт со стрелкой на кнопке, этот веб-стандарт не соответствует потребностям пользователей. +))) Ведь стандарты придумывают тоже люди, и по моему жизненному опыту часто руководствуются собственными «очевидными» привычками на тот определенный момент времени.
                                                        Как мне кажется, стандарт со стрелкой на кнопке просто устарел, и сегодня не имеет под собой логичного обоснования. Главный стандарт в дизайне интерфейсов — интерфейс должен быть понятен.
                                                        • UFO just landed and posted this here
                                                          • UFO just landed and posted this here
                                                              0
                                                              курсор-палец остается признаком ссылки

                                                              Признаюсь, я про стандарт со стрелкой/пальцем узнал из этих комментариев, и, наверняка, являюсь веб-программистом, который не знает всех стандартов. +))
                                                              Но, что самое смешное, я — юзер, которому курсор мыши пальцем дает только одну подсказку: можно нажать. Никогда не задумывался про возможность скопировать адрес или открыть в новой вкладке.
                                                              В таком случае интересен такой вопрос: мне часто проходится реализовывать кнопки, которые по факту являются ссылками, но результат нажатия напоминает отправку формы с перезагрузкой страницы. Какой курсор я должен использовать по стандарту (браузер использует палец)? Должен я указывать курсор стрелкой? +))
                                                              • UFO just landed and posted this here
                                                                  0
                                                                  Но выглядят они как кнопки. +)) Например, кнопка «Положить в корзину» в интернет-магазине.
                                                                  • UFO just landed and posted this here
                                0
                                В Вашем мире нет места AJAX`у.
                                  +1
                                  Вы не поверите, всё очень логично: AJAX не презагружает страницу, значит на кнопке (или dashed-ссылке) должен быть cursor:default.
                              0
                              ожидал увидеть нечто новое.
                              вы уж извините, но перед тем как писать новый велосипед нужно просмотреть существующие велосипеды.
                              ваша реализация идет имеет ряд недостатков.

                                0
                                Ваш велосипед устарел лет на несколько.

                                Все актуальные браузеры давно понимают $("#my-cool-button").click(function() { $("#real-file-input").click(); });, при этом "#real-file-input" можно запозиционировать куда угодно за край экрана, чтобы не мешался. Свойство value у #real-file-input тоже прочесть не проблема.
                                  0
                                  Свойство value у #real-file-input тоже прочесть не проблема.

                                  Как правило оно будет C:/fakepath/file.name.on.our.disk.ext, в целях безопасности JS не выдаст полный путь, ибо можно перехватить (и оно нужно только для оформления). При реальном аплоаде — отсылается нормальная форма
                                  +2
                                  Печалька. Стандарты то, стандарты се, javascript в 100500 раз быстрее, html5 и пр., а для решения такой тривиальной задачи приходится возвращаться к костылям. А если нужно сделать красивый аплоад с индикатором и прочими няшками, то и вовсе эйфория от продвинутости веба сливается моментом (html5 для одного, flash для другого и html4 для третьего).

                                  И всегда поражался, почему хром и сафари решили выпендриться и отображать собственный дефолтный вид этих контролов. Вот зачем?)
                                    +1
                                    Да нет никаких костылей. Это у автора поста костыли в голове. Давно уже все браузеры (кроме IE < 10, разумеется) поддерживают единый и простой API: david-m.livejournal.com/1270765.html. Для старых IE да, нужен флэш, но, опять же, есть туча готовых решений и на флэше.

                                  Only users with full accounts can post comments. Log in, please.