Пользователь
0,0
рейтинг
4 августа 2008 в 12:12

Дизайн → Стилизация файл-инпутов

Результат стилизации файл-инпута
Привет. Сегодня я хочу вам рассказать о том, как можно изменить внешний вид файлового инпута.

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

Для начала давайте посмотрим на то, как отображаются файл-инпуты без применения каких-либо стилей в разных браузерах.

пустые инпуты

Как видим, во всех браузерах кроме сафари имеется текстовое поле, а справа от него кнопка. Расскажу о различиях. В Опере и IE мы можем написать адрес файла вручную (сомневаюсь, что кто-либо когда-либо пользовался этой возможностью). Файерфокс, несмотря на то, что у него есть текстовое поле, не дает нам вписать туда адрес файла. Вместо этого появляется окно выбора файла как при нажатии на кнопку «Обзор».
Давайте теперь выберем в этих полях какой-либо файл.
заполненные инпуты

В результате везде, кроме сафари, мы видим начало адреса, которое не несет почти никакой смысловой нагрузки. Я сомневаюсь, что кто-то об этом не знал, но на эту глупость обратили внимание только ребята из эпла и сделали возможность сразу увидеть не только название выбранного файла, но и иконку. Такую же функциональность файл-инпута мы и собираемся реализовать для всех браузеров.
Но cначала ознакомимся с проблематикой.
1. Средствами JS мы не можем сымитировать клик на такой инпут. Вот что говорится об этом в святом писании спецификации DOM:
click
Simulate a mouse-click. For INPUT elements whose type attribute has one of the following values: “button”, “checkbox”, “radio”, “reset”, or “submit”.
No Parameters
No Return Value
No Exceptions
То есть методом click мы можем сымитировать клик почти на всех типах инпутов, но не на файл-инпуте. Это сделано чтобы обезопасить компьютер клиента: в противном случае хозяин сайта мог бы без проблем получать любые файлы с компьютера клиента. Хотя с другой стороны, по клику вызывается только окно выбора файла. Так или иначе, в девелопер-центре файерфокса этот факт обозначен как баг.
Решение есть, и мы не придумывали велосипед, мы его тюнинговали. Все, кто стилизует инпуты действуют по той же схеме: создается инпут с нулевой прозрачностью и ставится поверх кнопки или изображения, которые представляют собой кнопку выбора файла.
Основная трудность в следующей проблеме.
2. Мы не можем свободно влиять на размеры кнопок «обзор», чтобы подогнать инпут под размер перекрываемой картинки. В файерфоксе мы вообще не можем изменить внешний вид файл-инпута средствами css (кроме высоты). То есть задача заключается определении оптимального размера перекрываемой картинки, чтобы минимальное количество пикселей было некликабельно, а пустые области не реагировали на клик.
Посмотрим на кликабельные области и их размеры в разных браузерах.
кликабельные области

Все что внутри голубой обводки — кликабельная область. Замечу, что высоту кнопок мы можем увеличить, а вот ширину — нет.
Проблемы ясны. Переходим к делу.
Для начала нарисуем кнопку для выбора файла. Вот какая получилась у меня.
В обычном состоянии:
кнопка
при наведении:
кнопка

Теперь для разных типов файлов подготовим иконки и объединим их в один файл.
кнопка
Для серьезных проектов лучше, конечно, рисовать свои иконки. Хорошие, и главное халявные иконки для документов есть в блоге Павла Марковнина, другие можете поискать среди нашей подборки иконок.
Итак, сверстаем шаблон инпута:
HTML:
<div class=«blocker»> <!--блок, перекрывающий поле ввода слева от кнопки-->
<input type=«file» id=«File1» class=«customFile» />
<div id=«BrowseButton» title=«Выбрать файл» class=«fakeButton»>
<div id=«FileName»> <!--сюда мы будем вставлять имя файла и иконку-->


CSS:
<style type=«text/css»>
#File1 {
position: absolute;
}
.customFile {
width: 219px;
margin-left: -140px;
cursor: default;
height: 21px;
z-index: 2;
filter: alpha(opacity: 0);
opacity: 0;
}
.fakeButton {
position: absolute;
z-index: 1;
width: 85px;
height: 21px;
background: url(images/button.jpg) no-repeat left top;
float: left;
}

.blocker {
position: absolute;
z-index: 3;
width: 150px;
height: 21px;
background: url(images/transparent.gif);
margin-left: -155px;
}
#FileName {
position: absolute;
height: 15px;
margin-left: 90px;
font-family: Verdana;
font-size: 8pt;
color: Gray;
margin-top: 2px;
padding-top: 1px;
padding-left: 19px;
}
#activeBrowseButton {
background: url(images/button_active.jpg) no-repeat left top;
display: none;
}
</style>

Результат выглядит приблизительно так:
приблизительный результат
Обведенное красным — blocker, файл-инпут показан с половинной прозрачностью.
Теперь при выборе файла (событие onchange) мы должны вырезать название файла из value нашего файл-инпута, определить тип файла по расширению и сместить фон, чтобы показывалась нужная иконка. Обратите внимание, что в разных операционных системах путь к файлу может быть через прямой слэш (в Mac OS, например), или через обратный (Виндуз), поэтому чтобы вырезание названия файла работало везде необходимо два регулярных выражения.
function HandleChanges() {
file = fileInput.value;
reWin = /.*(.*)/;
var fileTitle = file.replace(reWin, "$1"); //выдираем название файла для windows
reUnix = /.*/(.*)/;
fileTitle = fileTitle.replace(reUnix, "$1"); //выдираем название файла для unix-систем
fileName.innerHTML = fileTitle;

var RegExExt =/.*.(.*)/;
var ext = fileTitle.replace(RegExExt, "$1");//и его расширение

var pos;
if (ext) {
switch (ext.toLowerCase()) {
case 'doc': pos = '0'; break;
case 'bmp': pos = '16'; break;
case 'jpg': pos = '32'; break;
case 'jpeg': pos = '32'; break;
case 'png': pos = '48'; break;
case 'gif': pos = '64'; break;
case 'psd': pos = '80'; break;
case 'mp3': pos = '96'; break;
case 'wav': pos = '96'; break;
case 'ogg': pos = '96'; break;
case 'avi': pos = '112'; break;
case 'wmv': pos = '112'; break;
case 'flv': pos = '112'; break;
case 'pdf': pos = '128'; break;
case 'exe': pos = '144'; break;
case 'txt': pos = '160'; break;
default: pos = '176'; break;
};
fileName.style.display = 'block';
fileName.style.background = 'url(images/icons.png) no-repeat 0 -'+pos+'px';
};

};
function MakeActive() {
activeButton.style.display = 'block';
};
function UnMakeActive() {
activeButton.style.display = 'none';
};


Последние две функции MakeActive и UnMakeActive добавляют hover эффект к нашей кнопочке. Активное и неактивное состояние кнопки разбито в два файла, чтобы легко можно было реализовать анимацию для появления кнопки.

Отлично, но осталось несколько проблем. Первая: в разметке большое количество дивов, которые портят семантику.
Вторая: при отключенном js пользователь не увидит, какой файл у него выбран. Давайте в случае отключенного js будем выводить обычный файл-инпут, а всю необходимую нам разметку загружать при загрузке страницы. Приступим:
На странице у нас останется только два элемента:
<div id=«wrapper»>
<input id=«File1» type=«file»/>
</div>

Если у пользователя будет отключен JavaScript, он увидит обычный файл-инпут. В противном случае произойдет следующее:
window.onload = WindowOnLoad;
var fileInput = document.getElementById('File1');
var fileName = document.createElement('div');
fileName.style.display = 'none';
fileName.style.background = 'url(images/icons.png)';
var activeButton = document.createElement('div');
var bb = document.createElement('div');
var bl = document.createElement('div');
function WindowOnLoad() {
var wrap = document.getElementById('wrapper');
fileName.setAttribute('id','FileName');
activeButton.setAttribute('id','activeBrowseButton');
fileInput.value = '';
fileInput.onchange = HandleChanges;
fileInput.onmouseover = MakeActive;
fileInput.onmouseout = UnMakeActive;
fileInput.className = 'customFile';
bl.className = 'blocker';
bb.className = 'fakeButton';
activeButton.className = 'fakeButton';
wrap.appendChild(bb);
wrap.appendChild(bl);

wrap.appendChild(activeButton);

wrap.appendChild(fileName);
};

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

Оригинал статьи на временно.нет

* Source code was highlighted with Source Code Highlighter
Евгений Белодед @Zhendalf
карма
100,2
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Дизайн

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

  • +15
    Отличная статья, спасибо.
    • –16
      Бесполезный комментарий, спасибо.
      • +5
        Меня как бы мало волнует чьё-то мнение о моих комментариях.
        • 0
          Справедливо голоса распределились.
  • 0
    Спасибо, круто)
    мне всегда нравилось как инпут.файл реализован в Сафари
    • 0
      Моё мнение: в Safari инпут не "нравится" - там он просто сделан правильно.
      • –1
        Согласен. Что за бред — позволять пользователю вводить в поле всякую чепуху (я про ИЕ).
        • +4
          это иногда бывает удобно

          Например. Заливаем кучу фоток с именами 001.jpg, 002.jpg, ... что бы не клацать мышкой всё время удобно копипастить путь от туда и править имя файла.

          Ну конечно очень нечастый пример, но всёже.
          • +1
            сам частенько так делаю..
            надо искать компромиссное решение
          • 0
            бывает, конечно, спору нет. но вы же разработчик. мне было бы приятнее еще многое в браузерах, например, встроенное изменение html и js на лету для своих целей (благих), но разработчики подумали, что в этом нет необходимости (и я согласен).
            Не думаю, что разработчики интерфейса Apple сделали так по прихоти...
        • +2
          а я копирую путь из файлменеджера и вставляю в поле. можно?
          • 0
            А у меня единственное постоянно открытое неконсольное приложение — броузер. Можно?
            • +1
              а у меня единственное открытое консольное приложение — Terminal.app, и то он не совсем консольный… Можно?
          • 0
            можно, конечно) но представьте обыкновенного пользователя — он так будет делать? те пользователи, которых я знаю, так не делают, им проще найти файл через обозреватель. я за свою работу ни разу не копировал. проще драг&дроп.
  • 0
    Спасибо большое, за интерестный и полезный урок, совсем не помешает. ;)
  • 0
    Спасибо, поюзаем ;)
  • –1
    А как быть при javascript off?
    • 0
      будет показываться обычный файл-инпут. В статье это написано.
      • –17
        Да, вижу, не заметил...
        Тогда нет вопросов - всё очень добротно, интересно и... старо, как мир... Но для новичков - будет полезно.
    • –3
      Ну что за паранойя, что за привычка придираться ко всякой мелочи?
      Тем более в статье ясно написано: «Если у пользователя будет отключен JavaScript, он увидит обычный файл-инпут.»
      А те пользователи кто живут без JS пусть идут лесом.

      Кстати, Zhendalf, спасибо за интересную статью.
      • +1
        "А те пользователи кто живут без JS пусть идут лесом."
        Это где вас такому учили? :(
        • НЛО прилетело и опубликовало эту надпись здесь
          • –3
            Мне искренне жаль таких горе-мастеров...
            • 0
              Как я уже писал когда-то, надо всегда смотреть на что ориентирован сайт.
              Большинство современных сайтов без JS будут не только не подобающе работать,
              они не будут работать вовсе.

              Делать надо исходя из затрат на поддержку при
              отключении JS. Есть старое правило - "Цель оправдывает средства".

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

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

              Если же нет, и Вы планируете что просмотр данного сайта будет идти через PC
              или же сайт вообще является веб аппликацией - то смысл убиваться за то, чтобы работало без JS нет вообще. Вы много видели браузеров на компьютерах, где отключен JS? Другое дело, что хорошим тоном было бы предупредить человека про JS, если же это все такие случилось.
          • +3
            Знаете, если вы нигде не видели сайтов, которые будут работать с отключенным JS это во-первых не значит что их нет, во вторых не значит что надо поступать так-же как и они.
            • –2
              +1
            • НЛО прилетело и опубликовало эту надпись здесь
          • –1
            Заминусовали до нельзя :(
            • НЛО прилетело и опубликовало эту надпись здесь
              • –3
                Судя по Вашей карме вы много кричали "ИЕ - говно" :)
                • НЛО прилетело и опубликовало эту надпись здесь
                  • –1
                    Отвечаю на Ваш вопрос:

                    "Вы много видели браузеров на компьютерах, где отключен JS?"
                    - Нет, как правило, всё именно так, как Вы говорите. Такие случаи редки, но знаете, часто бывает так, что в 0.01% попадает заказчик сайта, который абсолютно верно будет ездить вам по рогам, если у вас не было такого опыта, то, извините, это Ваше незнание...
              • –3
                Я есть живой контр-пример )
                Firefox + NoScript (http://noscript.net/) => по умолчанию все JS отлючены.
                • 0
                  А для чего? Никогда я этого не понимал.
                  • 0
                    Для безопасности, например, для производительности.
    • 0
      как ни крути а на js все равно делают такие вещи pngfix и min-weight для IE6, или ктото знает другие решения ;)
      • 0
        Во-первых — min-width, а во вторых, делают это с помощью CSS или expression() опять же в CSS.
  • 0
    Здорово-здорово!
    Вот только пользователя может слегка заступорить такая замена, плюс надпись «найти файл» не совсем очевидна.
    • 0
      Возможно. Но текст на картинке мы всегда можем поменять, а вот текст на обычном инпуте - нет.
  • 0
    Прекрасно, достойно! Замечательно! Давно не помню такой хорошей статьи, лишний раз появился стимул заходить сюда чаще. Автор — молодец!
  • 0
    Есть ли возможность как-то продумать вариант, если пользователь выбрал файл, а потом передумал и захотел оставить поле пустым?
    • 0
      Это сделать вообще нельзя. Мы не можем средствами js изменить value у файл-инпута. Это можно сымитировать, просто убрав текст.
      • 0
        Если я не ошибаюсь, присваивать значение инпуту нельзя, но обнулить его, сбросив значение, вполне врзможно.
        getElementById("outInput").value = '';
      • 0
        Ну можно например удалить со страницы файл-инпут и вставить на его место такой-же но пустой, если обнулять его нельзя.
      • 0
        а как же кнопка reset и одноименный метод у форм?
  • –1
    Шикарно 0_о
    • –2
      Вы забыли добавить слово «Хуясе».
      • 0
        Вы забыли, что неприлично перебивать старших ;-)
        • –1
          Хм, а я и не перебивал.
      • –3
        вы забыли катиться к чертям
        • 0
          А Вы нет?
  • –2
    Низкий поклон. Полностью согласен, от и до. Mac-style это практически всегда простой, удобный user-oriented (идеальный) вариант. Взял на заметку для использования, в том числе, и в некоторых win32-приложениях.
  • 0
    Качественная статья, спасибо.
  • 0
    Спасибо большое, дельный совет.
    Особенно точно - про "мы видим начало адреса, которое не несет почти никакой смысловой нагрузки"
  • 0
    А можно ли все-таки дополнительно дать информацию о пути к файлу?
    В тултипе, например.
    • –2
      Не стоит, если пользователь только что выбрал файл, он не может забыть какой именно.
      • 0
        оно не будет мешать - путь будет появляться при наведении на название файла.
    • 0
      согласен. Надо будет в финальной версии этого скрипта сделать. Только полный адрес можно будет получить не во всех браузерах. fileInput.value в некоторых браузерах возвращает полный путь, в некоторых только название файла. Сейчас уже точно не помню где как.
  • +1
    Спасибо, очень полезно.

    Если кому интересно продолжение темы кастомизации "непокорных" элементов, то
    - Кастомайз select'а http://designformasters.info/posts/select-replacement/
    - Кастомайз radio&checkbox http://lipidity.com/fancy-form/
    - Кастомайз скролла http://www.hesido.com/web.php?page=customscrollbar

    Все решения полнофункциональны, т.е. селект работает с клавиатурой (клавиши вверх, вниз и т.п.), скролл реагирует на колесо мыши и якоря.
    • 0
      хорошие ссылки. Спасибо ;)
    • 0
      вы попробуйте в тот селект (откастомайзеный) вставить больше 20 элементов, не будет окошка выбора со скролом, будет галимая бесконечная лента! А если элементов больше 1000? так будет вообще полная попа. раздосадная штука! у гугла есть рабочие семплы нормально изменённых селектов, и работают они быстрее!
      • 0
        а можно подробнее про рабочие семплы?
        • 0
          Мне бы тоже было интересно.
          А пока я нашел другой вариант, где скролл не превращается в "галимую ленту": http://ryanfait.com/resources/custom-checkboxes-and-radio-buttons/ (тем не менее первый вариант для небольших селектов очень приятен)
        • 0
          а понту, опять минус просто так поставят
          что за люди
  • 0
    Отличная идея. А то вечно приходится влазить в этот textbox, прокручивать текст и смотреть, тот ли я файл выбрал.

    А можно сделать, чтобы после выбора можно было навести курсор на имя файла и увидеть полный путь во всплывающем комментарии или в строке статуса?
    Просто часто полезно глянуть лишний раз, что отправляешь - иногда не только имя, а если там untitled.zip, то и путь. Путь гораздо реже нужен, но хотелось бы не терять эту информацию, а просто убрать её "поглубже".
    • 0
      Упс, уже написали выше
  • +2
    Вариант когда картинки выключены тоже нужно обсчитывать иначе инпут не видно
  • 0
    Шикарно. Просто блеск. Я не думал, что это вообще возможно, а здесь — классная идея и красивая реализация. Пожалуй, лучшее из технического, что я прочитал на Хабре.
  • –1
    Круто, но я предлагаю не делать свои костыли а рядом с input-файлом повесить ссылку "К сожаление разработчики %браузер% не всегда знают о своих косяках. Откройте им глаза!". Ну а при клике через аякс вызыввается скрипт отсылающий письмо с текстом "Ещё один посетитель нашего сайта недоволен работой вашего браузера. Просим вас устранить %неисправность%" на support@mozilla.org или куда там ещё.
  • 0
    для Java уже есть великолепная реализация на JSF от RichFaces:

    http://livedemo.exadel.com/richfaces-demo/richfaces/fileUpload.jsf

    Красивый GUI, множественный выбор, *прогресс загрузки*
  • –1
    ООО. Я уже такое делал но чуть по иному и у меян в опере невыходело сделать и ховер тоже невыходил, а тут все есть, плюс однозначно !
  • +1
    В целом очень-очень красиво реализовано.
    Чуть-чуть, самую малость, критики и предложений по улучшению.

    В функции HandleChanges() можно и нужно упростить регулярное выражение до одной строки
    fileTitle = fileInput.value.replace(/.*[\\\/]/, '');

    И сократите такие вещи как:
    case 'avi': pos = '112'; break;
    case 'wmv': pos = '112'; break;
    case 'flv': pos = '112'; break;

    до
    case 'avi':
    case 'wmv':
    case 'flv': pos = '112'; break;
    • 0
      это да. Спасибо.
    • 0
      fileTitle = fileInput.value.replace(/.*[\\\/]/, '');
      Спорно. А что если в одном пути будут и прямые и обратные слеши?
      • 0
        а разве в названии файла в юникс-системах могут быть слеши? В виндуз - нет. То есть в адресе не может быть одновременно разных видов слешей.
        • 0
          Теоретически, могут: /home/user/nazvanie\ s\ probelami

          Но я не уверен в том, как браузеры это дело обрабатывают — сохраняют ли экранирование, не проверял.
        • 0
          в виндовсе

          D:\>dir "d:\tmp/tmp1\tmp2"
          Том в устройстве D не имеет метки.
          Серийный номер тома: 9C70-5B85

          Содержимое папки d:\tmp\tmp1\tmp2

          04.08.2008 21:26 <DIR> .
          04.08.2008 21:26 <DIR> ..
          04.08.2008 21:26 <DIR> tmp3
          0 файлов 0 байт
          3 папок 153 398 829 056 байт свободно


          пример надуман, но вменах файлов виндос (кажется начиная с w2k, может и раньше), вполне себе понимает прямой слеш как разделитель каталогов
          • 0
            Очень сомневаюсь, что при использовании стандартного диалога ОС Виндовс выбора файла, он (диалог) вернет путь к файлу с разносторонними слешами одновременно!
            • 0
              выбор файла скорее всего правильные слеши, потому и написал, что пример надуман.
          • 0
            а а если так:

            dir /tmp
            >dir /tmp
            Ошибка в формате параметра: "mp".

            такчто не все так гладко как хотелосьбы
            • 0
              если так, то "/" обрабатывается в другом месте.
              Правильнее всего из программы проверять, конечно
  • +1
    Еще у инпута в Safari есть безоговорочный плюс. Можно просто сделать драг-н-дроп своего файла прямо на кнопку.
    • 0
      круто, сколько таит сафари в себе открытий чудных.
    • 0
      Да-да-да, это ведь и есть самое главное достоинство (на мой взгляд) Сафаревского инпута.
  • 0
    хм, мало юзал сафари и не знал, про это. В сафари действительно продуманей сделано, спасибо за инфу.
  • +1
    Пожалуй в статье не хватает лишь описания того, как сделать большую кнопку. Для этого нужно просто перемещать прозрачный конторл над большой кнопкой вместе с движением мышки.
    • 0
      можно гораздо проще. Увеличить размер шрифта + position:absolute; right:0;
      • 0
        Это не всегда сработает, в первую очередь в случае широких кнопок.
  • 0
    Только вот если ваша кнопка большая по ширине, то все, ку-ку досвидос.
    • 0
      • 0
        Лишний гемор. Лучше так поступить: http://habrahabr.ru/blog/ui_design_and_usability/48274.html#comment1040613
  • 0
    Недавно с товарищем как раз спорили по этому поводу. Благодарю за статью.
  • 0
    Лучше делать, чтоб при нажатии на кнопку в страницу добавлялся флэш-обьект, в котором вызывается диалог выбора файла.
    Тогда вы не зависимы ни от каких инпутов и стилизовать все проще.
  • 0
    Вот так выглядит в IE 7
    ie7
    • 0
      А у вас случайно не IE8beta1 в режиме эмуляуции IE7 ? там могут быть всякие глюки с CSS...
      • 0
        и правда, что-то я стормозил.. это бета ie8.. в ie7 проверил, всё ок...
  • 0
    Спасибо, добавил в избранное)
  • 0
    Хммм... Хью Лори... Свой человек :)

    Пасибо за инфу, все никак не мог найти толкового туториала на эту тему...
  • 0
    Респект за статью.. обязательно буду юзать...

    ЗЫ.. добавил в избранное
  • 0
    Насущно. Спасибо.
    Отдельный респект за "Hugh Laurie - Silent Night.mp3" :)
  • 0
    На яндекс почте такое реализовано (почти такое)
    • 0
      • 0
        извините, не разобрался пока, как тут парсер работает, вижу, что странно, через тег img не вставилась картинка:
        http://smages.com/i/91/de/91de029bad5689bb1332b62af55edbfb.png
        • 0
          width height не указал наверное
          • 0
            неа, все указал, ну да не важно - оффтоп
  • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    Что-то никто не отозвался по поводу asp.net контрола. Или здесь нету дотнет-прогеров?
    • 0
      Можно поподробнее?
      • 0
        в asp.net 2.0 есть встроенный объект, называется FileUpload. Единственное чем он отличается от файл-инпута - тем что он серверный контрол.
        Точно также можно сделать и с моим файл-инпутом. Можно добавить некоторые свойства, например количество файл-инпутов, генерируемых изначально или возможность добавления новых.
        Пример - телериковский файл-аплод. Сделан он криво, в некоторых браузерах работает меньшая часть кнопки. Да и стоит много уёв. Но на него можно посмотреть, чтобы понять о чем я говорю.
        • 0
          насколько помню на клиентской стороне fileUpload работает через стандартный инпут браузера. разве что на него валидаторы навешать можно. а серверная в нем только обработка сабмита формы. и если поставить какойто серверный компонент рядом с аплоадом - получишь кучу траблов - аплоад будет сбрасываться при релоаде страницы

          IMHO можно спокойно использовать описанную методику практически ничего не изменяя
          не говоря уже о том что создать пользовательский контрол из fileUpload с этой методикой

          вспомнилось... когда уже сделают мультиаплоад в браузерах? (в свое время нашел единственный вариант - на флеше. но там не все просто с сессией asp.net2)
  • 0
    С регекспами косяки:

    1) не нужно два, достаточно одного: /.*[\/\\](.*)/
    2) этот код:
    var RegExExt =/.*.(.*)/;

    должен быть таким:
    var RegExExt =/.*\.(.*)/;
  • +2
    Может вашу функцию немного переписать?

    function HandleChanges(){
    var pos = ['doc', 'bmp', 'jpg', 'jpeg', 'png', 'gif', 'psd', 'mp3', 'wav', 'ogg', 'avi',
    'wmv', 'flv', 'pdf', 'exe', 'txt'].indexOf(fileInput.value.match(/\.([a-z]{3,4})\s*$/)[1]);
    fileName.style.display = 'block';
    fileName.style.background = 'url(images/icons.png) no-repeat 0 -' + (pos < 0 ? 176 : pos * 16) + 'px';
    }

    Да [].indexOf не будет работать во всех браузерах, тогда добавим

    if (!Array.prototype.indexOf)
    Array.prototype.indexOf = function(value){
    for (var i = 0; i < this.length; i++)
    if (this[i] === value)
    return i;
    return -1;
    }

    Ну или перебор массива добавляем в код функции.
    • 0
      Отлично, и с рабочего стола переносятся файлы на кнопку. В избраное.
      • 0
        Упс, не туда.
    • 0
      тогда в файле с иконками должны быть повторения: jpeg,jpg - это одна и та же иконка. А если мы захотим что-то добавить, несмотря на то, что иконка уже в файле есть, все равно придется переделывать не только js, но и файл с иконками.
      • 0
        Я ожидал такого вопроса, все зависит от вашей задачи (условий). Тогда можно было бы сделать так (еще проще):
        function HandleChanges(){
        var ext = fileInput.value.match(/\.([a-z]{3,4})\s*$/)[1];
        var extList = ['doc', 'bmp', 'jpg|jpeg', 'png', 'gif', 'psd', 'mp3',
        'wav', 'ogg', 'avi', 'wmv', 'flv', 'pdf', 'exe', 'txt'];
        for (var pos = 0; pos < extList.length; pos++)
        if (new RegExp('^(' + 'jpg|jpeg' + ')$', 'i').test(ext))
        break;

        fileName.style.display = 'block';
        fileName.style.background = 'url(images/icons.png) no-repeat 0 ' + (-pos * 16) + 'px';
        }

        В любом случае switch в решении этой задачи неоптимален.
        • +1
          Сорри ошибочка вышла. Имелось ввиду

          if (new RegExp('^(' + extList[pos] + ')$', 'i').test(ext))
          • 0
            Ага, классно. Спасибо Вам в карму за оптимизацию.
        • 0
          Почему-то сработало только в файерфоксе. Ослик не показал иконку.
        • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    Было бы здорово создать для общего пользования .net компонент :)
  • 0
    понравилось :) зачет!
  • 0
    красиво !
    интересно можно ли это решение к фоксу прикрутить в виде addon или greacemonkey (или как оно правильно пишется)
  • 0
    Отлично, но осталось несколько проблем. Первая: в разметке большое количество дивов, которые портят семантику.

    <div class="blocker"> - ненужен:


    1. input полностью прозрачен, скрывать нечего
    2. div.blocker прозрачен тоже (там в бэкграунде transparent.gif)

    <div id="activeBrowseButton"> - лишняя сущность


    нужно просто добавлять класс .active к fakeButton, где спрайтами меняется фон.

    При таком бешенном пиаре (временно.нет тут, временно.нет там, открываешь архив с примером - там url-файл лежит, даже вконтакте - и там вступите в группу временно.нет... ) - таких ошибок быть недолжно, неважно генерится это в js или нет.
    • +1
      Вы теоретик? :)
      Даже у прозрачного input'a есть непрозрачный мигающий курсор в поле ввода.
      • 0
        нет я практик и всегда проверяю то что пишу, просто код оптимизировал сразу, чтоб там input обрезаелся wrapper'ом и в любом случае по нему нельзя кликнуть - не по чему, поэтому и не проверял такое.

        а за информацию - спасибо, интересный прикол)
    • 0
      activeBrowseButton нужет чтобы плавно можно было менять изображение: он появлялся при наведении(вначале оно было на jQuery с анимацией). А блокер, как уже сказали - нужен, чтобы не появлялся текстовый курсор при наведении.
      Вы с внимательностью отнеслись к статье - за это спасибо. Но вы не все заметили.
      В разметке, вообще говоря, не нужен враппер - его можно создать, и уже внутрь пихать все что нам надо. И это не все.
      Финальный код будет в пятничных сниппетах бешенно пиарящегося временно.нет =)
      И еще по поводу бешенного пиара - мы стараемся писать хорошие и интересные веб-разработчикам статьи. Пишем не для себя - поэтому и стараемся сообщить о себе как можно большему количеству людей.
      • 0
        статья действительно хорошая и что немаловажно своя, а не гугло-собрания из рубрики "28 способов сделать обтекание картинки текстом" :)
        молодцы.
        но вёрстка избыточна и весьма спорна.

        как бы я сделал вёрстку:
        #wrapper классом (т.к. их много по странице может быть)
        с {position: relative; _zoom: 1} чтобы держать элементы внутри
        с {overflow: hidden} чтобы левая часть input[file] (где путь к файлу и может быть курсор) невылезала из контейнера и немешалась.
        input[file] не нужен position: absolute и z-index, пусть просто стоит в потоке - оно спокойнее
        div.fakeButton ненужен float: left, всё равно всё тут абсолютно позицируется, зачем лишнее? а вот z-index: -1 и top и left по нулям обязательно.
        div#FileName - тоже классом и вместо margin'ов лучше задавать ему его родные top и left - надёжней и логичней.
        всё - blocker ненужен, а раз анимацию ценой jQuery не делаете (слава богу) то можно и спрайты использовать внутри одного блока fakeButton.

        За статью спасибо.
  • 0
    А вариант без blocker'a не подходит для кнопки?
  • 0
    Классная фишка! Спасибо, возьму на заметку )
  • 0
    Ещё "кликабельные области и их размеры" зависят от используемой темы Windows. Например, в классическом стиле размеры будут отличаться от стандартной темы XP или Vista Aero
  • 0
    К сожалению, не знаю, как это сделано в сафари. Но, имхо, неправильно определять тип файла по расширению.
  • 0
    Реальная штука, вообще пятерка, так держать;)
  • 0
    Невозможное — возможно.
    Впору писать кому-нибуть проект с названием «50 вещей, которые считаются невозможными»
  • 0
    Это просто мегакруто.
    Авторам увага =)
  • 0
    Спасибо.
    Все прекрасно работает
  • 0
    Товарищи, я одного понять не могу! А как на вКонтакте после того, как я выбираю файл показывается его размер!? сразу после выбора! не понимаю! как!?!?!?
    • 0
      SWFupload там... эх :)
  • –1
    жаль в ie5.5, ie8b1 не работает :(
  • 0
    А по мне, так легче под все браузеры подогнать, чем портить сайт JavaScript'om.
    Ну, не портить конечно, но минус в юзабилити если он отключен.
  • 0
    А автору все равно респект.
  • 0
    симпатично? возможно. интересно? несомненно.

    но я всё же не понимаю, зачем менять привычный пользователю интерфейс??? только для того чтобы угодить дизайнеру?
    • –1
      Ща любители рюшечек навставляют.
  • 0
    Мне почему-то кажется, что кастомизация форм - дело темное, и никому, кроме злоебучего дизайнера, не нужное.
    Потому что пользователь привык к тому, как выглядят формы. Пользователь привык к тому, как этими формами управлять с клавиатуры. Пользователь может отключить графику, и может отключить JS. Пользователь может зайти на сайт с PDA, и отключить на нем графику.

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

    Но стоит ли заниматься подобной хуйней, тратитя на ее доведение до ума недели, когда пользователям это не нужно?
    • +3
      об этом и речь... я аргументирую нежелание изменять глобально вид формы:
      1) пользователь привык за несколько лет уже к такому их виду
      2) более громоздкий код
      3) графика, которая может не загрузиться
      4) js, который по-моему мнению имеет другое назначение
      5) время уходящее на подгонку всего этого к нормальному виду во всех браузерах

      У дизайнера "аргумент" следующий:
      "Так круче", "мне так хочется", "я видел такое там-то..."
      • +1
        и кстати, кто-нибудь из утверждающих, что поле ввода не нужно и им никто не пользуется проводил какие-то исследования на эту тему или говорит опираясь на свой опыт? лично я пользуюсь полем ввода довольно часто: например в "админке" wordpress при загрузке нескольких файлов мне удобнее один раз нажав на кнопку выбрать файл, а затем просто скопировав путь к нему вставить его в остальные поля ввода, заменив только одну цифру (файлы предварительно пронумерованы). И считаю, что очень удобно, когда поле ввода большое и видно весь путь.

        вместе с тем, я согласен, что дизайн по-умолчанию не особо изящный и хотелось бы иметь больше возможностей изменять его (к примеру кнопку сделать более симпатичную, надпись поменять...) И без использования таких громоздких решений. По я против такого кардинального изменения как удаление поля вообще и считаю, что желание дизайнеров непременно сделать этот элемент "как в safari" как минимум необосновано.
        • 0
          Присоединяюсь к аргументам по поводу полного пути. Часто, имя файла, само по себе, ни о чем не говорит.
  • 0
    хороший пример, для меня был полезен момент с отображенем иконки загружаемого файла.
    в вашем методе есть недостаток - если увеличить или уменьшить размеры шрифта, пропорция кнопки инпута картинке-эмулятору будет нарушена, что вызывает "несоответсвующую кликабельность". я использую немного другой алгоритм: динамически перемещаю с помощью жабаскрипта файл-инпут под мишку пользователя в пределах картинки-эмулятора. Это позволяет использовать картинки-эмулятора любого размера и не зависит от шрифта пользователя.
    • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    > В Опере и IE мы можем написать адрес файла вручную (сомневаюсь, что кто-либо когда-либо пользовался этой возможностью).

    Не сомневайтесь, пользуюсь каждый день. ^C в ТоталКоммандере, ^V в браузере.
  • 0
    > В Опере и IE мы можем написать адрес файла вручную (сомневаюсь, что кто-либо когда-либо пользовался этой возможностью).

    Не сомневайтесь, пользуются. Очень удобно взять полное имя в ТоталКоммандере и выдавить его в браузере.
  • –1
    Есть одна проблема, которая, как мне кажется, не затронута в статье:

    Как будет работать данное решение, если загрузка происходит медленно (инпут размещен на реальном сайте, на "тяжелой странице").

    Решение дописывать JS по onload черевато тем, что пока onload не "выстрелил" пользователь будет видеть обычный инпут, который потом "мигнув" заменится на эту красоту.

    Чтобы избежать подобных метаморфоз (особенно это полезно когда кастомных контролов много на странице) и не обидеть пассажиров без JS (их кстати больше, чем вы думаете, смею заметить) я использую специальный файл стилей noscript.css где все "навороты" прячутся от несчастного без-JSника.

    Подключаю его внутри head:

    Насколько мне известно, это невалидное решение, но во всех целевых браузерах (в ИЕ6 тоже) работает без помех.
  • 0
    Немножко багов:

    1) Максимально допустимое имя файла в виндах невозможно выбрать этим контролом ("Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копия Копlemon.jpeg")

    2) Если имя укоротить, но оставить длинным, то оно отобразится рядом с инпутом в 2-3 строки и из-за этого фоновая картинка с пиктограммой становится двойной или тройной пиктограммой. Т.е. идею с одной пиктограммой надо откалибровать или перейти к отдельным пиктограммам.

    (Сижу в ИЕ6 под XP)
  • 0
    Одно хочу добавить, в сафари под Mac Os X вот на такое поле с инпутом файл можно просто перетащить. Именно этого не хватает мне в виндовсе. А квадратная кнопка или круглая по большому счету неважно.
    • 0
      В сафари под виндой это тоже возможно. Но этот вопрос уже к производителям браузеров.
  • 0
    Клевая статья! Спасибо!
  • 0
    спасибо, теперь все кнопки одного вида в проекте 8)
  • 0
    Да, элегантное решение. Мне понравилось. Воспользуюсь обязательно.
  • 0
    классная статья, вот только у меня в опере 9.52 под убунтой не работает.
    В фоксе под убунтой же все нормально.
    • НЛО прилетело и опубликовало эту надпись здесь
  • +1
    Оригинальный пост и архив с кодом переместились.
    • 0
      Спасибо, поправил.
  • 0
    хорошая идея, но нужны фиксы ещё для Opera 7.x, 8.x

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