[기초부터 완성까지, 프런트엔드] 2장. HTML과 CSS (2)

Posted by : on

Category : FrontendBook


CSS

CSS란?

CSS는 Cascading Style Sheets의 약자로, 문서를 표시하는 방법(스타일이나 레이아웃)을 지정한다. CSS를 사용해 사이트의 레이아웃을 만들고 텍스트의 색상을 변경하며 애니메이션을 넣어 시각적으로 아름답게 표현한다.

작성 방법

스타일을 작성하는 방법은 매우 단순하다. A의 B를 C로 하겠다 이 문장에 맞춰 스타일을 작성한다.
A는 대상을 가리키는 선택자, B는 그 대상의 프로퍼티를 의미하며 C는 그 프로퍼티를 어떻게 바꿀지를 의미하는 이다.

선택자(A) { 프로퍼티(B): 값(C); }

외부 CSS 파일에 작성된 스타일을 HTML 페이지에 연결할 때는 link 태그를 이용한다. href 속성을 통해 CSS 파일의 위치를 지정하고 rel로 관계를 표현한다. CSS는 stylesheet로 값을 넣는다.

<!DOCTYPE html>
<html lang="ko">
  <head>
    <!-- 외부 파일에 정의된 css 연결하기 -->
    <link rel="stylesheet" href="./main.css" type="text/css" />
  </head>
  <body>
    ...
  </body>
</html>

CSS 프로퍼티는 항상 .css 확장자를 가진 파일에서만 작성해야 하는 것은 아니다. HTML 파일 내의 <style> 태그 안에 작성하거나, HTML 요소에 바로 작성할 수 있다.
<style> 태그 내에 작성할 때는 CSS 파일에 작성하는 방법과 동일하며, 요소에 직접 작성할 때는 style 속성을 사용해 선택자와 중괄호 없이 작성한다. 여러 프로퍼티를 지정할 땐 동일하게 ‘;’로 구분한다.

<head>
  <!-- head 내에 style 태그를 열어 스타일 지정하기 -->
  <style>
    h1 {
      color: blue;
    }
  </style>
</head>
<h2 style="color: skyblue; font-size: 14px;">Hello</h2>

상속

CSS 프로퍼티 중, 상위 요소(부모, 조상)에서 적용되었지만, 자식 요소까지 상속되는 프로퍼티들이 있다. 대표적으로 font 관련 프로퍼티나 색상, 정렬 방식의 프로퍼티가 상속된다.

<div style="font-size: 20px;">
  parent
  <!-- child 또한 font-size가 20px로 노출 -->
  <p>child</p>
</div>

반대로 width, height, margin,display, border처럼 상속되지 않는 프로퍼티 또한 존재한다.

반면에 상속되는 프로퍼티지만 HTML 요소의 종류에 따라 상속되지 않기도 한다. 대표적으로 <button> 요소가 이에 해당한다.

<div style="font-size: 20px;">
  parent
  <button>child</button>
</div>

<button>에 있는 텍스트 child의 크기는 font-size를 상속받아 20px을 가져야 하지만, <button> 요소이기 때문에 font-size를 상속받지 않는다.

만약 프로퍼티와 요소의 종류에 영향받지 않고 부모 요소의 프로퍼티를 상속받고 싶다면, 명시적으로 inherit 값을 지정한다.

<div style="font-size: 20px;">
  parent
  <!-- button 내 폰트 또한 20px의 크기를 갖는다. -->
  <button style="font-size: inherit">child</button>
</div>

선택자

어느 요소에 스타일을 적용할지 대상을 뜻하는 패턴을 의미한다. 패턴이라는 말에서 알 수 있듯이 선택자를 작성하는 방법은 여러 가지가 있으며, 지정하는 방식에 따라 명시도나 우선 순위가 다르다.

전체 선택자

* 와일드 카트라 불리는 별표 문자를 사용해 스타일을 지정한다. 전체 선택자를 사용하면 페이지에 해당하는 모든 요소가 영향을 받는다.
전체 선택자는 브라우저의 기본 스타일을 초기화하는 reset css나 normalize css 등의 스타일에서 주로 사용한다. reset cssnormalize css는 브라우저마다 서로 다른 기본 스타일을 가지고 있기 때문에 동일한 스타일로 통일하기 위해 사용하는 기법이다.

* {
  /* 모든 요소의 padding이 0이 됩니다. */
  padding: 0;
}

타입 선택자

HTML 요소 이름을 선택자로 사용한다. 타입 선택자를 사용하면 해당하는 모든 요소가 영향을 받는다. 요소 이름을 그대로 선택자가 들어가야 하는 자리에 작성한다. 모든 <div>요소에 padding을 10px로 설정하고 싶은 경우 다음처럼 작성한다.

div {
  padding: 10px;
}

id 선택자

id 속성에 지정한 값을 이용해 스타일을 지정한다. 다른 HTML 속성을 지정하는 방식과 동일하게 open tag에서 id 속성에 값을 넣어 지정한다. id는 페이지 당 하나만 가지는 단일 값으로, 정확하게 일치하는 단일 요소에만 지정하고 싶을 때 사용한다. id 선택자는 id 앞에 ‘#’을 붙여 작성한다. id가 id-name인 요소에 padding을 10px로 지정하고 싶은 경우 다음처럼 작성한다.

<div id="id-name">id가 id-name인 div 요소</div>
<style>
  #id-name {
    padding: 10px;
  }
</style>

class 선택자

class 속성은 요소에 스타일을 지정하는 가장 일반적인 방법이다. class 속성은 id와 다르게 여러 요소에 같은 class 값을 지정해 동일한 스타일을 지정할 수 있다. class 선택자는 class명 앞에 ‘.’을 붙여 작성한다. 클래스명이 class-name인 요소들에 padding을 10px로 지정하고 싶은 경우 다음처럼 작성한다.

<div class="class-name">class가 class-name인 div 요소</div>
<p class="class-name">class가 class-name인 p 요소</div>
<style>
.class-name {
  padding: 10px;
}
</style>

속성(attribute) 선택자

html 속성의 값들을 비교한 결과로 스타일을 지정한다. 선택자는 요소 이름[속성명(연산자)값]의 형태를 갖는다.

  • 속성명 : 속성명만 작성할 때 해당 속성을 갖는 요소를 모두 선택한다.
  • = : 값이 정확하게 일치할 때 선택한다.
  • ~= : 값이 정확하게 일치할 때 선택한다. =과 다르게 띄어쓰기로 여러 값이 지정된 요소일 때도 찾아서 선택한다.
  • |= : 값이 일치하거나 값 뒤 -(하이픈)을 작성할 때 또한 선택한다.
  • ^= : 접두사로 값을 가질 때 선택한다.
  • $= : 접미사로 값을 가질 때 선택한다.
  • *= : 값이 포함된 모든 요소를 선택한다.
<head>
  <style>
    /* id 속성을 갖는 span 요소에 스타일 지정 */
    span[id] {
      color: skyblue;
    }

    /* href 속성이 https://example.com인 a 요소에 스타일 지정 */
    a[href="https://example.com"] {
      color: red;
    }

    /* 클래스로 class1을 갖는 span요소 선택 */
    span[class~="class1"] {
      color: blue;
    }

    /* id 중 hi 또는 hi- 형태를 갖는 span 요소 선택 */
    span[id|="hi"] {
      color: darkblue;
    }

    /* id의 접두사가 test인 span 요소 선택 */
    span[id^="test"] {
      color: cadetblue;
    }

    /* id의 접미사가 test인 span 요소 선택 */
    span[id$="test"] {
      color: rebeccapurple;
    }

    /* id에 javascript가 포함된 span 요소 선택 */
    span[id*="javascript"] {
      color: teal;
    }
  </style>
</head>

<body>
  <span id="id1">span[id]</span>
  <a href="https://example.com">a[href="https://example.com"]</a>
  <span class="class1 class2">span[class~="class1"]</span>
  <span id="hi-1>span[id|="hi"]</span>
  <span id="test-1">span[id^="test"]</span>
  <span id="id-test">span[id$="test"]</span>
  <span id="id-javascript-1">span[id*="javascript"]</span>
</body>

여러 선택자를 이용해 동시에 스타일 지정하기

여러 선택자에 동일한 스타일을 지정하고 싶을 때 ‘,’를 이용해 해당 선택자를 연결하면 동시에 스타일을 지정할 수 있다.

#id-name,
.class-name,
button {
  color: red;
}

우선순위와 명시도(Specificity)

마지막에 작성된 스타일이 적용된다.

div {
  color: blue;
  color: red;
}

한 선택자에 같은 스타일 프로퍼티를 지정하면 상단에 작성된 스타일은 상쇄되어 제일 마지막에 작성된 스타일이 우선순위로 적용된다. 예제에서는 color가 red로 적용된다.

<link rel="stylesheet" href="./src/styles.css" />
<link rel="stylesheet" href="./src/styles2.css" />

여러 파일에 같은 선택자로 스타일이 지정되면, 이후에 연결된 파일의 스타일이 우선순위로 적용된다. 이런 경우 같은 선택자의 스타일이 분리되어 작성되므로 순서를 통해 제어하기 보다는 별개의 클래스를 만들어 스타일을 완전히 구분하는 것이 좋다.

명시도(Specificity)가 높은 선택자의 스타일이 적용된다.

CSS에서 선택자는 종류나 개수에 따라 명시도(Specificity)를 갖는다. 만약 한 요소에 같은 스타일을 지정하는 선택자가 여러 개라면, 명시도가 높은 선택자의 스타일이 적용된다.
명시도가 같으면 더 많이(구체적으로) 작성된 선택자의 스타일이 적용되며, 상위 명시도를 가진 선택자가 하나라도 있으면 아무리 하위 선택자의 개수가 많아도 상위 명시도를 가진 선택자의 스타일이 적용된다.
A에 해당되는 선택자는 id, B는 class,속성, 의사 클래스 선택자, C는 요소, 의사 요소 선택자가 해당된다. 여기서 명시도의 우선 순위는 A > B > C 순서이다. (*, >, +, ~ 같은 선택자는 명시도에 영향을 주지 않는다.)

<html>
  <head>
    <meta charset="utf-8" />
    <style>
      #parent-id #child-id {
        /* 두 개의 id : (2, 0, 0) */
        /* 이 selector의 스타일이 적용 */
        border: 1px dashed #000;
      }

      #parent-id div .child-class {
        /* 한 개의 id, 한 개의 class, 한 개의 element : (1, 1, 1) */
        /* 위 selector의 명시도가 높으므로 상쇄 */
        border: 1px solid #000;
        /* 이 값은 적용 */
        font-size: 20px;
      }
    </style>
  </head>
  <body>
    <div id="parent-id">
      <div id="child-id" class="child-class">child 1</div>
    </div>
  </body>
</html>

id가 두 개인 선택자가 id 1, class 1, element 1을 갖는 선택자보다 명시도가 더 높아 중첩되는 border 속성은 dashed 스타일이 적용된다.
선택자의 점수가 더 낮더라도 font-size는 다른 선택자에서 정의된 적이 없어 그대로 적용된다.

<html>
  <head>
    <meta charset="utf-8" />
    <style>
      #div-id,
      #div-id {
        /* 두 개의 id : (2, 0, 0) */
        border: 1px dashed #000;
      }

      #div-id {
        /* 한 개의 id : (1, 0, 0) */
        border: 1px solid #000;
      }
    </style>
  </head>
  <body>
    <div id="div-id">영역입니다.</div>
  </body>
</html>

같은 선택자를 여러 번 연속해서 작성하더라도 명시도의 숫자가 올라가기 때문에, id 선택자를 한 번 작성한 경우보다 id 선택자를 두 번 작성한 스타일이 우선 적용된다.
이는 혼란을 주는 사용법이므로 사용하지 않는 것이 좋다.

명시도 무시하기

명시도 특성을 모두 무시하는 두 가지 강력한 방법이 있다.
첫 번째는 인라인 스타일(style=""), 두 번째는 !important이다.
인라인 스타일은 id를 부여하는 방식보다 더 높은 명시도를 갖는다. 또한, !important는 모든 특성을 무시하고 스타일을 적용하는 가장 강력한 방법이다.
!important를 사용하는 것은 모든 종속성이나 규칙을 무시하고 이후에 디버깅을 어렵게 만들기 때문에 안티 패턴으로 취급된다. 일반적인 상황이라면 명시도를 이해하는 것만으로도 충분히 원하는 대로 스타일을 지정할 수 있다.

<html>
  <head>
    <meta charset="utf-8" />
    <style>
      div {
        color: blue !important;
      }

      #test-id {
        color: yellow;
        font-size: 20px;
      }
    </style>
  </head>
  <body>
    <div id="test-id" style="font-size: 40px; color: red;">테스트</div>
  </body>
</html>

박스 모델과 여백 상쇄

박스 모델

브라우저의 렌더링 엔진은 각 요소를 나타낼 때 CSS 박스 모델에 맞춰 그린다. 박스 모델은 네 가지 영역으로 이뤄지는데, content영역, padding영역, border영역, margin영역으로 구분된다.
content 영역은 텍스트나 하위 박스 모델 등을 나타내며, padding, border, margin은 순서대로 content 영역을 둘러싸는 영역이다.
둘러싼 영역들은 margin, padding, border CSS 프로퍼티로 너비를 지정한다.

박스 모델을 이해하기 위해서는 box-sizing CSS 프로퍼티를 알아야한다. box-sizing 프로퍼티는 요소의 너비와 높이를 계산하는 방식을 지정한다. content-box, border-box 두 가지 값이 가능하며, 브라우저 디폴트 값은 content-box이다.

  • content-box : content 영역만을 기준으로 계산된다. 만약 해당 요소에 width를 100px 값을 준다면 content 영역의 너비만 100px이 되며, padding, border는 별개로 계산된다.
  • border-box : padding, border, content 영역을 합한 영역을 기준으로 계산된다. 만약 해당 요소에 width를 100px의 값을 준다면 padding, border, content 영역의 너비를 모두 합한 값이 100px이다. 양쪽 border의 합이 10px, padding의 합이 10px이라면 content 영역의 너비는 80px이다.

필요에 따라 요소에 box-sizing 프로퍼티를 변경해 가면서 사용하기 보다, 두 값 중 선호하는 값 하나로 통일해 동일한 계산법으로 작성하는 것이 일관된 레이아웃을 작성하는데 도움이 된다. 또한, 통일된 박스 모델을 사용하는 것이 요소에 적용된 스타일을 파악할 때도 용이하다.

여백 상쇄

여백은 단순하게 너비나 높이에 더하여 계산될 것 같지만, 실제로는 여백 상쇄로 인해 그렇게 동작하지 않는다. 인접한 같은 레벨의 블록 요소에 상하 여백이 겹치면 여백이 하나로 합쳐지는 현상을 여백 상쇄 라고 한다. 이때 여백은 인접한 여백 중 큰 여백으로 상쇄된다.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <style>
      div {
        margin: 20px 0;
        border: 2px solid #ccc;
      }

      p {
        margin: 30px 0;
        border: 4px dashed #ddd;
      }
    </style>
  </head>
  <body>
    <p>bottom 영역 마진이 상쇄됩니다.</p>
    <p>top 마진이 상쇄되며 bottom 영역의 margin은 더 큰 30px이 됩니다.</p>
    <div>
      <p>이 문단은 위아래로 30px의 margin을 갖습니다.</p>
      <p>이 문단은 위아래로 30px의 margin을 갖습니다.</p>
    </div>
  </body>
</html>

여백 상쇄는 display 프로퍼티 값이 flex, grid일 때나 position 프로퍼티가 absolute일 때, float인 상태일 때는 적용되지 않는다.

flex를 이용한 레이아웃 만들어 보기

레이아웃을 잡는 방법은 <table>을 이용하는 방법부터 아직도 많이 사용되는 float 프로퍼티와 position 등을 이용하는 방법이 존재한다.
모던 웹 브라우저에서는 보다 유연한 레이아웃 방식이 필요했고, CSS3가 등장하며 flexgrid 레이아웃 방식이 등장했다. 현재는 대부분의 모던 브라우저에서 flexgrid 프로퍼티를 지원하기 때문에 레이아웃 배치를 위해 이 두가지 방법을 가장 많이 사용한다.

기본 개념 살펴보기

flex는 디바이스나 디스플레이의 크기에 따라 컨테이너에 들어 있는 컨텐츠의 너비, 높이, 순서를 변경해 컨테이너의 공간을 가장 효율적으로 채우는 방법을 추구한다. 따라서 여유 공간을 채우도록 너비나 높이를 늘이거나 줄인다.

flex container와 flex items

display 프로퍼티에 flexinline-flex를 갖는 HTML 요소를 flex-container라고 한다.
flex container 안에 있는 자식 요소들을 flex items라고 부른다.
flex container는 flex-flow, flex-direction을 기준으로 배치된다.

주축(main axis)과 교차 축(cross axis)

  • 주축(main axis) : flex items가 배치되는 기본축을 의미한다. 항상 수평으로 진행되는 것은 아니며, flex container에서 flex-direction 프로퍼티로 진행 방향을 변경할 수 있다. 주축의 시작점을 main-start, 끝나는 지점을 main-end, 이 크기를 main-size라고 한다. 만약 평행으로 진행한다면 main-size는 flex-container의 너비이다.

  • 교차 축(cross axis) : 주축에 수직인 방향을 의미한다. 주축처럼 cross-start, cross-end가 존재하며 cross-size 또한 존재한다. 주축의 방향이 수평이라면 교차 축의 방향은 수직이므로 cross-size는 flex container의 높이이다.

flex container

flex 레이아웃을 만들려면 해당 요소를 flex container로 만들어야 한다.
HTML 요소의 display 프로퍼티에 flex나 inline-flex 값을 지정하면 해당 요소는 flex container가 된다. flex container인 요소는 몇 가지 flex 프로퍼티를 통해 자식 요소들의 레이아웃을 변경시킨다.

.container {
  display: flex | inline-flex;
}

flex-direction

flex container에서는 flex-direction을 통해 주축의 방향을 지정한다. 방향은 크게 row, column이 있으며, 이 값에 따라 자식 요소인 flex items가 쌓이는 방향이 정해진다.
row는 왼쪽에서부터 오른쪽으로 진행하며, row-reverse는 오른쪽에서 왼쪽으로 진행한다.
column은 row와 반대로 위에서부터 아래로 진행하며, column-reverse는 아래에서 위로 진행한다.

.container {
  flex-direction: row | row-reverse | column | column-reverse;
}

flex-wrap

기본적으로 flex container는 한 줄에 맞춰지지만, flex-wrap 프로퍼티를 사용하면 여러 행으로 표현할 수 있다.
기본값은 nowrap이며, wrap으로 사용하면 위에서부터 아래로 개행된다.
반대로 wrap-reverse를 사용하면 아래에서 위로 올라간다.

.container {
  flex-wrap: nowrap | wrap | wrap-reverse;
}

justify-content

주축의 item을 어떻게 배치할지 결정한다. justify-content 프로퍼티를 이용하면 flex container 내부의 여유 공간을 편리하게 분배할 수 있다.

.container {
  justify-content: flex-start | flex-end | center | space-between | space-around
    | space-evenly | start | end | left | right... safe | unsafe;
}
  • flex-start : 아이템을 main-start를 기준으로 나열한다.
  • flex-end : 아이템을 main-end를 기준으로 나열한다.
  • space-between : 첫 번째 아이템을 컨테이너의 main-start, 마지막 아이템을 main-end로 둔 뒤 여백을 공평하게 분배한다.
  • space-around : 양 끝 아이템의 좌주에 여백을 둔 뒤 아이템 간 여백을 배분한다. 양 끝 아이템의 여백 단위가 1이라면 아이템 간 간격은 2이다.
  • space-evenly : main-start와 첫 번째 아이템의 시작, main-end와 마지막 아이템의 끝, 각 아이템의 간격을 공평하게 분배한다.

justify-content 프로퍼티는 브라우저에 따라 지원하는 값이 제한된다.
left, right, safe, unsafe 등의 값은 파이어폭스에서 지원하지 않으며, IE는 더 많은 프로퍼티 옵션을 지원하지 않으므로 미리 확인 후 사용해야 한다.

align-items

교차 축에 대해 item을 어떻게 배치할지 결정한다. 교차 축에 대한 justify-content라고 볼 수 있다.

.container {
  align-items: stretch | flex-start | flex-end | center | baseline | first
    baseline | last baseline | start | end | self-start | self-end... safe |
    unsafe;
}

align-content

교차 축과 아이템 간 공간이 있으면 공간을 어떻게 분배할지 정한다. flex item이 여러 줄로 작성될 때 영향을 준다.

.container {
  align-content: flex-start | flex-end | center | space-between | space-around |
    space-evenly | stretch | start | end | baseline | first baseline | last
    baseline... safe | unsafe;
}

flex items

부모 요소가 flex container이면 자식 요소들은 자동으로 flex items이다. flex items 요소들은 flex container처럼 flex 관련 프로퍼티를 통해 flex items를 다룬다.

order

flex items의 순서를 지정한다. 기본값은 0이며, 음수와 양수 모두 가능하다.
order 값이 존재하면 order가 작은 요소부터 정렬된다.

flex-grow

item이 차지하는 비율을 정한다. 이 값은 양수만 가능하며, 이 프로퍼티를 가진 다른 자식 요소들과 균등 분배한다.

align-self

flex container에서 정의된 align-items의 프로퍼티를 오버라이딩한다. 프로퍼티 값과 동작은 align-items와 동일하다.

.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

반응형 웹을 위한 미디어 쿼리

미디어 쿼리를 사용하면 컨텐츠 자체를 변경하지 않고 장치의 해상도, 뷰포트의 너비, 미디어의 유형 같은 조건에 따라 스타일을 지정할 수 있다. 데스크탑, 모바일, 태블릿 등 화면의 크기에 따라 다른 스타일을 지정하거나 인쇄, 음성 장치 등의 조건에 따라 다른 스타일을 적용할 수 있다.
각 스타일은 media 속성에 작성된 조건에 해당될 때 적용된다. 그러나 CSS 파일(스타일 시트)은 조건의 참, 거짓 여부와 상관없이 다운로드 되니 주의해야 한다.

<link rel="stylesheet" media="screen (min-width: 300px)" href="main.css" />

<style media="screen (min-width: 300px)">
  /* ... */
</style>

미디어 쿼리는 미디어 타입과 미디어 기능을 기준으로 동작하며, 두 조건이 모두 일치할 때 해당 코드가 동작한다.
미디어 타입에는 모든 장치(all), 인쇄 미디어(print), 화면(screen) 등이 존재한다.

/* 미디어 타입이 screen 일 때 적용된다. */
@media screen {
  /* ... */
}

미디어 기능(feature)은 width나 height 등 장치의 환경 및 특성을 나타낸다. 이 값은 미디어 타입과 다르게 괄호로 묶어서 나타낸다.
min-과 max-를 이용해 최소, 최대 조건을 명시할 수도 있다. max면 이하일 때, min이면 이상일 때 스타일을 적용한다.

/* 장치의 너비가 700px 이상일 때 적용된다. */
@media (min-width: 700px) {
  /* ... */
}

모던 브라우저에서는 >, =, < 등의 비교 연산자를 사용하여 min, max를 이용한 조건과 동일하게 작성할 수 있다. 범위 연산자를 사용하면 좀 더 직관적으로 작성할 수 있다는 장점이 있으나, 아직 많은 브라우저에서 지원되지 않아 지원 여부를 확인한 뒤 사용해야 한다.

/* 장치의 너비가 700px 이상일 때 적용된다. */
@media (width >= 700px) {
  /* ... */
}

미디어 타입과 기능은 ‘,’, and, not, only 등의 연산자로 이어서 작성한다.

/* 생각 시 모든 타입의 장치를 의미한다.
700px 이상일 때 그리고 뷰포트의 방향이 가로일 때 해당 조건을 실행한다. */
@media (min-width: 700px) and (orientation: landscape) {
  div {
    border: 1px solid #ccc;
  }
}

접근성 (Accessibility, a11y)

a11y ?
Accessibility 단어가 길어 처음과 마지막 알파벳을 남기고 중간 열한 글자를 숫자로 대치한 단어이다.

웹 접근성은 모든 신체적 한계, 환경적 한계를 고려해 개발하는 것을 의미한다. 우리나라의 장애인 차별 금지법에도 웹 접근성과 관련된 내용이 작성되었기 때문에, 의무적으로 지켜야 하는 사항이다.
웹 접근성을 따르는 개발은 장애가 있거나 노령으로 인한 신체 변화, 여러 기기 환경을 사용하는 모든 사람이 웹 사이트와 도구 등을 사용할 수 있도록 개발하는 것을 의미한다.

웹 접근성 지침

웹 접근성 지침은 W3C에서 설립한 WAI(Web Accessibility Initiative)에서 전문적으로 연구하며 가이드라인을 제공한다. 웹 컨텐츠에 관한 내용부터 사용자들이 사용하는 도구 개발에서 지켜야할 점, 브라우저나 확장 프로그램을 만드는 사람들이 주의해야 할 점 등을 구분해 가이드라인을 만든다.
그 중 WCAG(Web Content Accessibility) 기반으로 몇 가지 가이드라인과 적용 방법을 살펴볼 것이다. WCAG에서 다루는 Content는 웹 페이지, 프로그램의 정보를 의미한다. 즉 텍스트나 이미지, 사운드 같은 정보들을 어떻게 작성해야 더 많은 사람이 쉽게 이해하는지 작성한 단일 공유 표준이다.

속어, 약어 사용을 지양하라

불필요한 전문 용어나 속어, 약어를 사용하는 것은 지양해야 한다. 속어나 약어 등을 사용하면 장애를 가진 사람, 가지지 않은 사람 모두가 정보를 이해할 가능성이 매우 낮아지며, 외국인 또한 사이트를 이해하기 매우 힘들어진다. 약어는 풀어서 모두가 이해할 수 있도록 작성하며, 속어나 비속어는 사용하지 않는 것을 권장한다.

컨텐츠의 제목과 단락을 명확하게 구분하자

컨텐츠 내 제목과 단락을 명확히 구분하는 것은 스크린 리더가 글의 내용을 파악할 때 도움을 준다. 스크린 리더는 컴퓨터의 화면을 읽어 주는 프로그램으로, 시각적으로 정보를 획득하기 어려운 사람들을 위해 화면에 나타나는 정보를 기계가 음성으로 읽어준다.
HTML을 작성할 때 제목 요소와 단락을 내용의 의미에 맞게 나누는 것이 중요하다. 스크린 리더는 제목 요소를 기준으로 목차를 만들거나 이전, 이후 문단으로 이동하는 기능을 제공할 때가 많다. 또한 문단으로 내용을 적절하게 나누면 스크린 리더가 속도를 조절해 더 명확하게 내용을 전달한다.
또한 레이아웃을 작성할 때 HTML5에서 제공되는 <article>이나 <nav>, <footer> 등의 요소를 사용하는 것이 좋다. 이를 통해 스크린 리더가 정보를 탐색할 때 기계에 추가로 정보를 제공해 각 요소의 내용에 맞게 읽는 방식을 조절할 수 있다.

키보드 동작을 제공하자

<button>이나 <input>, <selector> 요소 등을 사용하지 않고 <div>와 CSS를 이용해 비슷하게 구현해 사용할 때도 있지만, 이 때 기본 요소들이 제공하는 키보드 동작들을 모두 사용하지 못한다. 엔터 키나 탭 키를 누를 때 해당 요소로 이동시키는 동작과 같은 상호작용들을 누릴 수 없다. <select> 요소 또한 <div>로 만들면 이벤트를 추가하지 않는 이상 화살표로 아이템을 선택하거나 탭으로 이동하는 여러 동작이 제대로 동작하지 않는다. 또한 스크린 리더는 해당 요소를 선택해야 하는 요소인지, 이벤트를 발생시키는 요소인지 파악하지 못한다.
그럼에도 불구하고 <div> 요소를 반드시 사용해야 한다면, 몇 가지 추가적인 코드 작성으로 사용 목적과 유사하게 만들어야 한다.

  • role : 해당 요소의 원래 목적을 작성한다. <div><button>의 목적으로 사용할 때 role = button 으로 작성하면 스크린 리더 등 기계에서 해당 요소를 버튼으로 인식한다.
  • tab-index : 해당 요소를 탭 키로 도달하게 하는 속성이다. 해당 속성을 통해 탭 키로 이동할 다음 키보드 위치를 지정한다.
  • 키보드 이벤트 리스너 추가하기 : 버튼 동작이 엔터나 스페이스로 동작하게끔 자바스크립트를 이용해 이벤트를 추가하는 것이 좋다.
<div tabindex="0" role="button" id="button-id" className="div-as-button">
  div로 만든 버튼
</div>

Focus하는 지점을 명확하게 하자

웹 사이트는 키보드만으로 모든 기능이 동작해야 한다. 특히 장애가 있으면 키보드를 사용한 웹 조작 비중이 높아진다. 키보드 사용자는 일반적으로 탭 키를 이용해 링크나 버튼, 텍스트를 입력하는 부분을 찾는다. 항목에 Focus가 된다면 시각 장애가 있는 사용자를 위해 윤곽선이 나타나야 한다. 이런 윤곽선은 기본으로 나타나는데 outline CSS 프로퍼티를 0이나 none으로 지정할 경우 Focus가 된 요소인지 화면에서 식별할 수 없게 된다.
윤곽선을 지우는 것은 마우스를 사용할 수 없는 사람들에게 현재 포커스 지점을 알려줄 수 없어 지양해야 하며, 만약 윤곽선을 지운다면 현재 어떤 요소를 Focus 하는지 추가로 나타내야 한다.

멀티미디어 요소에 접근성을 부여하자

스크린 리더는 텍스트에 접근해 해당 요소를 읽지만, 이미지나 동영상, 오디오는 모든 스크린 리더에서 접근할 수 없다. 이미지나 동영상은 시각 장애가 있는 분들은 접근하기 힘들고, 오디오는 청각 장애가 있으면 접근하기 힘들다. 따라서 이러한 요소들이 어떠한 의미인지 전달해주는 속성들이 있다.

<img src="coffee.png" />

스크린 리더는 이미지를 "coffee.png, image"라고 읽는다. 파일 이름이 해당 이미지를 잘 설명한다면 문제가 없지만, 파일 이름이 해당 이미지와 관련 없는 이름이거나 너무 포괄적인 의미인 경우 어떤 이미지인지 판단하기 어렵다.

<img src="coffee.png" alt="컵에 담긴 따뜻한 아메리카노" title="아메리카노" />

위처럼 alt와 title 속성을 작성한다면 스크린 리더는 "컵에 담긴 따뜻한 아메리카노"라고 읽는다. alt 속성을 통해 이미지가 시각적으로 어떤 모습인지 올바르게 전달해야 하며, 개인적인 견해를 작성하는 것은 지양해야 한다. alt를 지정하면 마우스를 올릴 때 해당 이미지에 대한 title이 노출된다.
이 외에 해당 이미지가 문서에서 특별한 의미가 없다면 background 이미지로 작성하거나 alt 속성에 빈 문자열을 지정하는 것을 권장한다.

여기서 작성한 방법 외에 애니메이션이나 깜빡이는 효과, 색상 선택에도 주의를 기울여야 하며, ARIA(Accessible Rich Internet Applications) 등 더 살펴보고 주의해야 하는 부분이 존재한다. 웹 접근성 가이드라인을 모두 완벽하게 맞추는 것은 사실상 불가능하며, 여러 디자인과 서비스의 명세에 따라 제어할 수 없는 요소들 또한 존재하기 때문에 더욱 어렵다. 하지만 가이드라인을 준수하는 것은 더 많은 사람이 편견 없이 사이트를 이용하는 데에 굉장히 중요한 부분이므로, 더 나은 웹 생태계를 위해 프론트엔드 개발자는 이러한 가이드를 항상 고려하고 지키려는 노력을 해야 한다.

< 이미지 출처 :
https://poiemaweb.com/css3-box-model
https://studiomeal.com/archives/197
https://tapajyoti-bose.medium.com/flexbox-decoded-complete-illustrated-guide-569940a2a8d7
https://codeburst.io/flexbox-flex-basis-flex-grow-41b10bcd33a3 >


About Hyerin Jeon

안녕하세요, 전혜린 (Hailey) 입니다! 주니어 프론트엔드 개발자이며, 리액트를 사용하고 있습니다 :D

-->
Useful Links