Microsoft MVP성태의 닷넷 이야기
웹: 20. Sysnet 웹 사이트의 HTML5 변환 기록 [링크 복사], [링크+제목 복사],
조회: 29136
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 2개 있습니다.)

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 &amp;.)



바로 이 오류가, 그동안 제가 써온 게시물에서 내부적으로 인용한 숱한 외부 웹 사이트들에 대한 링크에서 발견되고 있어 HTML5 표준 검사를 통과하지 못하도록 한 주범입니다. 다행이라면, 보통 HTML로 출력된 a 태그의 href 속성에 "&" 문자가 들어있을 때 발생하기 때문에 해결책도 간단하다는 것입니다.

<a href="http://localhost/test.aspx?mode=1&sub=2">...</a>
==> <a href="http://localhost/test.aspx?mode=1&amp;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>






[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/9/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2011-07-08 11시16분
위의 내용에서 "기타" 항목의 "4번", "5번"은 browser 정의 파일로 해결할 수 있습니다.

Sysnet 웹 사이트의 HTML5 변환 기록 - 두 번째 이야기
; http://www.sysnet.pe.kr/2/0/1080
정성태

... 16  17  18  19  20  21  22  23  24  25  26  27  [28]  29  30  ...
NoWriterDateCnt.TitleFile(s)
13237정성태1/30/202314317.NET Framework: 2091. C# - 웹 사이트가 어떤 버전의 TLS/SSL을 지원하는지 확인하는 방법
13236정성태1/29/202313086개발 환경 구성: 663. openssl을 이용해 인트라넷 IIS 사이트의 SSL 인증서 생성
13235정성태1/29/202312566개발 환경 구성: 662. openssl - 윈도우 환경의 명령행에서 SAN 적용하는 방법
13234정성태1/28/202314981개발 환경 구성: 661. dnSpy를 이용해 소스 코드가 없는 .NET 어셈블리의 코드를 변경하는 방법 [1]
13233정성태1/28/202316147오류 유형: 840. C# - WebClient로 https 호출 시 "The request was aborted: Could not create SSL/TLS secure channel" 예외 발생
13232정성태1/27/202312062스크립트: 43. uwsgi의 --processes와 --threads 옵션
13231정성태1/27/202311288오류 유형: 839. python - TypeError: '...' object is not callable
13230정성태1/26/202312044개발 환경 구성: 660. WSL 2 내부로부터 호스트 측의 네트워크로 UDP 데이터가 1개의 패킷으로만 제한되는 문제
13229정성태1/25/202313930.NET Framework: 2090. C# - UDP Datagram의 최대 크기
13228정성태1/24/202314477.NET Framework: 2089. C# - WMI 논리 디스크가 속한 물리 디스크의 정보를 얻는 방법 [2]파일 다운로드1
13227정성태1/23/202313389개발 환경 구성: 659. Windows - IP MTU 값을 바꿀 수 있을까요? [1]
13226정성태1/23/202312334.NET Framework: 2088. .NET 5부터 지원하는 GetRawSocketOption 사용 시 주의할 점
13225정성태1/21/202311681개발 환경 구성: 658. Windows에서 실행 중인 소켓 서버를 다른 PC 또는 WSL에서 접속할 수 없는 경우
13224정성태1/21/202312172Windows: 221. Windows - Private/Public/Domain이 아닌 네트워크 어댑터 단위로 방화벽을 on/off하는 방법
13223정성태1/20/202312078오류 유형: 838. RDP 연결 오류 - The two computers couldn't connect in the amount of time allotted
13222정성태1/20/202311950개발 환경 구성: 657. WSL - DockerDesktop.vhdx 파일 위치를 옮기는 방법
13221정성태1/19/202312146Linux: 57. C# - 리눅스 프로세스 메모리 정보파일 다운로드1
13220정성태1/19/202311836오류 유형: 837. NETSDK1045 The current .NET SDK does not support targeting .NET ...
13219정성태1/18/202311435Windows: 220. 네트워크의 인터넷 접속 가능 여부에 대한 판단 기준
13218정성태1/17/202311293VS.NET IDE: 178. Visual Studio 17.5 (Preview 2) - 포트 터널링을 이용한 웹 응용 프로그램의 외부 접근 허용
13217정성태1/13/202312010디버깅 기술: 185. windbg - 64비트 운영체제에서 작업 관리자로 뜬 32비트 프로세스의 덤프를 sos로 디버깅하는 방법
13216정성태1/12/202311916디버깅 기술: 184. windbg - 32비트 프로세스의 메모리 덤프인 경우 !peb 명령어로 나타나지 않는 환경 변수
13215정성태1/11/202314950Linux: 56. 리눅스 - /proc/pid/stat 정보를 이용해 프로세스의 CPU 사용량 구하는 방법 [1]
13214정성태1/10/202313860.NET Framework: 2087. .NET 6부터 SourceGenerator와 통합된 System.Text.Json [1]파일 다운로드1
13213정성태1/9/202312205오류 유형: 836. docker 이미지 빌드 시 "RUN apt install ..." 명령어가 실패하는 이유
13212정성태1/8/202313576기타: 85. 단정도/배정도 부동 소수점의 정밀도(Precision)에 따른 형변환 손실
... 16  17  18  19  20  21  22  23  24  25  26  27  [28]  29  30  ...