Tailwind CSS Academy · 강의

외곽선과 링 유틸리티

ring-* 유틸리티로 접근성을 고려한 포커스 표시기를 추가합니다. 이 표시기는 요소 바깥에 렌더링되어 레이아웃에 영향을 주지 않습니다.

레슨 4/413개 단계

외곽선과 링 유틸리티은(는) CoddyKit의 무료 Tailwind CSS Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Tailwind CSS Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Tailwind CSS Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

Why Outlines and Rings Matter

When users navigate with a keyboard or screen reader, visible focus indicators are essential for knowing which element is active. Browsers provide a default focus outline, but many designers suppress it with outline-none without providing an accessible replacement. Tailwind's ring-* utilities are designed precisely for this — they create visible, accessible focus indicators that look better than the browser default without sacrificing accessibility.

<!-- Accessible focus ring replacing browser default -->
<button class="bg-blue-500 text-white px-4 py-2 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
  Press Tab to focus me
</button>

How Ring Utilities Work

Tailwind's ring is implemented using box-shadow, not the CSS outline property. This means it participates in shadow stacking and can be combined with other box shadows. The ring-* utilities set the ring width, ring-{color} sets the color, and ring-offset-* adds a gap between the element and the ring. Unlike outlines, rings do not affect layout and work correctly with border-radius.

<!-- Ring details: width + color + offset -->
<div class="flex gap-6 p-6">
  <!-- Width only -->
  <button class="bg-gray-200 px-4 py-2 rounded focus:ring-2 focus:outline-none">
    Ring width 2
  </button>
  <!-- Width + color -->
  <button class="bg-gray-200 px-4 py-2 rounded focus:ring-2 focus:ring-blue-500 focus:outline-none">
    Colored ring
  </button>
  <!-- Width + color + offset -->
  <button class="bg-gray-200 px-4 py-2 rounded focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:outline-none">
    Ring with offset
  </button>
</div>

Ring Width Utilities

Ring widths range from ring-0 (no ring) to ring-8 (8px). The most commonly used values are ring-1, ring-2, and ring-4. A ring-2 creates a noticeable but not overwhelming focus indicator. Note that unlike border-*, there is no directional control — rings always surround the entire element on all sides.

<!-- Ring width scale -->
<div class="flex gap-4 flex-wrap p-6">
  <div class="w-16 h-16 bg-white rounded-lg ring-1 ring-blue-500 flex items-center justify-center text-xs">ring-1</div>
  <div class="w-16 h-16 bg-white rounded-lg ring-2 ring-blue-500 flex items-center justify-center text-xs">ring-2</div>
  <div class="w-16 h-16 bg-white rounded-lg ring-4 ring-blue-500 flex items-center justify-center text-xs">ring-4</div>
  <div class="w-16 h-16 bg-white rounded-lg ring-8 ring-blue-500 flex items-center justify-center text-xs">ring-8</div>
</div>

Ring Color and Opacity

Set the ring's color with ring-{color}-{shade}, such as ring-indigo-500 or ring-green-400. The ring color should have sufficient contrast with both the element background and the page background. You can also apply opacity with the slash modifier: ring-blue-500/50 for a semi-transparent ring. This creates a softer glow effect while still maintaining adequate visibility.

<!-- Semantic ring colors for different states -->
<div class="space-y-3 max-w-xs">
  <input class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Default focus" />
  <input class="w-full border border-green-300 rounded-lg px-4 py-2 ring-2 ring-green-400" placeholder="Success state" />
  <input class="w-full border border-red-300 rounded-lg px-4 py-2 ring-2 ring-red-400" placeholder="Error state" />
</div>

ring-offset and ring-offset-color

ring-offset-* adds white space between the element's border and the ring, making the ring visually distinct from the element itself. ring-offset-2 is the most common value, creating a 2px gap. By default the offset is white — on colored backgrounds, match it with ring-offset-blue-600 to fill the gap with the background color instead of white, maintaining the visual separation.

<!-- ring-offset creating visual separation -->
<div class="flex gap-4 items-center p-6">
  <!-- On white: default white offset looks great -->
  <button class="bg-blue-500 text-white px-4 py-2 rounded-lg ring-2 ring-blue-500 ring-offset-2">
    White bg offset
  </button>

  <!-- On colored bg: match offset to background -->
  <div class="bg-blue-600 p-4 rounded-xl">
    <button class="bg-white text-blue-600 px-4 py-2 rounded-lg ring-2 ring-white ring-offset-2 ring-offset-blue-600">
      Colored bg offset
    </button>
  </div>
</div>

ring-inset for Inner Rings

ring-inset draws the ring on the inside of the element instead of the outside, similar to shadow-inner. This is useful when an outer ring would conflict with adjacent elements or overflow a clipped container. Inner rings are also visually distinct — they convey a selected or active state rather than a focused state, making them useful for toggle components and active tabs.

<!-- Inner ring for active/selected states -->
<div class="flex gap-3">
  <!-- Selected card with inner ring -->
  <div class="bg-blue-50 border border-blue-200 rounded-xl p-4 ring-2 ring-inset ring-blue-500 cursor-pointer">
    <div class="font-semibold text-blue-700">Basic Plan</div>
    <div class="text-sm text-blue-600">$9/month</div>
  </div>

  <!-- Unselected card -->
  <div class="bg-white border border-gray-200 rounded-xl p-4 cursor-pointer hover:border-gray-300">
    <div class="font-semibold">Pro Plan</div>
    <div class="text-sm text-gray-500">$29/month</div>
  </div>
</div>

The outline-* Utilities

Tailwind also provides utilities for the CSS outline property. While rings are usually preferred for focus styles, native outlines have one unique advantage: they are not affected by overflow-hidden — they render outside clipped containers. outline-none removes the browser default, while outline, outline-2, and outline-dashed add styled outlines.

<!-- outline utilities -->
<div class="space-y-3 max-w-xs">
  <!-- Remove default outline (bad practice alone!) -->
  <button class="w-full bg-gray-200 p-2 rounded focus:outline-none">outline-none (no focus!)</button>

  <!-- Custom outline -->
  <button class="w-full bg-gray-200 p-2 rounded outline outline-2 outline-blue-500">
    outline-2 outline-blue-500
  </button>

  <!-- Dashed outline -->
  <button class="w-full bg-gray-200 p-2 rounded outline outline-dashed outline-2 outline-gray-400">
    outline-dashed
  </button>
</div>

outline-offset Utility

outline-offset-* controls the gap between the element's border and its outline, just like ring-offset-* does for rings. Positive values push the outline outward, negative values draw it inward. This utility is useful for creating distinctive focus styles that maintain spacing from the element's edge without affecting layout (outlines are layout-inert in CSS).

<!-- outline-offset creates space between element and outline -->
<div class="flex gap-6 p-6">
  <button class="bg-blue-500 text-white px-4 py-2 rounded outline outline-2 outline-blue-500 outline-offset-0">
    offset-0
  </button>
  <button class="bg-blue-500 text-white px-4 py-2 rounded outline outline-2 outline-blue-500 outline-offset-2">
    offset-2
  </button>
  <button class="bg-blue-500 text-white px-4 py-2 rounded outline outline-2 outline-blue-500 outline-offset-4">
    offset-4
  </button>
</div>

Best Practice: focus-visible Variant

The focus-visible:ring-* pattern shows focus rings only for keyboard navigation, not mouse clicks. This resolves the UX conflict between designers (who dislike visible rings on mouse clicks) and accessibility requirements (which require visible focus for keyboard users). Always prefer focus-visible:ring-2 over focus:ring-2 in modern Tailwind projects.

<!-- focus-visible: best practice for modern a11y -->
<div class="flex gap-4">
  <!-- Ring shows for keyboard, hidden for mouse -->
  <button class="bg-blue-500 text-white px-4 py-2 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2">
    Smart Focus Ring
  </button>

  <!-- Compare: always visible on any focus -->
  <button class="bg-gray-500 text-white px-4 py-2 rounded-lg focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2">
    Always Visible Ring
  </button>
</div>

Rings in Interactive Components

Rings shine in complex interactive patterns. Checkbox and radio button custom implementations, multi-select tags, and color pickers all use rings to show selection state clearly. Here is a color picker pattern where the selected swatch shows an inset ring indicator — a common pattern in color palette selectors and theme pickers.

<!-- Color picker with ring-based selection indicator -->
<div class="flex gap-3">
  <!-- Selected: shows inset ring -->
  <button class="w-10 h-10 rounded-full bg-blue-500 ring-2 ring-blue-500 ring-offset-2" aria-label="Blue (selected)"></button>
  <!-- Unselected swatches -->
  <button class="w-10 h-10 rounded-full bg-purple-500 hover:ring-2 hover:ring-purple-500 hover:ring-offset-2 transition-all" aria-label="Purple"></button>
  <button class="w-10 h-10 rounded-full bg-green-500 hover:ring-2 hover:ring-green-500 hover:ring-offset-2 transition-all" aria-label="Green"></button>
  <button class="w-10 h-10 rounded-full bg-red-500 hover:ring-2 hover:ring-red-500 hover:ring-offset-2 transition-all" aria-label="Red"></button>
</div>

Combining Ring, Shadow, and Border

Since rings are implemented with box-shadow, you can combine them with Tailwind's other shadow utilities by listing both the shadow and ring classes. The box-shadow property stacks multiple values. This allows a card to have an elevation shadow and a focus ring simultaneously, ensuring the interactive affordance does not eliminate the visual depth.

<!-- Card that keeps its shadow AND gets a ring on focus -->
<div class="p-6">
  <button class="w-full text-left bg-white rounded-xl shadow-md border border-gray-200 p-5 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 hover:shadow-lg transition-shadow">
    <h3 class="font-bold">Clickable Card</h3>
    <p class="text-gray-500 text-sm mt-1">Has shadow + focus ring when keyboard focused.</p>
  </button>
</div>

Quick Check

Test your understanding of Tailwind CSS Mastery concepts from this lesson.

Lesson Recap

In this lesson you learned: ring-* utilities create accessible focus indicators using box-shadow without affecting layout, ring-offset-* adds visual separation between the element and its focus ring, and focus-visible:ring-* is the modern best practice that shows rings for keyboard users only. Next up we explore hover and active state variants for interactive styling.

무료로 시작

AI 튜터와 함께 HTML을(를) 배우세요 — 무료

브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.

코스
30
레슨
120

자주 묻는 질문

“외곽선과 링 유틸리티” 강의는 무료인가요?

네 — “외곽선과 링 유틸리티” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Tailwind CSS Academy 강의 전체를 잠금 해제할 수 있습니다. Tailwind CSS Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“외곽선과 링 유틸리티”에서 뭘 배우나요?

ring-* 유틸리티로 접근성을 고려한 포커스 표시기를 추가합니다. 이 표시기는 요소 바깥에 렌더링되어 레이아웃에 영향을 주지 않습니다. 브라우저에서 직접 실행하는 실습 코드로 Tailwind CSS Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Tailwind CSS Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Tailwind CSS Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“외곽선과 링 유틸리티” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Tailwind CSS Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Tailwind CSS Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 테두리 두께와 색상
  2. 테두리 반경과 둥근 모서리
  3. 상자 그림자
  4. 외곽선과 링 유틸리티
← Tailwind CSS Academy(으)로 돌아가기