사이드뷰 웹 접근성 개선 내역 > 그누보드5 팁자료실

그누보드5 팁자료실

사이드뷰 웹 접근성 개선 내역 정보

자바스크립트 사이드뷰 웹 접근성 개선 내역

본문

목차

  1. 들어가기
  2. 소스 비교
    1. 기존 소스
    2. 개선 소스
  3. 차이점 그리고 해결과제

들어가기

알림! 차이점 그리고 해결과제에서 언급할 내용 개선 테스트 도중 4.0b3 에서 불완전한 사이드뷰 코드 및 스타일이 포함된 것을 발견했습니다. 4.0b4 에서 업데이트 해두겠습니다.

사이드뷰는 그누보드에서도 활용도가 높은 기능 중 하나입니다. 사이드뷰를 사용하는 게시판에서 우리는 특정 회원의 정보를 열람하고, 쪽지를 보내고, 해당 회원이 쓴 글을 몇 번의 클릭 만으로 모두 찾아볼 수 있습니다.

이렇게 높은 활용도를 자랑하는 사이드뷰에도 다음과 같은 단점이 있었습니다.

  • dtd 선언 시 사이드뷰 출력 위치 설정의 어려움
  • 키보드 접근 불가

키보드 접근 불가는 이전까지는 비중 있는 고려 대상이 아니었을지도 모릅니다. 하지만 dtd 선언 후 발생하는 사이드뷰 위치 문제는, 단순 게시판 스킨이 아닌 전체게시물 혹은 전체검색 등에서 한번 더 후처리를 해야 하는 번거로움을 야기시켜 왔습니다.

그누보드4s 에는 사이드뷰의 기본 구조를 개선하여, 이러한 단점들을 모두 수정했습니다.
특히 키보드 접근이 불가능했던 점을 개선한 것은 웹 접근성에 있어서도 상당한 성과 중 하나라고 할 수 있을 것입니다.
또한 sideview.js 로 동작하던 기능을 get_sideview 함수만으로도 php 에서 처리 가능하게 바뀌어 스크립트 off 환경에 대해서도 대응하도록 개선되었습니다.

또한 스타일을 sideview.js 에서 정의하던 기존 방식과 달리 CSS 폴더 내 default.css 와 admin.css 로 스타일을 분리시켜 사이드뷰의 색상이나 위치, 크기 수정 등이 더욱 편리해졌습니다.

소스 비교

기존 소스

  • /lib/common.lib.php
  • /js/sideview.js

sideview.js 는 코드를 생략하고, common.lib.php 를 살펴보겠습니다. 실제 개선된 코드에서는 sideview.js 파일을 사용하지 않습니다.

// 회원 레이어
function get_sideview($mb_id, $name="", $email="", $homepage="")
{
    global $config;
    global $g4;

    $email = base64_encode($email);
    $homepage = set_http($homepage);

    $name = preg_replace("/\'/", "", $name);
    $name = preg_replace("/\'/", "", $name);
    $name = preg_replace("/\"/", """, $name);
    $title_name = $name;

    if ($mb_id) {
        $tmp_name = "<span class='member'>$name</span>";

        if ($config['cf_use_member_icon']) {
            $mb_dir = substr($mb_id,0,2);
            $icon_file = "$g4[path]/data/member/$mb_dir/$mb_id.gif";

            //if (file_exists($icon_file) && is_file($icon_file)) {
            if (file_exists($icon_file)) {
                //$size = getimagesize($icon_file);
                //$width = $size[0];
                //$height = $size[1];
                $width = $config['cf_member_icon_width'];
                $height = $config['cf_member_icon_height'];
                $tmp_name = "<img src='$icon_file' width='$width' height='$height' align='absmiddle' border='0'>";

                if ($config['cf_use_member_icon'] == 2) // 회원아이콘+이름
                    $tmp_name = $tmp_name . " <span class='member'>$name</span>";
            }
        }
        $title_mb_id = "[$mb_id]";
    } else {
        $tmp_name = "<span class='guest'>$name</span>";
        $title_mb_id = "[비회원]";
    }

    $name     = get_text($name);
    $email    = get_text($email);
    $homepage = get_text($homepage);

    return "<a href=\"javascript:;\" onClick=\"showSideView(this, '$mb_id', '$name', '$email', '$homepage');\" title=\"{$title_mb_id}{$title_name}\">$tmp_name</a>";
}

개선 소스

  • /lib/common.lib.php
  • /js/common.js (sideview.js 삭제하고 common.js 에 사이드뷰 관련 코드 신규 추가)
  • css/admin.css
  • css/default.css

/lib/common.lib.php 의 소스는 다음과 같습니다.

// 회원 레이어
function get_sideview($mb_id, $name='', $email='', $homepage='')
{
    global $config;
    global $g4;
    global $bo_table, $sca, $is_admin;

    $email = base64_encode($email);
    $homepage = set_http($homepage);

    $name = preg_replace("/\'/", "", $name);
    $name = preg_replace("/\'/", "", $name);
    $name = preg_replace("/\"/", """, $name);
    $title_name = $name;

    $tmp_name = "";
    if ($mb_id) {
        $tmp_name = "<a href=\"".G4_BBS_URL."/profile.php?mb_id=".$mb_id."\" class=\"sv_member\" title=\"$name 자기소개\" target=\"_blank\" onclick=\"return false;\">$name</a>";

        if ($config['cf_use_member_icon']) {
            $mb_dir = substr($mb_id,0,2);
            $icon_file = G4_DATA_PATH.'/member/'.$mb_dir.'/'.$mb_id.'.gif';

            if (file_exists($icon_file)) {
                $width = $config['cf_member_icon_width'];
                $height = $config['cf_member_icon_height'];
                $icon_file_url = G4_DATA_URL.'/member/'.$mb_dir.'/'.$mb_id.'.gif';
                $tmp_name = '<img src="'.$icon_file_url.'" width="'.$width.'" height="'.$height.'" alt="">';

                if ($config['cf_use_member_icon'] == 2) // 회원아이콘+이름
                    $tmp_name = $tmp_name . " <a href=\"".G4_BBS_URL."/profile.php?mb_id=".$mb_id."\" class=\"sv_member\" title=\"$name 자기소개\" target=\"_blank\" onclick=\"return false;\">$name</a>";
            }
        }

        $title_mb_id = '['.$mb_id.']';
    } else {
        if(!$bo_table)
            return $name;

        $tmp_name = "<a href=\"".G4_BBS_URL."/board.php?bo_table=".$bo_table."&sca=".$sca."&sfl=wr_name,1&stx=".$name."\" title=\"$name 이름으로 검색\"class=\"sv_guest\" onclick=\"return false;\">$name</a>";
        $title_mb_id = '[비회원]';
    }

    $name     = get_text($name);
    $email    = get_text($email);
    $homepage = get_text($homepage);

    $str = "<span class=\"sv_wrap\">\n";
    $str .= $tmp_name."\n";

    if(!G4_IS_MOBILE) {
        $str2 = "<span class=\"sv sv_js_off\">\n";
        if($mb_id)
            $str2 .= "<a href=\"".G4_BBS_URL."/memo_form.php?me_recv_mb_id=".$mb_id."\" onclick=\"win_memo(this.href); return false;\">쪽지보내기</a>\n";
        if($email)
            $str2 .= "<a href=\"".G4_BBS_URL."/formmail.php?mb_id=".$mb_id."&name=".urlencode($name)."&email=".$email."\" onclick=\"win_email(this.href); return false;\">메일보내기</a>\n";
        if($homepage)
            $str2 .= "<a href=\"".$homepage."\" target=\"_blank\">홈페이지</a>\n";
        if($mb_id)
            $str2 .= "<a href=\"".G4_BBS_URL."/profile.php?mb_id=".$mb_id."\" onclick=\"win_profile(this.href); return false;\">자기소개</a>\n";
        if($bo_table) {
            if($mb_id)
                $str2 .= "<a href=\"".G4_BBS_URL."/board.php?bo_table=".$bo_table."&sca=".$sca."&sfl=mb_id,1&stx=".$mb_id."\">아이디로 검색</a>\n";
            else
                $str2 .= "<a href=\"".G4_BBS_URL."/board.php?bo_table=".$bo_table."&sca=".$sca."&sfl=wr_name,1&stx=".$name."\">이름으로 검색</a>\n";
        }
        if($mb_id)
            $str2 .= "<a href=\"".G4_BBS_URL."/new.php?mb_id=".$mb_id."\">전체게시물</a>\n";
        if($is_admin == "super" && $mb_id) {
            $str2 .= "<a href=\"".G4_ADMIN_URL."/member_form.php?w=u&mb_id=".$mb_id."\" target=\"_blank\">회원정보변경</a>\n";
            $str2 .= "<a href=\"".G4_ADMIN_URL."/point_list.php?sfl=mb_id&stx=".$mb_id."\" target=\"_blank\">포인트내역</a>\n";
        }
        $str2 .= "</span>\n";
        $str .= $str2;//."\n<noscript class=\"sv_nojs\">".$str2."</noscript>";
    }

    $str .= "</span>";

    return $str;
}

/js/common.js 의 소스는 다음과 같습니다.

// 사이드뷰
var sv_hide = false;
$('.sv_member, .sv_guest').click(function() {
    $('.sv').removeClass('sv_on');
    $(this).closest('.sv_wrap').find('.sv').addClass('sv_on');
});

$('.sv, .sv_wrap').hover(
    function() {
        sv_hide = false;
    },
    function() {
        sv_hide = true;
    }
);

$('.sv_member, .sv_guest').focusin(function() {
    sv_hide = false;
    $('.sv').removeClass('sv_on');
    $(this).closest('.sv_wrap').find('.sv').addClass('sv_on');
});

$('.sv a').focusin(function() {
    sv_hide = false;
});

$('.sv a').focusout(function() {
    sv_hide = true;
});

$(document).click(function() {
    if(sv_hide) {
        $('.sv').removeClass('sv_on');
    }
});

$(document).focusin(function() {
    if(sv_hide) {
        $('.sv').removeClass('sv_on');
    }
});

/css/admin.css 와 default.css 의 소스는 다음과 같습니다.
관리자와 사용자 모드를 분리해 두었지만 스타일은 같은 스타일이 적용되어 있으니, 편의에 따라 수정하여 사용하실 수 있습니다.

.sv_wrap {display:inline-block;position:relative;font-weight:normal}
.sv_wrap .sv {z-index:1000;display:none;margin:5px 0 0;border:1px solid #283646;background:#111}
.sv_wrap .sv a {display:inline-block !important;margin:0 !important;padding:3px !important;width:94px;border-bottom:1px solid #283646;color:#fff !important}
.sv_wrap a:focus,
.sv_wrap a:hover,
.sv_wrap a:active {text-decoration:none !important}
.sv_on {display:block !important;position:absolute;top:10px;left:20px;width:auto;height:auto !important}
.sv_nojs .sv {display:block}

차이점 그리고 해결과제

우선 가장 중요한 차이점은 스크립트 off 환경에 대응할 수 있다는 것, 키보드만으로 접근이 가능하다는 것입니다.
특히 Tab 키만으로 회원 닉네임에 도달할 경우에도 사이드뷰가 출력이 가능해져서 운용의 용이성 측면을 충분히 만족시켰다고 볼 수 있습니다.

하지만 장점만큼 해결과제도 분명 존재하는 것이 사실입니다.
스크립트 off 일 경우 사이드뷰가 회원 닉네임 아래로 기본 출력되는 방식이어서 전체적인 측면에서의 시각적인 면에서는 마이너스 효과일 수 있지만, 스크립트 off 일 때도 동일한 기능을 제공하기 위한 최선의 방법입니다.
그리고 하나의 공통된 사이드뷰를 호출된 해당 회원에게 적용시키는 것이 아니라, 목록 내 모든 적용 대상에게 반복적으로 사이드뷰를 생성하다보니 생성되는 마크업이 약간은 비효율적인 면도 생겨났습니다.
즉, 팝업용 사이드뷰 한개와 <noscript> 용 사이드뷰 한개 총 두개의 사이드뷰가 목록 내 모든 적용 대상 수 만큼 생성된다는 것입니다.

물론 이 해결과제에서 나타난 비효율적인 코드 생성이 전체적으로 부담을 줄만큼 비효율적이지는 않습니다. 하지만 보다 세련된 해결방법의 필요성은 여전히 존재하며, 지금 당장 개선되기는 어려운 부분들이지만, 많은 분들의 경험과 노하우가 쌓인다면 자연스럽게 해결될 것이라는 기대를 가지고 있습니다.

추천
0

댓글 2개

gnb 부분은 이런 부담 없이 자바스크립트 off 에 깔끔하게 대응하도록 문제를 풀어냈는데, 유독 사이드뷰가 아직 애를 먹이고 있네요. 급하게 생각지 않으려 하고 있습니다.
전체 2,411 |RSS
그누보드5 팁자료실 내용 검색

회원로그인

(주)에스아이알소프트 / 대표:홍석명 / (06211) 서울특별시 강남구 역삼동 707-34 한신인터밸리24 서관 1404호 / E-Mail: admin@sir.kr
사업자등록번호: 217-81-36347 / 통신판매업신고번호:2014-서울강남-02098호 / 개인정보보호책임자:김민섭(minsup@sir.kr)
© SIRSOFT