본문으로 건너뛰기

마우스와 키보드 상태

HTML·CSS 목차선택자레슨 46 / 93

목차

가상 클래스(pseudo-class)는 :으로 시작하는 선택자 조각으로, 마우스가 올라와 있는지 · 포커스가 있는지처럼 그때그때 바뀌는 상태로 요소를 고릅니다. 상태가 바뀌면 브라우저가 다시 골라, 규칙이 붙었다 떨어집니다.

레시피 노트의 내비게이션 링크는 마우스를 올렸을 때 밑줄이 생기고, 폼 칸은 키보드로 왔을 때 둘레에 표시가 보여야 합니다. 그런 상태는 HTML에 적어 둘 수 없습니다. HTML에 적지 않았는데 클래스처럼 붙었다 떨어지는 조건이라 가상 클래스라고 부릅니다(자료에 따라 의사 클래스). 이 레슨은 :hover · :focus · :focus-visible 셋과 포커스 표시를 바꾸는 법을 봅니다.

그림 준비 중

1:hover — 마우스를 올린 동안

:hover는 마우스 포인터가 올라와 있는 요소를 고릅니다. 아래 잰 값은 '조리 순서' 링크에 마우스를 올린 뒤 잰 것입니다. 결과 화면에서도 링크에 마우스를 올려 보세요.

<nav>
  <a href="index.html">목록</a>
  <a href="#steps">조리 순서</a>
</nav>
nav a {
  text-decoration: none;
}

nav a:hover {
  text-decoration: underline;
}
결과 화면
잰 값개발자 도구에서 본 값
  • a[href="#steps"]의 text-decoration-lineunderline
  • a[href="index.html"]의 text-decoration-linenone
  • nav의 :hover켜짐

마우스가 올라온 링크만 밑줄이 생깁니다. 마우스를 치우면 그 링크는 더 이상 :hover가 아니라 규칙이 떨어지고 밑줄도 사라집니다. 상태가 바뀔 때마다 브라우저가 다시 고르기 때문입니다(브라우저 규칙 4).

마우스가 올라온 요소를 감싼 조상도 함께 :hover입니다. 링크에 올리면 그 링크를 감싼 nav도 :hover라, nav:hover로 '내비게이션 위에 마우스가 있을 때'를 고를 수 있습니다.

2:focus와 :focus-visible

포커스는 키보드 입력을 받을 요소 하나에 있습니다. :focus는 포커스가 있는 요소를 언제나 고르고, :focus-visible은 브라우저가 '포커스 표시가 필요하다'고 볼 때만 고릅니다. 아래는 단추를 마우스로 누른 뒤 잰 값입니다.

<label for="q">검색</label>
<input id="q" type="text" />
<button>찾기</button>
input:focus-visible,
button:focus-visible {
  outline: 3px solid #005bb5;
}
결과 화면
잰 값개발자 도구에서 본 값
  • button의 :focus켜짐
  • button의 :focus-visible꺼짐
  • button의 outline-stylenone

마우스로 누른 단추에는 포커스가 있지만 :focus-visible은 꺼져 둘레 표시가 없습니다. 크롬 기준으로 네 경우를 견주면 이렇습니다.

어떻게 왔나글자 칸단추
마우스로 누름:focus-visible 켜짐꺼짐
Tab으로 옴켜짐켜짐

글자 칸은 마우스로 눌러도 지금 칠 곳을 보여야 해서 켜지고, 단추는 키보드로 왔을 때만 켜집니다. 그래서 포커스 표시는 :focus-visible에 주면 마우스로 누르는 사람에게는 군더더기가 없고, 키보드로 옮기는 사람에게는 자리가 보입니다.

나머지 두 경우의 잰 값

글자 칸을 마우스로 눌렀을 때:

<label for="q">검색</label>
<input id="q" type="text" />
<button>찾기</button>
input:focus-visible,
button:focus-visible {
  outline: 3px solid #005bb5;
}
결과 화면
잰 값개발자 도구에서 본 값
  • #q의 :focus-visible켜짐
  • #q의 outline-stylesolid

Tab을 두 번 눌러 단추로 왔을 때:

<label for="q">검색</label>
<input id="q" type="text" />
<button>찾기</button>
input:focus-visible,
button:focus-visible {
  outline: 3px solid #005bb5;
}
결과 화면
잰 값개발자 도구에서 본 값
  • 지금 포커스의 읽는 이름찾기
  • button의 :focus-visible켜짐
  • button의 outline-stylesolid

3포커스 표시는 outline으로 바꾼다

포커스 표시는 윤곽선(outline — 자료에 따라 외곽선)으로 바꿉니다. 윤곽선은 요소 둘레에 덧그릴 뿐 요소가 차지하는 자리에 들지 않아, 굵게 그려도 옆 요소를 밀지 않습니다(차지하는 자리는 10단원 '박스 모델'에서 자세히).

지우기만 하면 키보드로 옮긴 자리가 보이지 않습니다. 키보드만 쓰는 사람은 지금 어디에 있는지 모른 채 Enter를 누르게 됩니다.

<button>보내기</button>
button:focus {
  outline: none;
}
결과 화면
잰 값개발자 도구에서 본 값
  • button의 :focus-visible켜짐
  • button의 outline-stylenone

Tab으로 왔는데도 윤곽선이 없습니다. 이 규칙을 지우면 크롬 기본 스타일의 윤곽선이 돌아오고, 모양을 바꾸려면 윤곽선을 없애지 말고 :focus-visible 규칙에 새 윤곽선을 줍니다.

상태로 고르는 규칙은 그 상태일 때만 Styles 창에 보입니다. 그런데 개발자 도구를 누르면 포커스가 페이지에서 개발자 도구로 옮겨 가, 단추를 골라도 button:focus 규칙이 창에 없습니다. 이때는 Styles 창 맨 위 줄의 :hov 단추를 누르고 :focus와 :focus-visible 체크박스를 켭니다. 켠 상태는 실제로 그 상태가 아니어도 켜진 것으로 쳐서, button:focus 규칙과 기본 스타일의 :focus-visible 윤곽선 선언이 함께 보입니다. 마우스를 올린 상태는 :hover를 켜고 봅니다.

예제

레시피 노트 내비게이션 — 마우스와 키보드 둘 다

마우스를 올리면 밑줄, 키보드로 오면 파랑 윤곽선이 보이게 합니다.

<nav>
  <a href="index.html">목록</a>
  <a href="#steps">조리 순서</a>
</nav>
nav a {
  color: #1d1d1f;
  text-decoration: none;
}

nav a:hover {
  text-decoration: underline;
}

nav a:focus-visible {
  outline: 2px solid #005bb5;
}
결과 화면
잰 값개발자 도구에서 본 값
  • 지금 포커스의 읽는 이름목록
  • a[href="index.html"]의 outline-stylesolid
  • a[href="index.html"]의 text-decoration-linenone
  • nav a: 평소 모양 — 본문 글자색, 밑줄 없음입니다.
  • nav a:hover: 가상 클래스도 붙여 쓰는 조건이라 'nav 안의 링크이면서 마우스가 올라온 것'을 고릅니다.
  • nav a:focus-visible: Tab으로 '목록'에 오자 윤곽선이 켜졌습니다. 마우스가 없으니 밑줄은 없습니다 — 두 상태는 따로 켜집니다.

자주 틀리는 곳

틀린 생각: 마우스를 올려야 보이는 표시도 누구나 본다.

<p>
  재료는
  <a href="#rice">밥</a>부터
  씁니다.
</p>
a {
  color: #1d1d1f;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}
결과 화면
잰 값개발자 도구에서 본 값
  • a의 글자색rgb(29, 29, 31)
  • a의 text-decoration-linenone

마우스를 올리기 전에는 링크가 본문 글과 똑같습니다. 휴대전화 · 태블릿처럼 마우스가 없는 기기에서는 올릴 수 없으니 링크인 줄 모릅니다(누르는 순간 잠깐 :hover가 켜지기도 하지만 기기마다 다릅니다).

맞는 규칙: :hover는 덤으로만 씁니다. 링크라는 표시처럼 꼭 보여야 할 것은 상태 없이도 보이게 둡니다.

틀린 생각: :focus와 :focus-visible은 같다.

<button>찾기</button>
button:focus {
  outline: 3px solid #005bb5;
}
결과 화면
잰 값개발자 도구에서 본 값
  • button의 outline-stylesolid

:focus는 마우스로 누를 때도 켜져, 누를 때마다 단추에 굵은 윤곽선이 남습니다. 이것이 보기 싫어 outline: none으로 지우면 키보드 쓰는 사람의 표시까지 사라집니다.

맞는 규칙: :focus는 포커스가 있으면 늘, :focus-visible은 표시가 필요할 때만 고릅니다. 포커스 표시는 :focus-visible에 줍니다(브라우저 규칙 4).

틀린 생각: 포커스 표시는 윤곽선을 지우고 border로 그려도 같다.

<nav>
  <a href="index.html">목록</a>
  <a href="#steps">조리 순서</a>
</nav>
a:focus-visible {
  outline: none;
  border: 3px solid #005bb5;
}
결과 화면
잰 값개발자 도구에서 본 값
  • a의 border-left-width3px
  • a의 outline-stylenone

Tab으로 '목록'에 오면 좌우 테두리 3px씩 링크가 6px 넓어지고, 옆 '조리 순서'가 그만큼 오른쪽으로 밀립니다. 결과 화면에서 Tab을 눌러 보세요. outline으로 그리면 링크 너비가 그대로입니다.

맞는 규칙: 테두리는 요소가 차지하는 자리에 들어 이웃을 밀고, 윤곽선은 들지 않습니다. 포커스 표시는 outline으로 그립니다.

확인 문제

1. 1절 예제의 nav a:hover를 nav:hover a로 바꿨습니다. 마우스를 '목록' 링크에 올리면 밑줄이 생기는 링크를 모두 고르세요. 기호를 다 쓰세요.

<nav>
  <a href="index.html">목록</a>
  <a href="#steps">조리 순서</a>
</nav>
nav a {
  text-decoration: none;
}

nav:hover a {
  text-decoration: underline;
}
  • ㉠ a 목록
  • ㉡ a 조리 순서
  • ㉢ 없음
힌트

:hover가 붙은 조각이 nav인지 a인지 보세요.

힌트 둘

'목록'에 마우스가 올라와 있을 때 nav가 :hover인지 1절 끝 문단에서 찾아보세요.

정답

㉠ ㉡ — 두 링크 모두입니다.

결과 화면
잰 값개발자 도구에서 본 값
  • a[href="index.html"]의 text-decoration-lineunderline
  • a[href="#steps"]의 text-decoration-lineunderline
  • 마우스가 '목록'에 올라오면 그 조상 nav도 :hover입니다. nav:hover a는 ':hover인 nav 안의 링크'라 두 링크를 모두 고릅니다(브라우저 규칙 4).
  • 흔한 오답은 ㉠만입니다. :hover가 링크에 붙어 있다고 읽은 것입니다. 가상 클래스는 바로 앞 조각(nav)의 조건입니다.

2. 글자 칸에 포커스가 있는 동안 배경색을 바꾸려 합니다. ____ 자리를 채우세요.

input____ {
  background-color: #f5f5f7;
}
힌트

2절 표에서 글자 칸 줄을 보세요.

정답

:focus

<label for="q">검색</label>
<input id="q" type="text" />
input:focus {
  background-color: #f5f5f7;
}
결과 화면
잰 값개발자 도구에서 본 값
  • #q의 background-colorrgb(245, 245, 247)

다르게 써도 되는 곳: :focus-visible도 됩니다. 글자 칸은 마우스로 눌러도 Tab으로 와도 :focus-visible이 켜져, 크롬에서는 둘이 같게 고릅니다.

  • input :focus처럼 콜론 앞에 빈칸을 두면 'input 안에서 포커스가 있는 요소'가 되어 아무것도 고르지 않습니다. 가상 클래스는 붙여 씁니다.

3. 동아리 가입 페이지입니다. 키보드로 '보내기' 단추에 왔는데 지금 어디에 있는지 보이지 않습니다. 단추를 고르고 :hov에서 :focus와 :focus-visible을 켜니 Styles 창에 아래 규칙이 보입니다. 마우스로 누를 때는 윤곽선이 없고, 키보드로 왔을 때만 파랑 윤곽선이 보이게 고치세요.

<label for="mail">메일</label>
<input id="mail" type="email" />
<button>보내기</button>
button:focus {
  outline: none;
}
결과 화면
힌트

이 규칙이 고르는 상태와 그 선언을 하나씩 보세요. 2절 표의 단추 줄도 견줘 보세요.

정답

선택자를 button:focus-visible로 바꾸고, 선언을 윤곽선으로 바꿉니다.

<label for="mail">메일</label>
<input
  id="mail"
  type="email"
/>
<button>보내기</button>
button:focus-visible {
  outline: 3px solid #005bb5;
}
결과 화면
잰 값개발자 도구에서 본 값
  • 지금 포커스의 읽는 이름보내기
  • button의 outline-stylesolid
  • outline: none을 준 button:focus 규칙은 키보드로 왔을 때도 윤곽선을 지웁니다. 찾는 차례 4번 '닿았으면 알아들었나 · 이겼나'에서 이 선언이 이겨, 기본 스타일 :focus-visible 규칙의 outline 선언에 취소선이 그어진 것이 보입니다.
  • :focus-visible은 단추에 키보드로 왔을 때만 켜져, 마우스로 누를 때는 윤곽선이 없습니다. 규칙을 지우기만 해도 키보드 표시는 돌아오지만(크롬 기본 스타일의 윤곽선), 색을 정하려면 이렇게 씁니다.
  • 다르게 써도 되는 곳: button:focus 규칙을 둔 채 그 아래에 button:focus-visible 규칙을 더해도 됩니다. 키보드로 오면 두 규칙이 다 닿고, 두 선택자의 무게가 같아 뒤에 쓴 규칙이 이깁니다(9단원 명시도 · 나중에 쓴 규칙). 위에 더하면 뒤의 outline: none이 이겨 윤곽선이 없습니다.
  • button:focus에 윤곽선을 주는 답은 마우스로 누를 때도 윤곽선이 남습니다 — 물음의 '마우스로 누를 때는 윤곽선이 없고'를 못 지킵니다.

컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요. 예제의 HTML과 CSS를 style 요소로 한 파일에 담아 nav.html로 저장해 엽니다. Tab으로 링크를 옮겨 다니며 윤곽선을 본 뒤, outline 줄을 지우면 어떻게 될지 먼저 적고 저장하고 새로고침해 맞춰 봅니다. 그다음 outline: none;으로 바꿔 다시 Tab을 눌러 봅니다. 끝으로 Elements 패널에서 '목록' 링크를 고르고 :hov에서 :focus-visible을 켜, outline: none에 진 기본 스타일의 outline 선언을 Styles 창에서 찾아봅니다.

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

HTML·CSS 목차로