Sysnet 웹 사이트의 HTML5 변환 기록
와~~~ 예전에 XHTML 표준화 작업 이후 두 번째로 HTML5 표준화 작업을 해보는군요. ^^
XHTML or HTML 4.01 표준 준수
; https://www.sysnet.pe.kr/2/0/199
방문하시는 여러분들도 언제든지 쉽게 SYSNET 웹 사이트의 HTML5 표준 현황을 확인할 수 있는데요, 웹 페이지의 왼쪽 하단에 있는 "W3C" 이미지를 클릭하면 현재 보고 있는 웹 페이지에 대한 HTML5 표준 상황을 볼 수 있습니다.
이쯤에서 미리 언급을 해야겠는데, 아쉽게도 현재 모든 페이지에서 아래의 메타태그 때문에 기본적으로 1개의 오류를 발생시키고 있습니다.
<meta http-equiv="X-UA-Compatible" content="IE=9" />
이걸 빼는 경우 가끔씩 IE 9에서 Document Mode가 "Internet Explorer 7 standards"로 인식되어 UI가 깨지는 현상이 나와서 부득이 그대로 사용하기로 결정했습니다.
한 가지 더 문제가 있다면, 제가 지금까지 HTML5 표준을 염두에 두지 않고 써 온 수많은 게시물들이 있습니다. 글이 너무나 많기 때문에 수작업으로는 도저히 맞출 수 없고, 자동화 작업도 시간 관계상 포기하고 ^^; 최근 2011년 6월 8일부터 씌여진 게시물들에 대해서만 HTML5에 맞게 작성하고 있습니다.
그런데, 여기서도 문제가 하나 있습니다. 바로 W3C의 Validator가 다음과 같은 오류를 생성한다는 것인데요.
Line 614, Column 4: No p element in scope but a p end tag seen.</p>
</p>
아쉽게도, 위의 보고와는 달리 p 태그는 정확히 쌍을 맞춰서 생성하고 있는데, 아마도 Validator 자체의 오류인 것 같습니다. (W3C Validator의 버그가 생각 외로 많은데, 이 글의 하단에 몇 가지 사례를 다뤘습니다.)
결과적으로 볼 때, 이 정도면 기본적인 태그 수준의 HTML5 표준을 지켰다고 할 수 있을 것 같습니다. ^^
참고로, 제 웹 사이트는 ASP.NET 웹 폼으로 만들어진 것으로 HTML5 표준을 맞추기 위해서 제법 해주어야 할 것이 많았는데, 그에 대한 기록을 이 글에 남겨봅니다.
The cellpadding attribute on the table element is obsolete. Use CSS instead.
The cellspacing attribute on the table element is obsolete. Use CSS instead.
The width attribute on the table element is obsolete. Use CSS instead.
위의 오류가 발생한 구문은 다음과 같습니다.
<table cellpadding="0" cellspacing="0" width="100%">
3가지 속성값을 모두 CSS로 옮기라는 것인데, 다들 아시겠지만 cellpadding/cellspacing은 CSS에 동일한 이름의 속성이 없습니다. 그래도 ^^ 검색을 해보니 답이 나오는군요.
In HTML5, with respect to tables, what replaces cellpadding, cellspacing, valign, and align?
; http://stackoverflow.com/questions/6048913/in-html5-with-respect-to-tables-what-replaces-cellpadding-cellspacing-valign
그래서, 제 경우에는 다음과 같이 CSS를 넣어두고 HTML table을 정의했습니다.
table.nomargin
{
border-spacing: 0;
width: 100%;
}
table.nomargin td
{
padding: 0;
}
HTML 코드는 다음과 같이 정의하는 것으로 해결!
<table class="nomargin">
The valign attribute on the tr element is obsolete. Use CSS instead.
The valign attribute on the td element is obsolete. Use CSS instead.
원인이 되는 태그는 다음과 같습니다.
<tr valign="top">
<td valign="top">
제 경우에는, TR 태그의 valign 속성의 경우 그에 상관없이 HTML 웹 페이지 외관이 변화가 없었으므로 그냥 모두 삭제를 해버렸습니다.
하지만, TR 태그와는 달리 TD 태그의 valign을 빼면 웹 페이지의 외관이 바뀌는 차이가 있어서 제거할 수는 없었습니다. 그래서, CSS 파일에 vertical-align을 정의하고,
td.topAlign
{
vertical-align: top;
}
HTML에서는 클래스를 지정하는 것으로 완료.
<td class="topAlign">
align attribute on the td element is obsolete. Use CSS instead.
valign과는 달리 align의 경우에는 CSS에 horizontal-align 값이 없더군요. 검색을 해봐도 이에 대해 딱히 설명해 둔 자료도 없고 해서, 일단 비슷한 값을 찾기 위해 뒤적거리다가 의미는 다소 제한적이지만 "text-align" 값으로 대체를 해보았는데 정상적으로 적용이 되었습니다.
td.leftAlign
{
text-align: left;
}
hr
{
text-align: left;
}
HR 태그의 경우에도 잘 적용되는 것을 보면 어느 정도는 'text'라는 의미를 'content' 정도로 이해해도 무방할 것 같습니다.
An img element must have an alt attribute, except under certain conditions. For details, consult guidance on providing text alternatives for images.
IMG 태그에 alt 속성을 통해서 의미 있는 문장을 부여하지 않았다는 것인데요. 사실, 부여하면 그만이지만 웹 페이지를 만들다 보면 별로 사용자가 알 필요가 없는 그림들이 사용되는 경우도 많습니다.
예를 들어, 제 경우에 위의 오류가 발생한 경우는 다음과 같은 태그 사용이었는데요.
<td><img src="/SysWebRes/theme/toolbar_split.png" /></td>
생각해 보니까, 위와 같은 경우는 굳이 img 태그를 둘 필요 없이 td의 background-image로 처리해도 무방하기 때문에 다음과 같이 통합할 수 있었습니다.
<td style="background-image:url(/SysWebRes/theme/toolbar_split.png);"></td>
만약, 이처럼 통합이 안되는 경우라면, alt 속성을 정의하되 그냥 공백으로 놓아도 오류가 발생되지 않습니다. (이렇게 되면, 표준을 위한 끼워맞추기식 작업이 발생하는 건데 바람직하지는 않은 것 같습니다.)
td><img alt="" src="/SysWebRes/theme/toolbar_split.png" /></td>
Table column 2 established by element td has no cells beginning in it.
이것은 HTML5 오류라기보다는, '정합성 오류'에 가깝습니다. 즉, 해당 테이블에 colspan=2 속성을 주어야 할 아무런 이유가 없는 경우이므로 colspan=2를 삭제해 주면 됩니다. 예를 들어, 다음과 같은 테이블 정의에서 이런 오류가 발생합니다.
<table>
<tr>
<td colspan="2"></td> // colspan="2" 가 필요 없으므로 삭제해야 함
</tr>
</table>
End tag br.
"End tag" 유의 오류가 나는 경우는, start/end가 하나의 태그로 정의된 것을 굳이 분리한 경우에 발생합니다. 예를 들어, <br /> 정의를 <br></br>로 하는 경우입니다.
잠깐 여기서 ASP.NET 서버 측의 HtmlGenericControl을 언급할 필요가 있는데요. HtmlGenericControl 클래스가 생성하는 HTML 텍스트는 반드시 start/end 태그 쌍으로 이뤄집니다.
new HtmlGenericControl("hr");
==> <hr></hr>
이 문제를 방지하려면 HtmlGenericControl 개체 사용을 LiteralControl로 대체하면 됩니다.
new LiteralControl("<hr />");
==> <hr />
Stray end tag img.
Stray end tag input.
위에서 살펴본 "End tag br." 오류와 동일한 사례인데, 이 경우에는 img(또는 input) 태그를 다음과 같이 start/end로 분리했기 때문에 발생합니다.
<img ...></img>
==> <img ... />
<input ...></input>
==> <input ... />
& did not start a character reference. (& probably should have been escaped as &.)
바로 이 오류가, 그동안 제가 써온 게시물에서 내부적으로 인용한 숱한 외부 웹 사이트들에 대한 링크에서 발견되고 있어 HTML5 표준 검사를 통과하지 못하도록 한 주범입니다. 다행이라면, 보통 HTML로 출력된 a 태그의 href 속성에 "&" 문자가 들어있을 때 발생하기 때문에 해결책도 간단하다는 것입니다.
<a href="http://localhost/test.aspx?mode=1&sub=2">...</a>
==> <a href="http://localhost/test.aspx?mode=1&sub=2">...</a>
참고로, ASP.NET 서버 측에서 'URL'을 입력하는 구문이 있다면, HtmlEncode 함수를 사용해 주시면 정상적인 인코딩 문자열을 얻을 수 있습니다.
_w3c_link.HRef = HttpUtility.HtmlEncode("http://localhost/test.aspx?mode=1&sub=2");
기타 1. - 너무 많은 class 정의에 시달려야 할까요?
가령 웹 페이지에 아래와 같이 정의된 경우를 볼 수 있습니다.
<span width="100" align="left" height="150">
...
</span>
<span width="200" align="right" height="250">
...
</span>
위의 html을 정리하기 위해 class로 정의한다면 다음과 같이 처리할 수 있습니다.
<style>
span.type1
{
width: 100;
text-align: left;
height: 150;
}
span.type2
{
width: 200;
text-align: right;
height: 250;
}
</style>
하지만, 이런 것이 늘어난다고 생각해 보면, 분명 독립된 .css 파일에서 관리하는 것이 만만치 않음을 알 수 있습니다. 결국, 늘어난 class들로 인해 나중에는 엄청난 스타일 구문에 허우적 댈 텐데요. 자신의 상황에 맞게 잘 정리를 하셔야 합니다.
가령, 너무 특수한 페이지에만 국한된 css라면 별도의 css 파일로 분리하기보다는 웹 페이지에 inline style 구문으로 정의하는 것도 좋은 선택입니다.
아니면, 다음과 같이 style을 세세하게 분리하는 방법도 있습니다.
<style>
.leftAlign
{
text-align: left;
}
.rightAlign
{
text-align: right;
}
.width100
{
width: 100;
}
.width200
{
width: 200;
}
.height150
{
height: 150;
}
.height250
{
height: 250;
}
</style>
그러면 개별 경우에 한해 조합 가능한 class 적용을 할 수 있습니다.
<span class="width100 leftAlign height150">
...
</span>
<span class="width200 rightAlign height250">
...
</span>
또는, 너무 가변적인 것들은 굳이 css로 빼지 말고 다음과 같이 태그 자체의 style 속성값으로 정의하시면 됩니다.
<span style="width: 100; align: left; height: 150">
...
</span>
<span style="width: 200; align: right; height: 250">
...
</span>
기타 2. - ASP.NET 서버 측 컨트롤 사용하는 경우
그 외에, ASP.NET 서버 컨트롤을 사용하는 경우 코드를 수정해야 하는 문제가 있습니다.
예를 들어, 아래와 같이 runat='server'로 정의된 table 요소의 width를 실행 시에만 결정할 수 있다고 가정하면,
<table runat="server" id="menuTable" class="nomargin">
기존에는 다음과 같이 코딩해도 무방했는데요.
menuTable.Width = (count * 100).ToString();
HTML5에는 table에 width 속성값이 정의되어 있지 않으므로 넣을 수가 없습니다. 게다가 실행 시에 정의되는 특이함으로 인해 정적인 CSS 파일에 정의해 두는 것도 불가능합니다. 이런 경우는, style 속성으로 출력될 수 있도록 다음과 같이 변경되어야 합니다.
menuTable.Style.Add("width", (topList.Count * 100).ToString() + "px");
기타 3. - ASP.NET DataGrid의 비표준 속성
HTML5 표준을 지키기 위해 가장 난감한 컨트롤이 바로 DataGrid입니다. 원치 않는 속성값 4개(cellspacing, cellpadding, rules, border)를 table 태그에 '무조건' 쓰기 때문입니다.
다행이라면, 그중의 3가지 속성을 지우는 방법이 다음의 글에서 나옵니다.
The Case of The Polluting GridView
; http://knitinr.blogspot.com/2009/03/case-of-polluting-gridview.html
그래서, 각각 다음과 같은 처리를 해줄 수 있습니다.
'rules' 제거
==> GridLines="None"
'cellspacing' 제거
==> CellSpacing="-1"
'cellpadding' 제거
==> CellPadding="-1"
문제는 border 속성인데, 일단 제가 아는 방법에서는 '우아하게' 제거하는 방법이 없습니다. 굳이 해야 한다면, 아래의 코드에서처럼 ASP.NET 서버 컨트롤을 상속받아서 Render 메서드를 재정의하는 방법을 사용해야 합니다.
===== 코드 =====
public class Html5DataGrid : DataGrid
{
protected override void Render(HtmlTextWriter writer)
{
StringWriter sw = new StringWriter(CultureInfo.CurrentUICulture);
HtmlTextWriter htmlWriter = new HtmlTextWriter(sw);
base.Render(htmlWriter);
// DataGrid가 생성한 HTML 텍스트를 구하고,
string text = htmlWriter.InnerWriter.ToString();
// 이후 text에 조작을 가하고,
text = text.Replace("border=\"0\" ", string.Empty);
// 변경된 HTML 텍스트를 최종적으로 쓴다.
writer.Write(text);
}
}
===== ASPX 웹 페이지 =====
<%@ Register Assembly="MyAssembly.WebControls" Namespace="MyAssembly.WebControls" TagPrefix="ExtControl" %>
<ExtControl:Html5DataGrid GridLines="None" ...>...</ExtControl:Html5DataGrid>
참고로, 제가 SYSNET 웹 사이트에서 사용하는 DataGrid는 2군데가 있습니다. 게시물 목록과 댓글 목록인데, 그중에서 게시물 목록의 DataGrid는 완전히 제거하고 HTML 태그를 직접 쓰는 것으로 교체했습니다. (간결해진 ViewState를 보니 속이 다 시원하군요. ^^)
기타 4. - W3C의 Markup Validation Service 자체에 오류가 있는 경우
재미있는 경우인데요. HTML5 표준을 검사하는 도구 자체에 오류가 있었습니다. 예를 들어, 제가 span 태그를 다음과 같이 사용하고 있는데,
<span id="lbl_TodayWritten" style="color:#C00000;">0</span>
이에 대해, "Markup Validation Service" 도구는 다음과 같이 오류를 발생시켰습니다.
“
Line 318, Column 73: The font element is obsolete. Use CSS instead.
… <span id="lbl_TodayWritten"><font color="#C00000">0</font></span>
“
style의 color 사용을 font 태그로 스스로 치환해서 오류를 만들어 버린 것입니다. 매우 애매해지는 경우인데요. 그냥 두자니 껄끄럽고, 변경하자니 억울하고. ^^
어쨌든, 저는 다음과 같이 css로 그냥 빼버리는 쪽을 선택했습니다.
.mycolor
{
color: #c00000;
}
<span id='...' class='mycolor' />
기타 5. - <asp:ImageButton /> 서버 컨트롤의 border-width 출력과 "Markup Validation Service" 자체 오류가 합쳐진 경우
System.Web.UI.WebControls.ImageButton 타입은 무조건 기본값으로 다음과 같이 style에 border-width 속성을 출력해 줍니다.
<img src="..." style="border-width:0px;" />
그런데 이것 역시 "Markup Validation Service" 도구가 스스로 오류를 내는데, 엉뚱하게 border 속성이 설정된 것으로 잘못 판단하기 때문입니다.
Line 343, Column 162: Attribute border not allowed on element input at this point.
…h" border="0" />
참고로, ImageUrl 속성을 지정한 System.Web.UI.WebControls.HyperLink의 경우에도 위와 동일한 문제가 발생합니다.
해결 방법은? 각각의 기능과 유사한 일반 HTML 태그를 정의하고 runat='server'로 변경하시면 됩니다.
<asp:ImageButton ID="_imgBtnDelete" OnClick="_imgBtnDelete_Click"
runat="server" ImageUrl="/SysWebRes/sysimg/btn_bbs_delete.gif"> </asp:ImageButton>
==> <input type="image" runat="server" OnServerClick="btnDelete_Click" src="....gif" />
<asp:HyperLink ID="_hlinkEdit" runat="server" BorderWidth="0" Width="63"
ImageUrl="/SysWebRes/sysimg/btn_bbs_modify.gif"></asp:HyperLink>
==> <a id="_hlinkEdit" runat="server">
<img class="noborder" src="....gif" />
</a>
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]