해결 방법 :has(): 긴 형식 텍스트의 세로 간격

해결 방법 :has(): 긴 형식 텍스트의 세로 간격

많은 사이트에서 일한 적이 있다면 긴 형식의 텍스트 — 특히 사람들이 WYSIWYG 편집기에서 텍스트 스크리드를 입력할 수 있는 CMS 사이트 — 제목, 단락, 목록 등과 같은 다양한 타이포그래피 요소 사이의 세로 간격을 관리하기 위해 CSS를 작성해야 했을 것입니다.

이 문제를 해결하는 것은 의외로 까다롭습니다. Tailwind Typography 플러그인과 Stack Overflow의 Prose가 존재하는 이유 중 하나입니다. 이러한 플러그인은 수직 간격보다 훨씬 더 많은 것을 처리합니다.

파이어폭스 지원 :has() 뒤에 layout.css.has-selector.enabled 플래그 in about:config 쓰기의 때에.

타이포그래피 세로 간격을 복잡하게 만드는 것은 무엇입니까?

확실히 그것은 각 요소가 다음과 같이 말하는 것처럼 간단해야 합니다. p, h2, ul, 등 — 위쪽 및/또는 아래쪽 여백이 어느 정도 있습니다… 맞습니까? 안타깝게도 그렇지 않습니다. 이 원하는 동작을 고려하십시오.

  • 긴 형식의 텍스트 블록에서 첫 번째 요소와 마지막 요소에는 위나 아래에 추가 공간이 있어서는 안 됩니다(각각). 이는 다른 비활자 요소가 긴 형식 콘텐츠 주위에 여전히 예측 가능하게 배치되도록 하기 위한 것입니다.
  • 긴 형식의 콘텐츠 내의 섹션은 그들 사이에 멋진 큰 공간이 있어야 합니다. "섹션"은 제목과 해당 제목에 속하는 모든 다음 콘텐츠입니다. 실제로 이것은 제목 앞에 멋진 큰 공간이 있음을 의미하지만… 지원 해당 제목 바로 앞에 다른 제목이 있는 경우!
단락 뒤에 나오는 제목 3과 제목 2 뒤에 오는 다른 제목의 예.
제목 3이 단락과 같은 활자체 요소 뒤에 오는 경우에는 더 많은 공간을 원하지만 다른 제목 바로 뒤에 오는 경우에는 더 적은 공간을 원합니다.

이것이 유용한 곳을 보려면 바로 여기 CSS-Tricks에서 더 이상 볼 필요가 없습니다. 다음은 다른 기사에서 가져온 간격에 대한 몇 가지 스크린샷입니다.

제목 2 바로 위에 있는 제목 3 요소.
제목 2와 제목 3 사이의 세로 간격
단락 요소 바로 뒤에 오는 제목 3 요소.
제목 3과 단락 사이의 세로 공간

전통적인 솔루션

내가 본 일반적인 솔루션은 긴 형식의 콘텐츠를 래핑에 넣는 것입니다. div (또는 적절한 경우 시맨틱 태그). 내가 다니는 수업 이름은 .rich-textWYSIWYG 콘텐츠를 렌더링할 때 이 클래스를 자동으로 추가하는 Wagtail CMS의 이전 버전에서 숙취로 사용한다고 생각합니다. 순풍 타이포그래피 ~을 사용하다 .prose 수업 (일부 한정자 클래스 추가).

그런 다음 CSS를 추가하여 해당 래퍼의 모든 인쇄 요소를 선택하고 세로 여백을 추가합니다. 물론 위에서 언급한 누적된 제목 및 첫 번째/마지막 요소와 관련된 특수 동작에 주목하십시오.

전통적인 솔루션은 합리적으로 들립니다. 문제가 무엇입니까? 나는 몇 가지가 있다고 생각합니다…

단단한 구조

다음과 같은 래퍼 클래스를 추가해야 합니다. .rich-text in all right place는 HTML 코드에 특정 구조를 적용하는 것을 의미합니다. 때로는 필요하지만 이 특별한 경우에는 필요하지 않은 것처럼 느껴집니다. 특히 CMS와 하드 코딩된 콘텐츠의 혼합에 사용해야 하는 경우 필요한 모든 곳에서 이 작업을 수행하는 것을 잊기 쉽습니다.

래퍼 요소의 직계 자식이어야 하기 때문에 첫 번째 요소와 마지막 요소 각각에서 위쪽 및 아래쪽 여백을 잘라낼 수 있기를 원할 때 HTML 구조는 훨씬 더 엄격해집니다. .rich-text > *:first-child. 그 > 중요합니다. 결국 우리는 각각의 첫 번째 목록 항목을 실수로 선택하는 것을 원하지 않습니다. ul or ol 이 선택기로.

혼합 마진 속성

사전에:has() 우리는 그 뒤에 오는 것을 기반으로 요소를 선택하는 방법이 없었습니다. 따라서 타이포그래피 요소의 간격을 두는 전통적인 접근 방식은 두 요소를 혼합하여 사용하는 것입니다. margin-topmargin-bottom:

  1. 요소에 기본 간격을 설정하는 것으로 시작합니다. margin-bottom.
  2. 다음으로 다음을 사용하여 "섹션"의 간격을 둡니다. margin-top — 즉, 각 제목 위의 매우 큰 공간
  3. 그런 다음 우리는 큰 margin-top인접한 형제 선택자를 사용하여 다른 제목이 바로 뒤에 오는 경우(예: h2 + h3).

자, 나는 당신에 대해 모르지만 항상 간격을 둘 때 단일 여백 방향을 사용하는 것이 더 낫다고 느꼈습니다. margin-bottom (그것은 가정 CSS gap 재산 이 경우에는 불가능합니다.) 이것이 큰 일인지 아니면 사실인지는 당신이 결정하게 할 것입니다. 하지만 개인적으로 margin-bottom 긴 형식 콘텐츠의 간격을 지정합니다.

여백 축소

때문에 여백 축소, 이러한 상단 및 하단 여백의 혼합은 그 자체로는 큰 문제가 아닙니다. 두 개의 누적 여백 중 더 큰 여백만 적용되며 두 여백의 합은 적용되지 않습니다. 하지만…

축소 마진은 아직 알아야 할 또 하나의 사항입니다. 해당 CSS 특성에 익숙하지 않은 주니어 개발자에게는 혼란스러울 수 있습니다. 래퍼를 flex 레이아웃 flex-direction: column 예를 들어 세로 여백을 한 방향으로 설정하면 발생하지 않는 일입니다.

축소 여백이 작동하는 방식을 어느 정도 알고 있으며 의도적으로 존재한다는 것도 알고 있습니다. 나는 또한 그들이 때때로 내 삶을 더 쉽게 만들어 주었다는 것을 압니다. 그러나 그들은 다른 경우에도 더 어렵게 만들었습니다. 나는 그들이 좀 이상하다고 생각하고 일반적으로 그들에게 의존하는 것을 피하고 싶습니다.

XNUMXD덴탈의 :has() 해결책

그리고 여기에 이러한 문제를 해결하려는 시도가 있습니다. :has().

개선 사항을 요약하면 다음과 같습니다.

  • 래퍼 클래스가 필요하지 않습니다.
  • 우리는 함께 일하고 있습니다 일관된 마진 방향.
  • 축소 마진이 방지됩니다(입장에 따라 개선될 수도 있고 그렇지 않을 수도 있음).
  • 설정 스타일이 없으며 즉시 재정의합니다.

에 대한 참고 사항 및 주의 사항 :has() 해결책

  • 항상 브라우저 지원을 확인하십시오. 글을 쓰는 시점에서 파이어폭스만 지원 :has() 실험적인 깃발 뒤에.
  • 내 솔루션에는 가능한 모든 인쇄 요소가 포함되어 있지 않습니다. 예를 들어 <blockquote> 내 데모에서. 선택기 목록은 확장하기가 쉽습니다.
  • 내 솔루션은 활자체가 아닌 요소도 처리하지 않습니다. 예를 들어 특정 긴 형식의 텍스트 블록에 있을 수 있습니다. <img>. 내가 작업하는 사이트의 경우 제목, 단락 및 목록과 같은 핵심 텍스트 노드에 WYSIWYG를 최대한 잠그는 경향이 있기 때문입니다. 예를 들어 인용문, 이미지, 표 등은 별도의 CMS 구성 요소 블록이며 이러한 블록 자체는 페이지에 렌더링될 때 서로 떨어져 있습니다. 그러나 다시 선택기 목록을 확장할 수 있습니다.
  • 만 포함시켰습니다 h1 완전성을 위해. 나는 보통 CMS 사용자가 h1 WYSIWYG를 통해 페이지 제목이 CMS 페이지 편집기에 입력되지 않고 페이지 템플릿 어딘가에 구워지기 때문입니다.
  • 동일한 수준의 제목(h2 + h2). 이것은 첫 번째 제목이 어떤 콘텐츠도 "소유"하지 않는다는 것을 의미하며, 이는 제목을 잘못 사용한 것처럼 보입니다(그리고 제가 틀렸다면 정정해 주십시오. 하지만 수도 위반하다 WCAG 1.3.1 정보 및 관계). 또한 유효하지 않은 건너뛴 제목 수준을 제공하지 않습니다.
  • 나는 내가 언급한 기존 접근 방식을 결코 노크하지 않습니다. 또 다른 Tailwind 사이트를 구축한다면 우수한 Typography 플러그인을 사용할 것입니다. 의심할 여지가 없습니다!
  • 저는 디자이너가 아닙니다. 나는 그것을 주시함으로써 이러한 간격 값을 생각해 냈습니다. 아마도 더 나은 값을 사용할 수 있고 사용해야 합니다.

특이성 및 프로젝트 구조

나는 여기서 전통적인 방법과 새로운 :has() 그것을하는 방법은 ITCSS 방법론… 하지만 이제 우리는 :where() (특이성이 XNUMX인 선택기) 이제 모든 선택기에 대해 선호하는 특정 수준을 선택할 수 있습니다.

즉, 우리가 더 이상 래퍼를 다루지 않는다는 사실은 — .prose, .rich-text, 등 — 나에게 이것이 "요소" 계층에 있어야 한다고 느끼게 합니다. 즉, 클래스 수준의 특이성을 다루기 전에 말입니다. 나는 사용했다 :where() 내 예에서 특이성을 일관되게 유지합니다. 두 예제의 모든 선택기는 특이성 점수 of 0,0,1 (베어 본 재설정 제외).

최대 포장

그래서 당신은 매우 지루한 문제에 대한 최첨단 솔루션을 가지고 있습니다! 이 새로운 접근 방식은 여전히 ​​"단순" CSS라고 부르는 것이 아닙니다. 처음에 말했듯이 처음에 생각했던 것보다 더 복잡한 주제입니다. 그러나 몇 가지 약간 복잡한 선택자를 제외하고는 새로운 접근 방식이 전반적으로 더 적합하고 덜 엄격한 HTML 구조가 매우 매력적으로 보입니다.

당신이 이것 또는 이와 유사한 것을 사용하게 된다면, 그것이 당신에게 어떻게 작용하는지 알고 싶습니다. 그리고 당신이 그것을 개선할 수 있는 방법을 생각할 수 있다면, 나는 그것들도 듣고 싶습니다!

타임 스탬프 :

더보기 CSS 트릭