FormData() 는 자바스크립트에서 HTML 폼 데이터를 쉽게 서버로 전송할 수 있게 해주는 내장 객체이다.
주로 파일 업로드 이미지 전송 등 multipart/form-data 방식이 필요한 상황에서 사용된다.
1. 기본 문법
new FormData()로 form 객체를 생성한다.
그리고 몇 가지 메소드를 사용해서 FormData를 다룰 수 있다.
append(key, value) : 데이터 추가
set(key, value) : 기존 키가 있으면 덮어쓰고 없으면 새로 추가
get(key) : key에 해당하는 첫 번째 값을 가져옴
getAll(key) : key에 해당하는 모든 값을 배열로 가져옴
delete(key) : 해당 key값의 필드를 삭제 (키, 밸류 모두 제거)
has(key) : 해당 key값이 존재하는지를 확인
const form = new FormData();
// append
form.append('file', testData); // file 이라는 key를 가지고 testData를 가진 데이터를 추가
// set
form.set('file', testData2); // file 이라는 key가 있으므로 file에 testData2 밸류로 덮어씀
// get
form.get('file'); // file 이라는 key의 value를 반환
// getAll
form.append('username', 'Chris');
form.append('username', 'Bob');
form.getAll('username'); // Returns ["Chris", "Bob"] - username이라는 key를 가진 모든 value를 배열로 반환
//delete
form.get('file'); // file 이라는 key를 가진 필드를 제거
// has
form.has('file'); // file 이라는 key를 가졌는지 여부 확인 (file을 delete 했기 때문에 false 반환)
2. 전송
fetch나 XMLHttpRequest 의 요청 바디에 FormData 객체를 넣으면 브라우저는 자동으로 적절한 Content-Type 헤더(multipart/form-data)를 지정하여 전송한다.
파일이나 이미지 업로드 등을 바이너리 데이터 전송한다.
바이너리 데이터 0과 1로 이루어진 이진수 데이터로 이미지, 오디오, 동영상 등 데이터를 바이너리 형태로 저장. 전송시 base64로 인코딩해서 사용
제이쿼리에서는 js로 애니메이션 효과를 구현하려면 편하게 .animate 메소드를 사용할 수 있었지만
바닐라 js로 애니메이션을 구현하려고 하면 비교적 복잡한 코드로 구현이 필요하다는걸 알 수 있다.
애니메이션 작동 원리를 생각해보면 일정한 시간 간격으로 특정 위치로 이동하게 되는 소스를 구현해야 하는데 일정 시간을 반복하는걸 생각해보면 setInterval이나 setTimeout 를 생각할 수 있는데 두 가지 방법 보다는 requestAnimationFrame이 브라우저 측면에서는 훨씬 효율적이다.
1. requestAnimationFrame 란?
requestAnimationFrame는 (줄여서 RAF라고 부른다.) 브라우저에서 제공하는 메소드로 애니메이션과 같이 반복적인 작업을 수행할 때 사용한다.
requestAnimationFrame의 특징을 설명하기 위해서는 setInterval, setTimeout 함수와 비교를 해보면 쉽게 알 수 있다.
setInterval / setTimeout
requestAnimationFrame (RAF)
타이머의 주기가 정확하지 않기 때문에 애니메이션이 일정하지 않게 보이거나 끊겨 보일 수 있다.
브라우저의 리페인트 주기에 맞게 콜백 함수를 예약하기 때문에 브라우저가 화면을 갱신할 때에 맞춰 애니메이션을 실행한다. 따라서 부드러운 애니메이션을 볼 수 있다.
고정된 타이머 주기를 사용해서 타이머 기능이 필요하지 않더라도 불필요하게 작업이 되거나배터리 소모가 된다.
브라우저에 최적화하여 애니메이션을 처리하기 때문에 사용자 디바이스의 사양이나 배터리 수명 등을 최적화 하여 실행한다.
브라우저가 비활성된 상태에서 혹은 백그라운드에서 실행을 멈추지 않고 계속해서 작업을 실행하기 때문에불필요한 리소스를 소비하게 된다.
브라우저가 비활성된 상태이거나 백그라운드에서 실행을 할 때 애니메이션 처리를 조정하여 성능을 최적화한다.
정해진 시간 간격에 따라 비동기적으로 작업을 예약하고 실행하기 때문에 다른 브라우저 작업과 동기화가 보장되지 않을 수 있다.
브라우저의 리페인트 주기에 맞게 콜백 함수를 실행하기 때문에 다른 브라우저 작업과 동기화 되어 실행한다.
그리고
requestAnimationFrame은 초가 60프레임 정도를 구현한다.
(브라우저 상황에 따라 다를 수 있다. 하지만 최대한 구현하려한다.)
2. requestAnimationFrame 사용
기본적인 사용은 아래와 같다.
const callBackFnc = (timeStamp) => {
console.log(timeStamp); // timeStamp 값이 시간에 따라 계속 증가한다.
}
// requestAnimationFrame(콜백함수);
requestAnimationFrame(callBackFnc);
로 지정을 하는데 testDuration이라는 반복되는 값을 만들어서 requestAnimationFrame 함수가 실행 될 때 마다
50씩 증가를 시켜 스크롤 위치에 변화를 준다.
그리고 증가하는 testDuration 변수 값이 500이 넘어가게 되면 requestAnimationFrame 함수의 반대 성격의 cancelAnimationframe() 함수를 사용해서 애니메이션을 멈출 수 있다.
(버튼 클릭 -> 50씩 스크롤 위치 증가 -> 증가된 값이 500이 넘어가면 멈춤)
3. requestAnimationFrame 활용
실무에서 쓸법한 내용으로 예시를 들자면
const duration = 500; // 애니메이션 속도 조정
const moveEtc = (target) => {
const targetEl = document.querySelector(target); // 함수를 실행할 때 목적지 엘리먼트를 받아옴
if(targetEl){
let start;
const targetPosition = targetEl.getBoundingClientRect().top; // 파라미터로 받아온 target의 위치값 구하기
const startPosition = window.scrollY; // 애니메이션 이벤트가 발생했을 때의 현재 위치 값
const distance = targetPosition;
const easings = { // 애니메이션의 easing 효과
linear(t) {
return t;
},
easeInQuad(t) {
return t * t;
},
easeOutQuad(t) {
return t * (2 - t);
},
easeInOutQuad(t) {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
},
easeInCubic(t) {
return t * t * t;
},
easeOutCubic(t) {
return (--t) * t * t + 1;
},
easeInOutCubic(t) {
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
},
easeInQuart(t) {
return t * t * t * t;
},
easeOutQuart(t) {
return 1 - (--t) * t * t * t;
},
easeInOutQuart(t) {
return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t;
},
easeInQuint(t) {
return t * t * t * t * t;
},
easeOutQuint(t) {
return 1 + (--t) * t * t * t * t;
},
easeInOutQuint(t) {
return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t;
}
};
const moveScroll = function(timeStamp){ // requestAnimationFrame를 적용할 함수, 첫 번째 파라미터로 타임 스탬프 받아오기
if(start === undefined){
start = timeStamp; // requestAnimationFrame 함수의 타임스탬프를 기준으로 시작 시간을 지정
}
const elapsed = timeStamp - start; // 시작 시간, 타임 스탬프를 이용해서 애니메이션 경과 시간을 구한다.
const targetPos = startPosition + distance * easings.linear(elapsed / duration); // 현재 위치, 목표 위치, easing 등으로 최종 목적지까지의 애니메이션 형태를 구성
window.scrollTo(0, targetPos);
if(elapsed <= duration){
requestAnimationFrame(moveScroll);
}else if(timeStamp >= elapsed){
// 애니메이션 종료 후
const targetPosFix = window.scrollY + targetEl.getBoundingClientRect().top;
window.scrollTo(0, targetPosFix);
}
};
requestAnimationFrame(moveScroll);
}
}
위와 같이 작성할 수 있다.
requestAnimationFrame(콜백함수)의 콜백함수는 첫 번째 파라미터로 받아온 타임 스탬프 값(timeStamp)을 이용해서 애니메이션 시작점, 목적지, 애니메이션의 경과 시간 등을 계산한다.
컴포넌트의 데이터는 각 컴포넌트에서 관리하기 때문에 각 컴포넌트는 고유한 데이터 유효범위를 갖는다.
따라서 컴포넌트간 데이터를 주고 받기 위해서는 특별한 규칙을 따라야한다.
위와 같이 상→하로 props를 통해 데이터를 전달하고
하→상은 이벤트를 올려서 전달한다.
*컴포넌트 통신 규칙 : 직접 연관이 되어있는 상, 하위 컴포넌트 간의 데이터 전달이 가능하다. (데이터 오류 발생시 추적에 용이)
1. props (상 -> 하)
props는 위에서 설명한 것과 같이 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달하는 방법이다.
부모 컴포넌트에 등록되어 있는 데이터를 가져오는 기본적인 사용 방법은
1. 자식(하위) 컴포넌트에 props 속성을 사용해 프롭스 속성명을 등록해준다.
var appHeader = {
template: '<h1>Title</h1>',
props: ['propsdata'] // 프롭스 속성 명은 임의로 지정이 가능하다.
}
new Vue({
el: '#app',
component: {
'app-header' : appHeader,
},
data: {
message: 'hi',
}
})
2. 자식 컴포넌트에서 v-bind를 사용해서 상위 컴포넌트의 데이터 속성을 해당하는 자식 컴포넌트로 전달한다.
<!-- v-bind:프롭스 명="상위 컴포넌트의 data 속성" -->
<app-header v-bind:propsdata="message"></app-header>
크게 위 1, 2번의 방법으로 적용할 수 있다.
<div id="app">
<app-header v-bind:propsdata="message"></app-header>
<app-content v-bind:propsnum="num"></app-content>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var appHeader = {
template: '<h1>{{ propsdata }}</h1>', // {{ 데이터 }} 이중 괄호를 통해 부모 컴포넌트로부터 받은 props 값을 그대로 뿌려줄 수 있다.
props: ['propsdata'],
}
var appContent = {
// 각 영역 안에 데이터는 고유의 데이터로 가진다. 따라서 appHeader와 마찬가지로 propsdata라는 같은 이름으로 사용해도 된다.
template: '<div>{{ propsnum }}</div>',
props: ['propsnum'],
}
new Vue({
el: '#app',
components: {
'app-header' : appHeader,
'app-content' : appContent,
},
data: {
message: 'hi',
num: 10
}
});
</script>
2. Event Emit (하 -> 상)
부모 컴포넌트의 데이터를 가져올 때 props 속성을 사용한다면
자식 컴포넌트에서는 이벤트 발생(emit)을 통해 상위로 이벤트를 전달해준다.
방법은
1. 자식 컴포넌트에 event emit 메소드를 등록해준다.
// appHeader에 있는 button을 클릭하면 passEvent 함수가 실행되고 그 함수는 'pass'라는 이벤트명을 가진 event emit용 함수이다.
var appHeader = {
template: '<button v-on:click="passEvent">click me</button>',
methods: {
passEvent: function(){ //passEvent라는 메소드를 통해 해당 자식 컴포넌트에 $emit 이벤트명은 정의한다.
this.$emit('pass'); // 이벤트 이름 등록 : $emit('이벤트명')
}
}
}
new Vue({
el: '#app',
components: {
'app-header': appHeader,
},
methods: {
logText: function(){
console.log('hi');
},
}
})
2. 자식 컴포넌트에 $emit으로 등록한 이벤트 명을 통해 부모 컴포넌트의 메소드를 가져온다.
<!-- v:on:하위 컴포넌트에서 발생한 이벤트 이름="상위 컴포넌트의 메소드 이름" -->
<app-header v-on:pass="logText"></app-header>
위와 같이 작업하면 app-header 영역에 버튼이 생기고
해당 버튼을 클릭하면 자식 요소의 버튼을 클릭하지만 부모 요소에 logText() 메소드가 실행된다.
일반적인 웹에서는 html, css, javascript를 이용해서 화면을 구성하고 조작한다.
Vue.js
<div id="app"></div>
<script>
const app = document.querySelector('#app');
let str = 'hello';
app.innerHTML = str; // #app 영역에 hello 텍스트 노출
str = 'Hi';
app.innerHTML = str; // str 변수의 값을 바꿨지만 바뀐 내용이 즉시 반영되는 것이 아닌 innerHTML 을 통해 다시 선언해줘야 바뀐 변수값이 #app 영역에 적용된다.
</script>
반면 Vue.js는 MVVM(Model-View-ViewModel) 패턴으로
화면에서 보여지는 내용들을(View) Vue의 Dom Listeners를 통해 자바스크립트에 있는 데이터를 바꿔주거나 특정 자바스크립트를 실행하게 된다.
그리고 Dom Listeners를 통해 자바스크립트의 데이터가 변경 됐을 때 Data Bindings를 통해 변경된 내용을 화면에 반영하게 된다.
<div id="app"></div>
<script>
const app = document.querySelector('#app');
const viewModel = {};
// Object.defineProperty(대상 객체, 객체의 속성, {
// 정의할 내용
// })
Object.defineProperty(viewModel, 'str', {
// 속성에 접근했을 때의 동작을 정의
get: function(){
console.log('접근') // 콘솔창에서 viewModel.str 을 입력하면 '접근' 출력
}
// 속성에 값을 할당했을 때의 동작을 정의
set: function(newValue){
console.log('할당', newValue) // 콘솔창에서 viewModel.str = 'Hi' 를 입력하면 '할당 10' 출력
app.innerHTML = newValue // viewModel.str 값을 할당/변경할 때 마다 해당하는 값을 app에 뿌려준다.
}
});
</script>
* Object.defineProperty : 객체의 속성에 접근, 할당 했을 때의 동작을 정의한다.
위와 같이 데이터를 접근/변경할 때 마다 바로바로 데이터를 바인딩 시켜주는 것은 Vue.js의 가장 중요한 특징인 Reactivity이다.
하지만 이러한 방법은 RAM이나 그래픽 처리 장치(GPU)의 사용량을 커지게하여 페이지에 병목 현상을 줘서 오히려 악영향을 끼치게 한다.
2. will-change
위 css핵을 대체할 수 있는 새로운 css 속성이 생겼다. 그 속성이 will-change 이다.
속성명 그대로 어떤 속성이 변경이 될 것인지 미리 엘리먼트에 적용하여 브라우저가 해당 css를 읽을 때 변경 될 속성을 알게하여 미리 그 변경에 대비할 수 있게 하는 것이다.
will-change: auto; /* 기본 값 */
will-change: scroll-position; /* 스크롤 위치가 변경 될 예정 */
will-change: contents; /* 요소의 컨텐츠 내용이 변경 될 예정 */
/* 특정 css 속성 적용 */
will-change: transform; /* transform 속성이 변경 될 예정 */
will-change: opacity; /* opacity 속성이 변경 될 예정 */
will-change: left, top; /* left, top 값이 변경 될 예정 */
will-change: transform, opacity
자바스크립트 공부를 하거나 면접을 보다보면 호이스팅에 대해 설명을 하거나 이해를 요구할 때가 많다.
그렇기 때문에 호이스팅에 대해 완벽하게 이해를 하고 있어야 원활한 자바스크립트 사용을 할 수 있다.
1. 호이스팅이란?
변수나 함수를 스코프 범위 안에서 언제든지 사용할 수 있도록 하는 것을 말한다.
예시를 보면 위의 말이 어떤 내용인지 이해할 수 있다.
console.log(a); // undefined
var a = 123;
위의 코드를 보면 console.log를 통해 a라는 변수를 불러왔는데 해당 구문 위에는 a변수 선언이 없었음에도 에러메시지가 뜨는 것이 아니라 undefined가 뜨는 것을 볼 수 있다.
var a;
console.log(a);
a = 123;
즉 실제 코드의 실행은 위의 소스와 같이 적용이 됐다는 것을 알 수 있다. a라는 변수 선언을 호이스팅하고 그 a를 console.log를 통해 불러왔으니 아직 할당 된 값이 없기 때문에 undefined가 노출이 되는 것이다.
[!] 호이스팅은 선언된 변수가 스코프 범위 내에서 최상단으로 이동해서 하단에 있는 영역에서 그 변수들을 사용할 수 있도록 해주는 것이라 이해하면 쉽다. (실제로 변수의 위치가 상단으로 이동하는 것은 아니다.)
하지만 변수 선언은 var만 있는 것이 아니라 let, const 변수 선언이 있다.
그리고 let과 const는 var와 같은 호이스팅의 형태를 가지고 있지 않다.
2. var 변수 호이스팅
위의 예시와 같이 var는 변수 선언을 스코프 내에서 호이스팅한다. (선언과 동시에 초기화)
그리고 var 변수 선언은 특징이 있는데 함수(function) 내부에서 선언한 변수는 지역변수로 호이스팅이 되지만
함수 외에 if문, for문, while문 등의 문법에서는 해당 구문 안에서 사용된 var 변수 선언들을 전역변수로 호이스팅 시켜버린다.
- 함수
function test(){
var a = 123;
console.log(a);
}
test(); // 123 출력
console.log(a); // 에러
- for 문
for (var i = 0; i < 5; i++){
console.log(i);
// 1
// 2
// 3
// 4
}
console.log(i); // 5
위 for문의 예시를 보면 for문 안에서 변수 i를 선언했지만 for문 밖에서 console.log를 통해 i를 호출했을 때 for문이 다 돈 후 숫자 5가 출력이 되는 것을 볼 수 있다. 즉 for문 밖에서도 for문 안에서 선언한 변수를 사용할 수 있다는 것을 알 수 있다.
함수를 제외한 모든 구문 및 환경에서 var로 선언한 변수는 변수 선언 자체를 최상단으로 다 올린다고 생각하면 된다. (실제로 변수들을 제일 위로 올리는 것은 아니다)
이처럼 함수 내부에서만 지역 변수로 사용이 되는 var 변수는
함수 레벨 스코프 변수이다.
3. let, const 변수 호이스팅
위에서 설명한 var 변수 선언과 let, const 변수 선언은 다르다. 예시를 보면 쉽게 알 수 있다.
console.log(a); // 에러
let a = 123;
console.log(a); // 123
var였다면 위의 소스는 undefined가 출력이 됐을텐데 let으로 변수 a를 선언하면 위의 소스는 에러가 출력된다. 이게 let과 var의 호이스팅에 가장 큰 차이인데, var는 선언된 변수들을 함수를 제외하곤 호이스팅하여 모든 곳에서 사용할 수 있도록 하고 let은 변수가 선언된 위치에 도달했을 때 그 기점을 기준으로 변수를 초기화한다. const 변수도 동일한 특성을 가진다.
즉 해당 let, const 변수 선언 이후에서야 비로소 해당 변수 값을 사용할 수 있다는 뜻이다.
그렇다고 let이나 const가 호이스팅을 안하는 것은 아니다. 위와 같이 변수가 선언된 이후에야 그 변수를 사용할 수 있는 이유는 TDZ(Temporal Dead Zone) 영역의 특징 때문이다.
let과 const변수가 선언되기 이전에 내용들은 일시적으로 죽은 영역이 된다. 즉 사용할 수 없는 영역이 된다.
console.log(a);
//////////////// TDZ (let으로 선언한 변수 a를 사용할 수 없다)
let a = 123;
console.log(a); // 123
그리고 var와는 또 다른 특징이 있는데 var는 함수에서만 지역변수로 호이스팅되고 for, if문 과 같은 다른 구문에서는 전역 변수로 호이스팅이 되었었는데 let, const는 모든 구문에서 지역변수 단위로 호이스팅이 된다. 이를 블록 레벨 스코프라고 부른다.
각 {} 중괄호 안에 있는 블록 블록마다의 요소들에 각각의 지역 변수를 선언해준다는 뜻이다.
for(let i = 0; i < 5; i++){
console.log(i);
}
console.log(i); // 에러
var에서 예시로 봤던 for문을 예로 들면
for문 안에 let으로 변수 i를 선언하고 그 바깥에서 console.log로 i를 호출했을 때 for문 안에서 i를 선언했기 때문에 에러메시지가 뜨는 것을 알 수 있다.
만약 for문 바깥에서도 i를 사용하고 싶다면 let i 변수 선언을 for문 바깥에서 해주는 것도 방법이다.
let i;
for(i = 0; i < 5; i++){
console.log(i);
}
console.log(i); // 5
var, let, const 변수 선언에 대한 추가적인 설명은 하단 링크에도 작성해놓았다.
자바스크립트를 사용하면서 내가 모든 소스를 짜고 최적화와 모든 예외 상황들을 고려하여 작업을 할 수 있다면 좋겠지만 많은 리소스가 들고 또 내가 생각하지 못하는 부분들도 존재하기 때문에 간단하게 사용할 수 있는 플러그인을 많이 사용한다. 대표적인 플러그인이 슬라이더(slick, swiper 등...), 차트(chart.js, 구글차트) 등이 있다.
그리고 오늘 알아볼 AOS라는 플러그인도 스크롤에 따른 애니메이션 효과를 구현할 때 많이 쓰인다.
1. AOS 란?
AOS는 Animate on scroll library의 약자로 스크롤을 이용한 애니메이션 효과를 구현하는 플러그인이다. 스크롤을 내리는 위치에 따라 내가 지정한 영역이 fade효과와 더불어 아래쪽에서 올라오거나 왼쪽에서 오른쪽으로 이동하거나 하는 효과를 구현할 수 있다.
AOS에서 구현하는 애니메이션 효과는 css3 transition과 transform을 사용하며 작동한다.
위 1번에서 사용한 css를 보면 caption태그를 html 구조상에만 남겨두고 실제 페이지 노출시 안보이게 하기 위해
position:absolute를 사용하여 숨기는 내용의 css를 사용했는데
caption 태그에 absolute가 들어가게 되면 모바일 safari, chrome 등에서 table의 너비 자체를 인식 못하는 버그가 있기 때문에 caption태그를 숨기기 위해서는 absolute를 사용해서 띄워서 숨기는 것이 아닌 다른 방식으로 caption태그를 숨겨줘야한다.
브라우저를 통해 페이지를 탐색할 때 비장애인의 경우엔 내가 보고 싶은 컨텐츠를 마우스로 편하게 클릭하고 이용할 수 있다. 하지만 시각 장애인의 경우 tab키, 방향키 등을 사용한 스크린리더를 통해 페이지에서 원하는 정보를 얻을 수 있다. 그렇기 때문에 페이지의 양이 많다면 그리고 그 정보가 페이지 하단부에 있다면 정보를 얻기까지 수도 없이 많은 tab, 방향키 입력이 필요할 것이다. 이러한 접근성이 부족한 내용을 해결하기 위해 사용하는 것이 스킵 네비게이션이라는 방법이다.
1. 스킵 네비게이션(skip navigation)
스킵 네비게이션은 원래는 말 그대로 네비게이션 영역의 많은 링크들을 건너뛰고 바로 컨텐츠 정보를 탐색하기 위해 사용하는 용도를 가지고 있다.
1번에서 설명한 예시와 달리 위의 방법은 각 주요 서비스 섹션을 스킵 네비게이션으로 연결하여 바로바로 접근할 수 있도록 작업하였다.
스킵 네비게이션은 위에서 설명한바와 같이 기본적으로 네비게이션을 스킵(건너뛰기)하기 위해서 사용을 한다.
그리고 과거에는 그 용도 외에 페이지 각 세부 영역별로 스킵 네비게이션과 연결하면 오히려 접근성을 저해하고 페이지 이용을 복잡하게 만든다고 추천하지 않았다.
하지만 최근들어 많은 대규모 페이지나 플랫폼에서 스킵 네비게이션을 단순 네비게이션을 스킵하기 위한 용도가 아닌 원하는 서비스나 정보를 한번에 이용할 수 있게 만든 하나의 링크 묶음으로 사용하고 있다.
이 부분은 명확히 어떤게 옳고 그르다고 말하기엔 방법에 대한 고민이 필요해보인다.
3. 스킵 네비게이션 스타일
스킵 네비게이션은 비장애인 사용자들이 페이지를 이용할 때 화면에서 보이지 않게 작업해야한다. 키보드나 스크린리더로 페이지를 tab 하였을 때 스킵 네비게이션이 노출되고 사용될 수 있게 해야한다.
그렇기 때문에 페이지에 맨 처음 접근하게 되면 일반적인 상황에서는 스킵 네비게이션을 확인할 수 없다. 그리고 그러한 이유로 스킵 네비게이션에 따로 css 스타일을 입히지 않아도 된다고 생각할 수 있다.
하지만 보통의 상황에서는 스킵 네비게이션 링크에 tab이 되었을 경우 tab이 활성화 된 링크에 css 스타일 효과를 줘서 화면에 노출되게끔 처리하는 것이 많이들 사용하는 방법이고 좋은 방법이라 생각한다.
스킵 네비게이션 예시 (네이버 메인)
.skip_nav a{position:absolute; top:-30px; left:0; background:#000; height:30px; line-height:30px; color:#fff; font-size:12px; padding:0 6px;}
.skip_nav a:focus,
.skip_nav a:active{top:0;} <!-- 해당 a태그가 focus 혹은 active 되었을 경우 a태그가 화면에 노출되게 처리 -->
4. 스킵 네비게이션 사용시 주의사항
스킵 네비게이션을 사용할 때에 몇 가지 주의 사항이 있다.
1. 스킵 네비게이션의 위치는 가능하면 최대한 body태그 맨 처음으로 위치해야 한다.
: 이유는 스킵 네비게이션의 목적이 네비게이션 영역을 스킵하기 위해서 혹은 주요 서비스로 페이지 초입에서 바로 접근하기 위해 사용을 하기 때문에 네비게이션 영역 뒤에나 컨텐츠 영역 뒤에 위치하게 되면 스킵 네비게이션을 쓰는 목적이 사라지기 때문이다.
2. 스킵 네비게이션은 페이지 구석구석 여러번 사용하는 것이 아니라 처음에 한번만 사용해야 한다.
: 시각 장애인 입장에서 페이지를 구성한다고 했을 때 스킵 네비게이션이 페이지 이용하는 중간 중간에 위치해서 페이지 요소들을 넘나들며 여기저기 바로바로 이용할 수 있게 한다면 좋을 것 같다는 생각을 가끔했다. 하지만 스킵 네비게이션은 페이지 첫 부분에 딱 한번 사용하는 것이 적절하다.
오히려 과한 스킵 네비게이션의 사용은 페이지의 구조와 페이지 이용을 더 복잡하게 할 뿐이다.