본문 바로가기
css

CSS 그리드 내의 확장 가능한 섹션

by code-box 2021. 10. 19.
반응형

난 CSS 그리드가 좋아. 저는 몇 줄의 코드만으로도 미디어 질의 없이 완벽하게 반응하는 그리드 레이아웃을 만들 수 있는 방법이 마음에 듭니다. HTML 마크업을 깔끔하고 단순하게 유지하면서 흥미로운 레이아웃을 만들기 위해 CSS 그리드와 논쟁하는 것이 편합니다.

하지만 최근에, 저는 풀어야 할 독특한 UI 난제를 받았습니다. 기본적으로, 주어진 그리드 셀에는 그리드의 일부인 다른 더 큰 영역을 열 수 있는 버튼이 있을 수 있습니다. 그러나 이 보다 큰 그리드 셀은 다음과 같아야 했습니다.

  • 그것을 열었던 세포 바로 아래에, 그리고
  • 전폭의

CSS 그리드의 정신에 따라 좋은 해결책이 있다는 것이 밝혀졌습니다. 단지 몇줄의 코드만 사용했을 뿐이죠. 이 기사에서는 이 문제를 해결하기 위해 세 개의 한 줄 CSS 그리드 "트릭"을 결합하겠습니다. JavaScript가 전혀 필요하지 않습니다.

내가 풀어야 할 실제 문제에 대한 설명

 

다음은 미니멀리즘 UI의 예입니다.

다음은 스토리북 구성 요소 라이브러리에 렌더링된 실제 제품 카드 그리드입니다.

각 제품 카드를 클릭하면 다음과 같은 새로운 "빠른 보기" 버튼이 추가되었습니다.

  • 클릭된 제품 카드 바로 아래에 새로운 전체 너비 카드(더 자세한 제품 정보 포함)를 동적으로 "수신"합니다.
  • 기존 카드 그리드를 중단하지 않고(즉, 브라우저에 렌더링된 카드의 DOM 소스 순서와 시각적 순서를 유지)
  • 반응이 좋다
 

음… 이것이 현재의 CSS 그리드 구현으로도 가능했을까요?

특히 브라우저 크기를 조정할 때 카드 위치를 다시 계산하고 이동하기 위해 자바스크립트에 의존해야 합니까? 그렇죠?

구글은 내 친구가 아니었다. 나는 나를 도와줄 어떤 것도 찾을 수 없었다. "빠른 보기" 구현 검색에서도 모듈이나 오버레이를 사용하여 삽입된 카드를 렌더링하는 예만 나왔습니다. 결국, 모달은 페이지의 나머지 부분을 방해할 필요 없이 새로운 콘텐츠에 사용자를 집중시키기 때문에 이와 같은 상황에서는 일반적으로 유일한 선택이다.

저는 그 문제에 대해 깊이 생각해봤고, 결국 CSS 그리드의 가장 강력하고 유용한 기능들을 결합함으로써 실행 가능한 해결책을 찾았습니다.

CSS 그리드 트릭 #1

 

저는 이미 우리의 기본 그리드 시스템에 첫 번째 트릭을 사용하고 있었고, 제품 카드 그리드는 그 접근법의 특정 사례입니다. 다음은 몇 가지(간체) 코드입니다.

.grid {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(auto-fit, 20rem);
}
.grid {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(auto-fit, 20rem);
}
The “secret sauce” in this code is the `grid-template-columns: repeat(auto-fit, 20rem);` which gives us a grid with columns (`20rem` wide in this example) that are arranged automatically in the available space, wrapping to the next row when there’s not enough room.
Curious about `auto-fit` vs `auto-fill`? Sara Soueidan has written a wonderful explanation of how this works. Sara also explains how you can incorporate `minmax()` to enable the column widths to “flex” but, for the purposes of this article, I wanted to define fixed column widths for simplicity.
 

CSS 그리드 트릭 #2

다음으로, 새로운 전체 너비 카드를 그리드에 넣어야 했습니다.

.fullwidth {
    grid-column: 1 / -1;
}
.fullwidth {
    grid-column: 1 / -1;
}
This code works because `grid-template-columns` in trick #1 creates an “explicit” grid, so it’s possible to define start and end columns for the `.fullwidth` card, where `1 / -1` means “start in column 1, and span every column up to the very last one.”
 

잘됐네요. 전폭 카드가 그리드에 주입됐어요. 하지만 이제 전체 너비 이상의 공백이 생겼습니다.

image

CSS 그리드 트릭 #3

공백을 메우기—저는 이전에 가짜 메이슨 방식으로 이 일을 해 본 적이 있습니다.

.grid {
    grid-auto-flow: dense;
}
 
.grid {
    grid-auto-flow: dense;
}

다 됐다! 더 이상 어쩔 수 없다! 필요한 레이아웃이 달성되었습니다.

The `grid-auto-flow` property controls how the CSS Grid auto-placement algorithm works. In this case, the `dense` packing algorithm tries to fills in holes earlier in the grid.
  • 그리드 열은 모두 너비가 같습니다. 조밀한 패킹은 기둥 너비가 유연한 경우에도 작동합니다. 예를 들어, minmax(20rem, 1f)를 사용하여 분석합니다.
  • 모든 그리드 "셀"은 각 행의 높이가 동일합니다. 이것은 기본 CSS 그리드 동작입니다. 그리드 컨테이너에는 암묵적으로 align-items: stretch가 있어 셀이 사용 가능한 행 높이의 100%를 차지합니다.

그 결과 그리드의 구멍이 채워지고 렌더링된 출력물에 원래 소스 순서가 보존됩니다. 이것은 접근성 관점에서 중요하다.

 

CSS 그리드 자동 배치에 대한 자세한 설명은 MDN을 참조하십시오.

완전한 해결책

 

이 세 가지 트릭을 조합하면 매우 적은 CSS를 필요로 하는 간단한 레이아웃 솔루션을 제공합니다. 미디어 쿼리가 없고 JavaScript가 필요하지 않습니다.

하지만 아직 자바스크립트가 필요한가요?

 

예, 저희는 그렇습니다. 그러나 레이아웃 계산에는 해당되지 않습니다. 클릭 이벤트, 포커스 상태, 주입된 카드 디스플레이 등을 관리할 수 있습니다.

프로토타입에서 데모를 위해 전체 너비의 카드는 HTML에서 DOM의 올바른 위치에 하드 코딩되었으며, 자바스크립트는 디스플레이 속성을 간단히 전환합니다.

그러나 실운영 환경에서 주입된 카드는 자바스크립트로 가져와 올바른 위치에 배치될 수 있습니다. eCommerce 사이트의 제품과 같은 제품에 대한 그리드 레이아웃은 매우 무거운 DOM을 가지는 경향이 있으며, 우리는 추가적인 "숨겨진" 콘텐츠로 페이지 무게가 불필요하게 더 부풀어 오르는 것을 방지하고자 합니다.

빠른 보기는 점진적인 향상으로 간주되어야 하므로, 자바스크립트를 로드하지 못할 경우 사용자는 해당 제품 상세정보 페이지로 이동하기만 하면 됩니다.

접근성 고려사항

 
I’m passionate about using correct semantic HTML markup, adding `aria-` properties when absolutely necessary, and ensuring the UI works with just a keyboard as well as in a screen reader.

여기 이 패턴을 최대한 액세스할 수 있도록 하기 위해 고려해야 할 사항들에 대한 요약이 있습니다.

  • 제품 목록을 표시하기 때문에 제품 카드 그리드는 <ul><li> 구조를 사용합니다. 따라서 보조 기술(예: 화면 판독기)은 카드 사이에 관계가 있음을 이해하고 사용자에게 목록에 있는 항목의 수를 알려줍니다.
  • 상품 카드 자체는 적절한 제목 등이 포함된 기사 요소이다.
  • HTML 소스 순서는 .width 카드를 삽입할 때 유지되므로 삽입된 콘텐츠에 자연스러운 탭 순서를 제공하고 다음 카드로 다시 이동합니다.
  • 전체 카드 그리드는 아리아 라이브 지역으로 포장되어 있어 DOM 변경사항이 스크린 리더기에 발표된다.
  • 포커스 관리를 통해 삽입된 카드가 키보드 포커스를 수신하고 카드를 닫을 때 키보드의 포커스가 원래 카드의 가시성을 트리거했던 버튼으로 돌아갑니다.

프로토타입에서는 설명되지 않았지만, 다음과 같은 추가 개선 사항을 모든 프로덕션 구현에 추가할 수 있습니다.

  • 초점을 맞춘 주입 카드에 적절한 라벨이 부착되어 있는지 확인합니다. 이것은 내용 내부의 첫 번째 요소만큼 제목을 갖는 것만큼 간단할 수 있습니다.
  • ESC 키를 바인딩하여 주입된 카드를 닫습니다.
  • 삽입된 카드가 뷰포트 내부에서 완전히 보이도록 브라우저 창을 스크롤합니다.
 

마무리하는 중

So, what do you think?

  This could be a nice alternative to modals for when we want to reveal additional content, but without hijacking the entire viewport in the process. This might be interesting in other situations as well — think photo captions in an image grid, helper text, etc. It might even be an alternative to some cases where we’d normally reach for `<details>`/`<summary>` (as we know those are only best used in certain contexts).

어쨌든, 저는 여러분이 이것을 어떻게 사용할지, 아니면 어떻게 다르게 접근할지에 관심이 있습니다. 댓글로 알려주세요!

업데이트

우선, 저는 이 기사가 다른 프론트엔드 개발자들에게 도움이 된다는 것이 정말 기쁩니다. 나는 비슷한 난제에 직면한 유일한 사람이 나뿐이 아니라는 것을 알았다.

 

둘째, 몇 가지 건설적인 피드백에 따라 위의 특정 접근성 고려사항에 취소선을 추가하고 다음과 같은 변경 사항을 사용하여 CodePen 데모를 업데이트했습니다.

  • 굳이 카드 그리드를 아리아 라이브 지역으로 포장할 필요는 없다. 그 대신 빠른 보기 열기 및 닫기 버튼이 적절한 아리아 확장 및 아리아 제어 특성을 가진 "토글" 버튼처럼 동작하도록 했습니다. 저는 이 패턴을 노출 위젯(표시/숨기기, 탭, 아코디언)에 사용하지만, 이 경우에는 오버레이보다는 인라인이지만 모달 인터페이스와 더 유사한 동작을 상상하고 있었습니다. (팁은 Adrian 덕분입니다!)
  • 나는 더 이상 프로그램적으로 주사된 카드에 초점을 맞추고 있지 않다. 대신 tabindex=0만 추가하면 키보드가 삽입된 카드로 이동할지 말지 선택할 수 있고, 다시 "disclose" 버튼을 닫을 수 있습니다.
  • 나는 여전히 그리드에
    • 구조를 사용하는 것이 제품 카드 목록에 적합한 접근법이라고 생각한다. 제공되는 의미론은 카드 사이의 분명한 관계를 나타냅니다.

댓글