이 장은 디자인에만 집중하여, html form의 구조에 대해서는 신경쓰지 않겠습니다.
역사적인 문제로 인해, form styling은 쉽게 커스터마이징할 수 있는 것들도 있고, 건드리기 어렵거나 거의 손을 댈 수 없는 것들도 있습니다.
1) good
2) bad
3) ugly -> 매우 적용이 안되는 문제로 js와 함께 해야하므로 js부분 나갈 때 정리하겠음.
폼을 꾸미기 전에 기본적으로 알아두어야 할 공통적인 부분들을 먼저 보겠습니다.
브라우저 중에 부모의 글꼴과 크기를 상속받지 않게 구현되는 경우가 있습니다. 따라서 모든 브라우저에서 동일하게 동작하도록 명시적으로 reset.css에 아래 속성을 표시합니다. 이렇게 함에도 불구하고 bad, ugly 쪽에 속하는 input들은 적용 안되는 모습도 보입니다.
button, input, select, textarea {
font-family: inherit;
font-size: 100%;
}
각각의 폼은 종류 별로 고유의 크기를 가지고 있고, 표현 방법도 브라우저마다 천차만별입니다. 크로스 브라우징을 위해 이들의 기본 스타일을 없애줍니다.
button, input, select, textarea {
width : 100%;
padding: 0;
margin: 0;
border: 0;
border-radius: 0;
box-sizing: border-box;
background: transparent;
-webkit-appearance: none;
appearance: none;
}
폼을 그룹핑하는 데 쓰이는 요소들에 대한 디자인을 잡아보겠습니다.
우선, 그룹핑하는 요소는 form, fieldset, legend가 있습니다. 이들의 기본 스타일링을 제거하고, legend는 위치를 지정할 때 positioning으로만 움직이므로 기본 세팅을 해줍니다.
fieldset의 legend는 label의 보조기술이므로 라디오 버튼에 함께사용하면 좋습니다.
fieldset,
legend {
padding: 0;
margin: 0;
border: none;
}
fieldset { position: relative; }
legend { position: absolute; top: 0; left: 0; }
대부분 폼 아이템이 여러 개 있으면 동일한 간격으로 띄워주는 등 동일한 디자인이 적용됩니다.
이에 맞춰 item wrapper들에게 공통적인 디자인을 줍니다.
<form action="" data-type="form/inlineAlign">
<div data-itemWrapper>
<input type="radio" name="coffee" id="americano" />
<label for="americano">아메리카노</label>
</div>
<div data-itemWrapper>
<input type="radio" name="coffee" id="moca" />
<label for="moca">모카</label>
</div>
<div data-itemWrapper>
<input type="radio" name="coffee" id="cappuccino" />
<label for="cappuccino">카푸치노</label>
</div>
<div data-itemWrapper>
<input type="radio" name="coffee" id="latte" />
<label for="latte">라떼</label>
</div>
</form>
[data-type^="form/inlineAlign"] [data-itemWrapper] {
display: inline-flex;
margin-right: 1em;
}
textarea는 유저가 크기를 맘대로 조정할 수 있는 것이 기본 값입니다. 보통 디자인은 그대로 있기를 바라므로 조정할 수 없게 설정하겠습니다. 또, 브라우저 중에 textarea의 overflow 기본 값이 scroll로 되어 있어 처음부터 스크롤바가 보이기 때문에 통일시키겠습니다.
또 기본적으로 textarea는 2줄 이상 사용될 때 원할 것이기 때문에 height을 임의의 값으로 정해놓겠습니다. html에서 row,col 설정 대신 css로 크기를 정해주시고, 프로젝트마다 적당한 크기로 정하셔서 사용하시면 됩니다.
textarea {
overflow: auto;
resize: none;
height: 3.0em;
}
appearance:none을 지원하는 브라우저인 경우, 아래와 같이 매우 간단하고 실용적으로 작업할 수 있습니다.
appearance:none으로 모양이 전부 지워지므로 새로 디자인을 할 수 있기 때문입니다. 그러나...우리의 IE는 appearance를 지원하지 않습니다..하..
input[type="checkbox"] {
-webkit-appearance: none;
appearance: none;
position: relative;
width: 1em;
height: 1em;
border: 1px solid gray;
/* Adjusts the position of the checkboxes on the text baseline */
vertical-align: -2px;
/* Set here so that Windows' High-Contrast Mode can override */
color: green;
}
input[type="checkbox"]::before {
content: "✔";
position: absolute;
font-size: 1.2em;
right: -1px;
top: -0.3em;
visibility: hidden;
}
input[type="checkbox"]:checked::before {
/* Use `visibility` instead of `display` to avoid recalculating layout */
visibility: visible;
}
input[type="checkbox"]:disabled {
border-color: black;
background: #ddd;
color: gray;
}
자.. IE를 지원하기 위해서 더 먼 길을 돌아봅시다..
input[type="radio"] {
overflow: hidden;
position: absolute;
left: -10000px;
clip: rect(1, 1, 1, 1);
width: 1px;
height: 1px;
border: 0;
}
input[type="radio"] + label {
position: relative;
cursor: pointer;
padding-left: 1.5em;
}
input[type="radio"] + label::before {
position: absolute;
top: 0;
left: 0;
content: "";
display: block;
width: 1em;
height: 1em;
border: 1px solid gray;
}
input[type="radio"]:disabled + label::before {
background: #ddd;
}
input[type="radio"] + label::after {
content: "✔";
position: absolute;
font-size: 1.2em;
left: 0em;
top: -0.1em;
color: green;
visibility: hidden;
}
input[type="radio"]:checked + label::after {
visibility: visible;
}
마우스 포인터를 엘리먼트 위에 올려놓았을 때
키보드 접근성을 위해서 포커스 스타일링은 필요한 부분입니다. 보통 포커스할 때 설정되어 있는 outline을 없애고, 원하는 디자인을 입힙니다.
button:focus,
input:focus,
select:focus,
textarea:focus {
border: 1px solid orange;
}
해당 엘리먼트를 클릭하거나 엔터 키를 칠 때
필수요소이거나 아닐 때
form의 validation에 유효하거나 유효하지 않거나.
html 속성에 disabled가 있는가 없는가 / html 속성에 readonly가 있는가 없는가.
체크박스/라디오박스 체크 혹은 옵션이 선택되었는가 아닌가 / 로드될 때부터 원래 선택되어 있던 것