이콜레모 개발자 위키

Page history of 파일 업로드 버튼 CSS로 꾸미기



Title: 파일 업로드 버튼 CSS로 꾸미기 | edited by Youngrok Pak at 10 years, 6 months ago.

<h2>The Problem</h2>
<p>HTML 폼에서 파일 업로드 버튼만큼은 CSS로 꾸밀 수가 없다. 꾸밀 수 없는 이유는 보안 때문이다. 업로드 버튼을 여러 가지 스타일로 바꿀 수 있게 되면 이걸 이용해서 사용자 PC의 파일을 업로드하게 하는 일종의 피싱을 할 수 있기 때문이다. 그래서, 가급적이면 업로드 버튼은 바꾸지 않는 것이 좋다.</p>
<p>&nbsp;</p>
<p>그렇지만, 현실적으로 이걸 건드려야 하는 이유가 여러 가지로 존재한다. 디자이너들이 업로드 버튼을 이쁘게 꾸미고 싶어하는 것을 굳이 나무랄 이유는 없다. 파일을 업로드하는 버튼임을 사용자에게 확실히 알려주고 있다면 바꿔도 무방하다.</p>
<p>&nbsp;</p>
<h2>The Answer</h2>
<h3>opacity 이용</h3>
<p>CSS 로 파일 업로드 버튼을 바꿀 수 없으니 버튼을 숨기고 다른 태그로 그 위를 덮으면 된다. 아쉽게도 display: hidden, visibility: hidden은 뜻대로 안된다. 아예 화면에 표시하지 않기 때문에 클릭해도 업로드 버튼이 동작하지 않는다. 그래서 불투명도를 0으로 만드는 것이다.</p>
<ol class="code">
<li>filter:alpha(opacity=0) /* IE */</li>
<li>opacity:0 /* <a class="wiki" title="표준 호환 브라우저" href="http://ecolemo.springnote.com/pages/4051739">표준 호환 브라우저</a> */</li>
</ol>
<p>&nbsp;</p>
<p>이렇게 하면 파일 업로드 버튼은 안 보이지만 클릭은 가능하게 된다. 그 아래에 다른 태그로 버튼 모양만 그려놓으면 된다.</p>
<p>&nbsp;</p>
<p>그런데, 여기서 문제가 하나 더 있다. 그려놓은 버튼과 뒤에 있는 파일 업로드 버튼의 영역이 일치하지 않는다는 것이다. opacity 없이 다음과 같은 코드를 띄워보자.</p>
<ol class="code">
<li>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;input style="position: absolute; width: 100px; height: 50px;" type="file"/&gt;<br> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;button style="height: 50px;"&gt;바뀐 업로드 버튼&lt;/button&gt;</li>
</ol>
<p>그럼 아래처럼 나온다.</p>
<p><img class="attachment" title="upload_not_match_button.gif" src="http://ecolemo.springnote.com/pages/4214453/attachments/2137197" alt="upload_not_match_button.gif"></p>
<p>그러면 input을 가려도 영역이 달라서 안된다. 여기서 또 하나의 문제가 업로드 input의 텍스트필드와 버튼을 따로 컨트롤할 수 없다는 것이다. width, height를 줘 보자.</p>
<ol class="code">
<li>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;input style="position: absolute; width: 120px; height: 50px;" type="file"/&gt;<br> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;button style="height: 50px;"&gt;바뀐 업로드 버튼&lt;/button&gt;</li>
</ol>
<p><img class="attachment" title="upload_same_height.gif" src="http://ecolemo.springnote.com/pages/4214453/attachments/2137209" alt="upload_same_height.gif"></p>
<p>다행히 height는 맞춰지지만 width는 안 먹는다. 파이어버그로 보면 영역은 반영이 되었는데 보이기는 다 보인다. 그런데, 먹히는 CSS가 있다. font-size.</p>
<ol class="code">
<li>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;input style="position: absolute; width: 120px; height: 50px; font-size: 22px;" type="file"/&gt;<br> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;button style="height: 50px;"&gt;바뀐 업로드 버튼&lt;/button&gt;</li>
</ol>
<p><img class="attachment" title="upload_same_button.gif" src="http://ecolemo.springnote.com/pages/4214453/attachments/2137217" alt="upload_same_button.gif"></p>
<p>이제 텍스트필드만 잘 가리면 되겠다. 텍스트필드를 가리는 방법은 간단치는 않다. 일단 CSS로는 조정이 안되고 input의 size 속성을 이용한다.</p>
<ol class="code">
<li>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;input style="position: absolute; width: 120px; height: 50px; font-size: 22px; " type="file" size="1"/&gt;<br> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;button style="height: 50px;"&gt;바뀐 업로드 버튼&lt;/button&gt;</li>
</ol>
<p><img class="attachment" title="upload_small_textfield.gif" src="http://ecolemo.springnote.com/pages/4214453/attachments/2137223" alt="upload_small_textfield.gif"></p>
<p>이제 최소화된 크기만큼 왼쪽으로 쉬프트를 시키자.</p>
<ol class="code">
<li>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;input style="position: absolute; width: 120px; height: 50px; font-size: 22px; margin-left: -34px;" type="file" size="1"/&gt;<br> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;button style="height: 50px;"&gt;바뀐 업로드 버튼&lt;/button&gt;</li>
</ol>
<p><img class="attachment" title="upload_shifted.gif" src="http://ecolemo.springnote.com/pages/4214453/attachments/2137227" alt="upload_shifted.gif"></p>
<p>텍스트 필드 부분이 좀 남는데 이건 div를 그 자리에 엎어서 가린다.</p>
<ol class="code">
<li>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;div style="position:absolute; width:60px; height: 50px; z-index: 3; margin-left: -60px; background-color: white;"&gt;&lt;/div&gt;<br> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;input style="position: absolute; width: 120px; height: 50px; font-size: 22px; margin-left: -34px;" type="file" size="1"/&gt;<br> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;button style="height: 50px;"&gt;바뀐 업로드 버튼&lt;/button&gt;</li>
</ol>
<p><img class="attachment" title="upload_opacity.gif" src="http://ecolemo.springnote.com/pages/4214453/attachments/2137237" alt="upload_opacity.gif"></p>
<p>가리는 건 디자인에 따라 overflow: hidden을 이용할 수 있는 경우도 있고 다양한 방법들이 있을 것이다. 마지막으로 opacity를 0으로 만들어준다.</p>
<ol class="code">
<li>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;div style="position:absolute; width:60px; height: 50px; z-index: 3; margin-left: -60px; background-color: white;"&gt;&lt;/div&gt;<br> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;input style="position: absolute; width: 120px; height: 50px; font-size: 22px; margin-left: -34px; opacity: 0" type="file" size="1"/&gt;<br> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;button style="height: 50px;"&gt;바뀐 업로드 버튼&lt;/button&gt;</li>
</ol>
<p><img class="attachment" title="upload_complete.gif" src="http://ecolemo.springnote.com/pages/4214453/attachments/2137239" alt="upload_complete.gif"></p>
<p>여기에 cursor, hover 등을 이용해서 반응성을 좀 넣어주면 된다. IE에서도 거의 동일하게 동작한다.</p>
<h3>iframe 이용</h3>
<p>opacity 를 이용한 방법은 사실 논리적인 문제점이 하나 있다.&nbsp;업로드하는 파일명이 사용자에게 보이지 않는다는 것이다. 그래서 정상적으로 form을 submit하는 경우라면 이 방법을 적용하면 나쁜 설계가 된다. 버튼은 어떻게 바꾸더라도 텍스트필드에 파일명을 보여줘야 접근성을 확보할 수 있다. 그렇다면 이 방법을 써도 되는 건 언제일까? 버튼을 눌러서 파일을 선택하면 submit하지 않고 바로 업로드가 되며, 현재 페이지는 바뀌지 않는, Ajax스러운 업로드를 할 때는 자연스러운 UX다. 오히려 이 경우는 텍스트필드를 안 보여주는 게 더 자연스럽다. 그런데, 위의 방법을 그대로 적용하면 Ajax스러운 업로드가 어렵다. 스크립트로 동적인 iframe을 생성하고 그 안에 폼을 만들어서 submit까지 해야 한다. 그럴 바에야 처음부터 iframe으로 버튼을 넣을 수 있다면 어떨까.</p>
<p>&nbsp;</p>
<p>버튼을 꾸미는 방법은 위와 같은데, 요는 텍스트필드를 div로 가리지 않고 iframe 안에 업로드버튼을 넣어서 가리는 것이다. 나머지는 똑같다. 그리고 iframe 안에 form을 넣고 input에 onchange="this.form.submit()" 등을 달아서 파일을 선택하면 바로 submit되게 하는 것이다. 그리고 그 결과를 parent에서 받아서 처리한다. 이렇게 하면 별도의 팝업이 뜨거나, 화면이 전환되지 않으면서 파일을 업로드하는 것이 가능하다. 사실은 위의 방법을 이 방법과 결합해서 써야 완전한 UX가 달성되는 것이다.</p>
<p>&nbsp;</p>
<p>물론, 스크립트로 다 짜서 submit하는 것도 UX 상으로는 문제 없다. 다만 미리 넣어 놓는 방식이 디자인 맞추기가 편할 것이다.</p>
<h3>swfupload</h3>
<p>사실 UX 상으로 현재까지 알려진 방식 중 최고의 방법은 위의 방법들이 아니라 플래시를 쓰는 것이다. <a class="external" title="http://swfupload.org/" href="http://swfupload.org/">swfupload</a>가 괜찮은 듯 하다.</p>
<p>&nbsp;</p>
<p>이 방식은 두 가지 장점이 있다. 하나는 업로드 진행율을 보여줄 수가 있다는 점. 큰 파일을 업로드할 때는 막강한 장점이다. 또 하나는, 한 번에 여러 파일을 업로드할 수 있다는 것. 자주 필요한 기능은 아니지만 역시 아주 막강한 장점이다. 플래시의 보급률이 95%에 달한다는 점을 감안하면 괜찮은 방법이다. 물론, 버튼도 마음대로 꾸밀 수 있다.</p>
Wiki at WikiNamu