InfoGrab DocsInfoGrab Docs

SCSS 스타일 가이드

요약

사이트가 커질 때 CSS가 더 생성되는 것을 줄이려면, 새 CSS를 추가하기보다 유틸리티 클래스를 사용하는 편이 좋습니다. 유틸리티 클래스는 Tailwind CSS가 생성합니다. common.scss의 클래스는 사용이 중단되고 있습니다.

유틸리티 클래스#

사이트가 커질 때 CSS가 더 생성되는 것을 줄이려면, 새 CSS를 추가하기보다 유틸리티 클래스를 사용하는 편이 좋습니다. 복잡한 경우에는 컴포넌트 클래스를 추가하여 CSS를 처리할 수 있습니다.

CSS 유틸리티 클래스 정의 위치#

유틸리티 클래스는 Tailwind CSS가 생성합니다. Tailwind CSS 클래스를 확인하는 방법은 세 가지입니다.

  • GitLab Tailwind CSS 문서: GitLab Tailwind 구성에 특화된 문서 사이트입니다. 사용할 수 있는 모든 Tailwind CSS 클래스를 검색 가능한 목록으로 제공합니다.
  • Tailwind CSS 자동완성: VS Code 또는 RubyMine에서 사용할 수 있습니다.
  • Tailwind CSS 구성 뷰어: 간격, 색상, 크기처럼 GitLab 디자인 시스템에 특화된 Tailwind CSS 클래스를 시각적으로 보여 줍니다. 사용할 수 있는 모든 Tailwind CSS 클래스를 표시하지는 않습니다.

사용이 중단된 CSS 유틸리티 클래스#

common.scss의 클래스는 사용이 중단되고 있습니다. 디자인 시스템에 없는 값을 사용하는 common.scss의 클래스는 피해야 합니다. 대신 기준에 맞는 값을 쓰는 클래스를 사용합니다.

Bootstrap의 유틸리티 클래스는 피합니다.

Note

Bootstrap의 유틸리티 클래스를 GitLab UI 유틸리티 클래스로 마이그레이션할 때, margin과 padding 클래스가 모두 다르다는 점에 유의합니다. GitLab에서 사용하는 크기 스케일은 Bootstrap 라이브러리의 스케일과 다릅니다. Bootstrap의 padding 또는 margin 유틸리티와 같은 시각적 결과를 얻으려면 적용한 유틸리티의 크기를 두 배로 해야 할 수 있습니다(예를 들어 ml-1은 gl-ml-2가 됩니다).

Tailwind CSS#

2024년 8월부터 CSS 유틸리티 공급자로 Tailwind CSS를 사용합니다. 이는 이전의 자체 제작 솔루션을 대체합니다. 동기, 제안, 구현 세부 사항은 Tailwind CSS 설계 문서를 참고합니다.

Tailwind CSS 기본 사항#

다음은 Tailwind CSS의 기본 사항과, Pajamas 디자인 시스템을 사용하도록 구성한 방식에 대한 정보입니다. 더 자세한 안내는 Tailwind CSS 공식 문서를 참고합니다.

접두사#

Tailwind CSS가 접두사를 사용하도록 구성했으므로 모든 유틸리티 클래스에는 gl- 접두사가 붙습니다. 반응형 유틸리티나 상태 수정자를 사용할 때는 접두사가 콜론 뒤에 옵니다.

예시: gl-mt-5, lg:gl-mt-5.

반응형 CSS 유틸리티 클래스#

반응형 CSS 유틸리티 클래스에는 브레이크포인트 이름 뒤에 : 문자가 붙은 접두사가 붙습니다. 사용할 수 있는 브레이크포인트는 tailwind.defaults.js#L44에 구성되어 있습니다

예시: lg:gl-mt-5

hover, focus 및 기타 상태 수정자#

상태 수정자를 사용하면 모든 Tailwind CSS 클래스를 조건부로 적용할 수 있습니다. CSS 유틸리티 클래스 앞에 수정자 이름을 붙이고 그 뒤에 : 문자를 붙입니다.

예시: hover:gl-underline

!important 수정자#

CSS 유틸리티 클래스 앞에 !를 추가하면 important 수정자를 사용할 수 있습니다. 반응형 유틸리티 클래스나 상태 수정자와 함께 사용할 때는 !가 : 문자 뒤에 옵니다.

예시: !gl-mt-5, lg:!gl-mt-5, hover:!gl-underline

간격 및 크기 CSS 유틸리티 클래스#

간격 및 크기 CSS 유틸리티 클래스(예를 들어 margin, padding, width, height)는 src/tokens/build/tailwind/tokens.cjs에 정의된 간격 스케일을 사용합니다. 사용할 수 있는 CSS 유틸리티 클래스는 https://design.gitlab.com/tailwind-documentation/margin을 참고합니다.

예시: gl-mt-5는 margin-top: 1rem;입니다

색상 CSS 유틸리티 클래스#

색상 CSS 유틸리티 클래스(예를 들어 color와 background-color)는 src/tokens/build/tailwind/tokens.cjs에 정의된 색상을 사용합니다. 사용할 수 있는 CSS 유틸리티 클래스는 https://design.gitlab.com/tailwind-documentation/text-color을 참고합니다.

예시: gl-text-subtle은 color: var(--gl-text-color-subtle, #626168);입니다

Tailwind CSS 번들 빌드#

GitLab Development Kit에서 Vite 또는 Webpack을 사용하면 Tailwind CSS가 파일 변경을 감시하여 감지된 유틸리티를 즉시 빌드합니다.

새 Tailwind CSS 번들을 빌드하려면 yarn tailwindcss:build를 실행합니다. 이 스크립트는 bundle exec rake gitlab:assets:compile로 프로덕션 애셋을 빌드할 때 내부적으로 호출됩니다.

번들을 어떤 방식으로 빌드하든 출력은 app/assets/builds/tailwind.css에 저장됩니다.

Tailwind CSS 자동완성#

Tailwind CSS 자동완성은 코드 편집기에서 사용할 수 있는 모든 클래스를 나열합니다.

VS Code#
Note

자동완성이 느려 문제가 있다면 TS 서버가 사용할 수 있는 메모리 양을 늘려야 할 수 있습니다.

Tailwind CSS IntelliSense 확장을 설치합니다. HAML과 사용자 지정 *-class prop을 지원하려면 다음 설정을 권장합니다.

{
  "tailwindCSS.experimental.classRegex": [
    ["class: [\"|']+([^\"|']*)[\"|']+", "([a-zA-Z0-9\\-:!/]+)"],
    ["(\\.[\\w\\-.]+)[\\n\\=\\{\\s]", "([\\w\\-]+)"],
    ["[a-z]+-class(?:es)?=\"([^'\"]*)\""]
  ],
  "tailwindCSS.emmetCompletions": true
}
RubyMine#

Tailwind CSS 자동완성은 기본적으로 활성화되어 있습니다. HAML과 사용자 지정 *-class prop을 완전히 지원하려면 기본 설정을 다음과 같이 변경하는 것을 권장합니다.

{
  "includeLanguages": {
    "haml": "html"
  },
  "emmetCompletions": true,
  "experimental": {
    "classRegex": [
      ["class: [\"|']+([^\"|']*)[\"|']+", "([a-zA-Z0-9\\-:!/]+)"],
      ["(\\.[\\w\\-.]+)[\\n\\=\\{\\s]", "([\\w\\-]+)"],
      ["[a-z]+-class(?:es)?=\"([^'\"]*)\""]
    ]
  }
}

Tailwind CSS 임의 값#

임의 값은 몇 가지 이유로 피해야 합니다.

  • 한 페이지에서만 필요할 가능성이 높은데도 전역 CSS 번들에 추가되어 번들 크기를 키웁니다. 대신 페이지별 CSS를 사용해 필요한 곳에만 CSS가 포함되도록 합니다.
  • 미리 정의된 CSS 클래스가 이미 있을 가능성이 높습니다. 사용할 수 있는 Tailwind CSS 클래스는 GitLab Tailwind CSS 문서에서 확인합니다.
  • 디자인 시스템을 강제하지 않습니다.

새 유틸리티 클래스를 추가할 위치#

유틸리티 클래스는 대부분의 CSS 기능을 지원하는 Tailwind CSS가 생성합니다. 사용할 수 없는 것이 있으면 GitLab UI의 tailwind.defaults.js를 업데이트해야 합니다.

컴포넌트 클래스를 생성하는 시점#

"utility-first" 접근 방식을 권장합니다.

  1. 유틸리티 클래스로 시작합니다.
  2. 유틸리티 클래스를 컴포넌트 클래스로 조합하면 코드 중복이 없어지고 책임이 명확하게 캡슐화되는 경우에는 그렇게 합니다.

이렇게 하면 컴포넌트 클래스가 자연스럽게 늘어나고, 재사용할 수 없는 일회성 클래스가 만들어지는 것을 막습니다. 또한 "utility-first"에서 나오는 클래스는 도메인 중심(예를 들어 .security-report-widget, .commit-header-icon)이 아니라 디자인 중심(예를 들어 .button, .alert, .card)이 되는 경향이 있습니다.

참고 자료:

HTML과 스타일시트에서 Tailwind CSS 활용#

컴포넌트 클래스를 작성할 때는 디자인 시스템과의 일관성을 유지하고 CSS 번들을 작게 유지하려면 Tailwind CSS의 유틸리티 클래스를 효과적으로 통합하는 것이 중요합니다.

HTML의 유틸리티 CSS 클래스와 스타일시트의 유틸리티 CSS 클래스 비교:

HTML에서 유틸리티 클래스를 직접 사용하면 CSS 파일 크기를 더 작게 유지하고 utility-first 철학을 지킬 수 있습니다. 꼭 필요한 경우가 아니면 한 컴포넌트 클래스 안에서 유틸리티 클래스와 사용자 지정 스타일을 섞지 않음으로써 혼란과 잠재적 충돌을 막을 수 있습니다.

  • 이 방식을 선호하는 이유:
    • 더 작은 CSS 파일 크기: 유틸리티 클래스를 직접 활용하면 CSS 파일이 더 간결해지고 디자인 시스템의 일관성이 높아집니다.
    • 명확성과 유지 관리성: HTML에서 유틸리티 클래스를 사용하면 스타일이 어떻게 적용되는지 더 명확해지고, 충돌과 회귀 위험이 줄어듭니다.
  • 스타일을 섞을 때 생길 수 있는 문제:
    • 충돌: 한 클래스 안에서 유틸리티 클래스와 사용자 지정 스타일을 섞으면, 특히 스타일 사이에 상호 의존성이 있을 때 충돌이 생길 수 있습니다.
    • 회귀: 스타일이 어떻게 결정되어야 하는지 덜 분명해져서 회귀나 예상치 못한 동작이 생길 수 있습니다.

이 지침을 따르면 Tailwind CSS를 효과적으로 활용하는 깔끔하고 유지 관리하기 쉬운 스타일시트를 만들 수 있습니다.

1. HTML에서 유틸리티 클래스 직접 사용(권장 방식)#

유지 관리성을 높이고 utility-first 원칙을 지키려면 유틸리티 클래스를 HTML 요소에 직접 추가합니다. 컴포넌트 클래스에는 기본적으로 유틸리티가 아닌 CSS 스타일만 담습니다. 다음 예시에서는 SCSS 파일에 position: fixed; right: 0; left: 0;을 추가하는 대신 유틸리티 클래스 gl-fixed와 gl-inset-x-0을 추가합니다.

<!-- Bad -->
<div class="my-class"></div>

<style>
  .my-class {
    top: $header-height;
    min-height: $comparison-empty-state-height;
    position: fixed;
    left: 0px;
    right: 0px;
 }
</style>

<!-- Good -->
<div class="my-class gl-fixed gl-inset-x-0"></div>

<style>
  .my-class {
    top: $header-height;
    min-height: $comparison-empty-state-height;
  }
</style>

2. 컴포넌트 클래스에서 유틸리티 클래스 적용(필요한 경우)#

HTML에서 유틸리티 클래스를 직접 사용하는 것이 어려워서 사용자 지정 SCSS 파일에 포함해야 할 때도 있습니다. 그럴 때는 관련 속성이나 값을 직접 찾지 않고도 디자인 시스템의 스타일 정의를 상속하고 싶을 수 있습니다. 이 과정을 단순하게 하려면 Tailwind CSS의 @apply 디렉티브를 사용하여 유틸리티의 스타일 정의를 사용자 지정 스타일에 포함할 수 있습니다.

디자인 시스템에 의존하는 CSS 속성(예: margin, padding)을 적용할 때는 @apply 사용을 권장합니다. 단위가 없는 CSS 속성(예를 들어 display: flex)은 CSS 속성을 직접 사용해도 괜찮습니다.

// Bad
.my-class {
  margin-top: 0.5rem;
}

// Okay
.my-class {
  display: flex;
}

// Good
.my-class {
  @apply gl-mt-5;
  @apply gl-flex;
}

반응형 디자인#

GitLab UI는 모바일과 데스크톱에서 모두 잘 동작해야 합니다. 이를 위해 CSS 컨테이너 쿼리를 사용합니다. 일반적으로 컨테이너 쿼리에는 모바일 우선 접근 방식을 취해야 합니다. 즉, 모바일용 CSS를 먼저 작성하고, min-width 컨테이너 쿼리로 데스크톱에서 스타일을 재정의합니다. 이 규칙의 예외는 하위 컴포넌트에 표시 모드를 설정하는 경우입니다. 예를 들어 모바일에서 GlButton을 숨길 때는 컴포넌트 CSS가 설정한 표시 모드를 재정의하고 싶지 않으므로 max-width 컨테이너 쿼리를 사용해야 합니다. 현재 Tailwind 구성은 max-width 컨테이너 쿼리를 지원하지 않으므로, 그런 우회 방법이 필요하면 사용자 지정 스타일을 직접 작성해야 합니다.

Tailwind CSS 클래스#

<!-- Bad (using desktop-first media queries) -->
<div class="gl-mt-5 max-lg:gl-mt-3"></div>

<div class="gl-mt-3 sm:max-lg:gl-mt-5"></div>

<!-- Good (using min-width container queries) -->
<div class="gl-mt-3 @md:gl-mt-5"></div>

<div class="gl-mt-3 @sm:gl-mt-5 @lg:gl-mt-3"></div>

<!-- Bad -->
<!--
`gl-hidden` applies `display: none` to all container sizes. This forces us to make assumptions on
what `display` value to reset the component to on larger viewports. In this case, we _assume_ `flex`
should be used. However, this might not match the component's internal styling and might end up
causing visual regressions.
-->
<gl-button class="gl-hidden @lg:gl-flex">Edit</gl-button>

<!-- Good -->
<!--
A `@max-*:gl-hidden` class only applies `display: none` in smaller containers,
ensuring that the component can gracefully fall back to its own `display` value in larger containers.
-->
<gl-button class="@max-lg:gl-hidden">Edit</gl-button>
<!-- One can also define a breakpoint range in which to apply the override -->
<gl-button class="@sm:@max-md:gl-hidden">Edit</gl-button>

컴포넌트 클래스#

// Bad (using desktop-first media queries)
.class-name {
  @apply gl-mt-5 max-lg:gl-mt-3;
}

// Good (using min-width container queries)
.class-name {
  @apply gl-mt-3 @lg:gl-mt-5;
}

// Bad (using max-width container queries)
.class-name {
  display: block;

  @include gl-container-width-up-down(lg) {
    display: flex;
  }
}

// Good (using min-width container queries)
.class-name {
  display: flex;

  @include gl-container-width-up(lg) {
    display: block;
  }
}

네이밍#

파일 이름은 snake_case를 사용해야 합니다.

CSS 클래스는 snake_case나 camelCase가 아니라 lowercase-hyphenated 형식을 사용해야 합니다.

// Bad
.class_name {
  color: #fff;
}

// Bad
.className {
  color: #fff;
}

// Good
.class-name {
  color: #fff;
}

SCSS & 기능으로 복합 클래스 이름을 만드는 것은 피합니다. 사용처를 검색하기 어려워지고, 이점은 제한적입니다.

// Bad
.class {
  &-name {
    color: orange;
  }
}

// Good
.class-name {
  color: #fff;
}

태그 이름 선택자 대신 클래스 이름을 사용해야 합니다. 태그 이름 선택자는 계층 구조에서 의도하지 않은 요소에 영향을 줄 수 있으므로 권장하지 않습니다.

// Bad
ul {
  color: #fff;
}

// Good
.class-name {
  color: #fff;
}

// Best
// prefer an existing utility class over adding existing styles

ID보다 클래스 이름이 낫습니다. ID를 사용하는 규칙은 페이지에서 영향을 받는 요소가 하나뿐이므로 재사용할 수 없습니다.

// Bad
#my-element {
  padding: 0;
}

// Good
.my-element {
  padding: 0;
}

중첩#

불필요한 중첩은 피합니다. 래퍼 컴포넌트의 추가 특정성 때문에 재정의하기가 더 어려워집니다.

// Bad
.component-container {
  .component-header {
    /* ... */
  }

  .component-body {
    /* ... */
  }
}

// Good
.component-container {
  /* ... */
}

.component-header {
  /* ... */
}

.component-body {
  /* ... */
}

js- 접두사가 붙은 선택자#

js- 접두사가 붙은 선택자는 스타일 지정 목적으로 사용하지 않습니다. 이 선택자는 스타일을 깨뜨리지 않고 제거하거나 이름을 바꿀 수 있도록 JavaScript에서만 사용하기 위한 것입니다.

클래스 연결#

클래스를 만들기 위해 문자열을 연결하지 않습니다. 대신 가독성과 유지 관리를 위해 전체 클래스 이름을 그대로 적습니다.

// Bad
.foo {
  /* ... */
  &-bar {
    /* ... */
  }
}

// Good
.foo {
  /* ... */
}

.foo-bar {
  /* ... */
}

유틸리티 CSS 클래스를 사용한 선택자#

스타일시트에서 유틸리티 CSS 클래스를 선택자로 사용하지 않습니다. 이 클래스는 바뀔 가능성이 높아서 선택자를 함께 업데이트해야 하고, 구현을 유지 관리하기 어렵게 만듭니다. 대신 기존의 다른 CSS 클래스를 사용하거나 요소 스타일 지정을 위해 새 사용자 지정 CSS 클래스를 추가합니다. 이 방식은 유지 관리성을 높이고 버그 위험을 줄입니다.

// ❌ Bad
.gl-mb-5 {
  /* ... */
}

// ✅ Good
.component-header {
  /* ... */
}

ARIA 속성을 사용한 선택자#

ARIA를 사용하는 속성 선택자는 스타일 지정 목적으로 사용하지 않습니다. 이 속성과 역할은 보조 기술을 지원하기 위한 것입니다. ARIA로 표시된 컴포넌트의 구조는 바뀔 수 있고, 그 스타일도 바뀔 수 있습니다. 스타일을 깨뜨리지 않고 이 역할과 속성을 다른 요소로 옮길 수 있어야 합니다.

// Bad
&[aria-expanded=false] &-header {
  border-bottom: 0;
}

// Good
&.is-collapsed &-header {
  border-bottom: 0;
}

extend at-rule 사용#

extend at-rule 사용은 금지되어 있습니다. 이유는 메모리 누수와 이 규칙이 의도대로 동작하지 않는 문제입니다.

린팅#

스타일 가이드 준수를 확인하기 위해 stylelint를 사용합니다. stylelint는 .stylelintrc의 규칙 세트와 GitLab의 SCSS 구성의 규칙을 사용합니다. .stylelintrc는 프로젝트의 홈 디렉터리에 있습니다.

변경 사항으로 경고가 발생하는지 확인하려면 GitLab 디렉터리에서 yarn lint:stylelint를 실행합니다. 경고를 잡아내기 위해 Stylelint는 GitLab CI/CD에서도 실행됩니다.

Rake 태스크가 이해하기 어려운 경고를 내보내면, SCSS Lint 문서에 전체 규칙 목록이 있습니다.

SCSS 스타일 가이드

GitLab v19.4
원문 보기

요약

사이트가 커질 때 CSS가 더 생성되는 것을 줄이려면, 새 CSS를 추가하기보다 유틸리티 클래스를 사용하는 편이 좋습니다. 유틸리티 클래스는 Tailwind CSS가 생성합니다. common.scss의 클래스는 사용이 중단되고 있습니다.

유틸리티 클래스#

사이트가 커질 때 CSS가 더 생성되는 것을 줄이려면, 새 CSS를 추가하기보다 유틸리티 클래스를 사용하는 편이 좋습니다. 복잡한 경우에는 컴포넌트 클래스를 추가하여 CSS를 처리할 수 있습니다.

CSS 유틸리티 클래스 정의 위치#

유틸리티 클래스는 Tailwind CSS가 생성합니다. Tailwind CSS 클래스를 확인하는 방법은 세 가지입니다.

  • GitLab Tailwind CSS 문서: GitLab Tailwind 구성에 특화된 문서 사이트입니다. 사용할 수 있는 모든 Tailwind CSS 클래스를 검색 가능한 목록으로 제공합니다.
  • Tailwind CSS 자동완성: VS Code 또는 RubyMine에서 사용할 수 있습니다.
  • Tailwind CSS 구성 뷰어: 간격, 색상, 크기처럼 GitLab 디자인 시스템에 특화된 Tailwind CSS 클래스를 시각적으로 보여 줍니다. 사용할 수 있는 모든 Tailwind CSS 클래스를 표시하지는 않습니다.

사용이 중단된 CSS 유틸리티 클래스#

common.scss의 클래스는 사용이 중단되고 있습니다. 디자인 시스템에 없는 값을 사용하는 common.scss의 클래스는 피해야 합니다. 대신 기준에 맞는 값을 쓰는 클래스를 사용합니다.

Bootstrap의 유틸리티 클래스는 피합니다.

Note

Bootstrap의 유틸리티 클래스를 GitLab UI 유틸리티 클래스로 마이그레이션할 때, margin과 padding 클래스가 모두 다르다는 점에 유의합니다. GitLab에서 사용하는 크기 스케일은 Bootstrap 라이브러리의 스케일과 다릅니다. Bootstrap의 padding 또는 margin 유틸리티와 같은 시각적 결과를 얻으려면 적용한 유틸리티의 크기를 두 배로 해야 할 수 있습니다(예를 들어 ml-1은 gl-ml-2가 됩니다).

Tailwind CSS#

2024년 8월부터 CSS 유틸리티 공급자로 Tailwind CSS를 사용합니다. 이는 이전의 자체 제작 솔루션을 대체합니다. 동기, 제안, 구현 세부 사항은 Tailwind CSS 설계 문서를 참고합니다.

Tailwind CSS 기본 사항#

다음은 Tailwind CSS의 기본 사항과, Pajamas 디자인 시스템을 사용하도록 구성한 방식에 대한 정보입니다. 더 자세한 안내는 Tailwind CSS 공식 문서를 참고합니다.

접두사#

Tailwind CSS가 접두사를 사용하도록 구성했으므로 모든 유틸리티 클래스에는 gl- 접두사가 붙습니다. 반응형 유틸리티나 상태 수정자를 사용할 때는 접두사가 콜론 뒤에 옵니다.

예시: gl-mt-5, lg:gl-mt-5.

반응형 CSS 유틸리티 클래스#

반응형 CSS 유틸리티 클래스에는 브레이크포인트 이름 뒤에 : 문자가 붙은 접두사가 붙습니다. 사용할 수 있는 브레이크포인트는 tailwind.defaults.js#L44에 구성되어 있습니다

예시: lg:gl-mt-5

hover, focus 및 기타 상태 수정자#

상태 수정자를 사용하면 모든 Tailwind CSS 클래스를 조건부로 적용할 수 있습니다. CSS 유틸리티 클래스 앞에 수정자 이름을 붙이고 그 뒤에 : 문자를 붙입니다.

예시: hover:gl-underline

!important 수정자#

CSS 유틸리티 클래스 앞에 !를 추가하면 important 수정자를 사용할 수 있습니다. 반응형 유틸리티 클래스나 상태 수정자와 함께 사용할 때는 !가 : 문자 뒤에 옵니다.

예시: !gl-mt-5, lg:!gl-mt-5, hover:!gl-underline

간격 및 크기 CSS 유틸리티 클래스#

간격 및 크기 CSS 유틸리티 클래스(예를 들어 margin, padding, width, height)는 src/tokens/build/tailwind/tokens.cjs에 정의된 간격 스케일을 사용합니다. 사용할 수 있는 CSS 유틸리티 클래스는 https://design.gitlab.com/tailwind-documentation/margin을 참고합니다.

예시: gl-mt-5는 margin-top: 1rem;입니다

색상 CSS 유틸리티 클래스#

색상 CSS 유틸리티 클래스(예를 들어 color와 background-color)는 src/tokens/build/tailwind/tokens.cjs에 정의된 색상을 사용합니다. 사용할 수 있는 CSS 유틸리티 클래스는 https://design.gitlab.com/tailwind-documentation/text-color을 참고합니다.

예시: gl-text-subtle은 color: var(--gl-text-color-subtle, #626168);입니다

Tailwind CSS 번들 빌드#

GitLab Development Kit에서 Vite 또는 Webpack을 사용하면 Tailwind CSS가 파일 변경을 감시하여 감지된 유틸리티를 즉시 빌드합니다.

새 Tailwind CSS 번들을 빌드하려면 yarn tailwindcss:build를 실행합니다. 이 스크립트는 bundle exec rake gitlab:assets:compile로 프로덕션 애셋을 빌드할 때 내부적으로 호출됩니다.

번들을 어떤 방식으로 빌드하든 출력은 app/assets/builds/tailwind.css에 저장됩니다.

Tailwind CSS 자동완성#

Tailwind CSS 자동완성은 코드 편집기에서 사용할 수 있는 모든 클래스를 나열합니다.

VS Code#
Note

자동완성이 느려 문제가 있다면 TS 서버가 사용할 수 있는 메모리 양을 늘려야 할 수 있습니다.

Tailwind CSS IntelliSense 확장을 설치합니다. HAML과 사용자 지정 *-class prop을 지원하려면 다음 설정을 권장합니다.

{
  "tailwindCSS.experimental.classRegex": [
    ["class: [\"|']+([^\"|']*)[\"|']+", "([a-zA-Z0-9\\-:!/]+)"],
    ["(\\.[\\w\\-.]+)[\\n\\=\\{\\s]", "([\\w\\-]+)"],
    ["[a-z]+-class(?:es)?=\"([^'\"]*)\""]
  ],
  "tailwindCSS.emmetCompletions": true
}
RubyMine#

Tailwind CSS 자동완성은 기본적으로 활성화되어 있습니다. HAML과 사용자 지정 *-class prop을 완전히 지원하려면 기본 설정을 다음과 같이 변경하는 것을 권장합니다.

{
  "includeLanguages": {
    "haml": "html"
  },
  "emmetCompletions": true,
  "experimental": {
    "classRegex": [
      ["class: [\"|']+([^\"|']*)[\"|']+", "([a-zA-Z0-9\\-:!/]+)"],
      ["(\\.[\\w\\-.]+)[\\n\\=\\{\\s]", "([\\w\\-]+)"],
      ["[a-z]+-class(?:es)?=\"([^'\"]*)\""]
    ]
  }
}

Tailwind CSS 임의 값#

임의 값은 몇 가지 이유로 피해야 합니다.

  • 한 페이지에서만 필요할 가능성이 높은데도 전역 CSS 번들에 추가되어 번들 크기를 키웁니다. 대신 페이지별 CSS를 사용해 필요한 곳에만 CSS가 포함되도록 합니다.
  • 미리 정의된 CSS 클래스가 이미 있을 가능성이 높습니다. 사용할 수 있는 Tailwind CSS 클래스는 GitLab Tailwind CSS 문서에서 확인합니다.
  • 디자인 시스템을 강제하지 않습니다.

새 유틸리티 클래스를 추가할 위치#

유틸리티 클래스는 대부분의 CSS 기능을 지원하는 Tailwind CSS가 생성합니다. 사용할 수 없는 것이 있으면 GitLab UI의 tailwind.defaults.js를 업데이트해야 합니다.

컴포넌트 클래스를 생성하는 시점#

"utility-first" 접근 방식을 권장합니다.

  1. 유틸리티 클래스로 시작합니다.
  2. 유틸리티 클래스를 컴포넌트 클래스로 조합하면 코드 중복이 없어지고 책임이 명확하게 캡슐화되는 경우에는 그렇게 합니다.

이렇게 하면 컴포넌트 클래스가 자연스럽게 늘어나고, 재사용할 수 없는 일회성 클래스가 만들어지는 것을 막습니다. 또한 "utility-first"에서 나오는 클래스는 도메인 중심(예를 들어 .security-report-widget, .commit-header-icon)이 아니라 디자인 중심(예를 들어 .button, .alert, .card)이 되는 경향이 있습니다.

참고 자료:

HTML과 스타일시트에서 Tailwind CSS 활용#

컴포넌트 클래스를 작성할 때는 디자인 시스템과의 일관성을 유지하고 CSS 번들을 작게 유지하려면 Tailwind CSS의 유틸리티 클래스를 효과적으로 통합하는 것이 중요합니다.

HTML의 유틸리티 CSS 클래스와 스타일시트의 유틸리티 CSS 클래스 비교:

HTML에서 유틸리티 클래스를 직접 사용하면 CSS 파일 크기를 더 작게 유지하고 utility-first 철학을 지킬 수 있습니다. 꼭 필요한 경우가 아니면 한 컴포넌트 클래스 안에서 유틸리티 클래스와 사용자 지정 스타일을 섞지 않음으로써 혼란과 잠재적 충돌을 막을 수 있습니다.

  • 이 방식을 선호하는 이유:
    • 더 작은 CSS 파일 크기: 유틸리티 클래스를 직접 활용하면 CSS 파일이 더 간결해지고 디자인 시스템의 일관성이 높아집니다.
    • 명확성과 유지 관리성: HTML에서 유틸리티 클래스를 사용하면 스타일이 어떻게 적용되는지 더 명확해지고, 충돌과 회귀 위험이 줄어듭니다.
  • 스타일을 섞을 때 생길 수 있는 문제:
    • 충돌: 한 클래스 안에서 유틸리티 클래스와 사용자 지정 스타일을 섞으면, 특히 스타일 사이에 상호 의존성이 있을 때 충돌이 생길 수 있습니다.
    • 회귀: 스타일이 어떻게 결정되어야 하는지 덜 분명해져서 회귀나 예상치 못한 동작이 생길 수 있습니다.

이 지침을 따르면 Tailwind CSS를 효과적으로 활용하는 깔끔하고 유지 관리하기 쉬운 스타일시트를 만들 수 있습니다.

1. HTML에서 유틸리티 클래스 직접 사용(권장 방식)#

유지 관리성을 높이고 utility-first 원칙을 지키려면 유틸리티 클래스를 HTML 요소에 직접 추가합니다. 컴포넌트 클래스에는 기본적으로 유틸리티가 아닌 CSS 스타일만 담습니다. 다음 예시에서는 SCSS 파일에 position: fixed; right: 0; left: 0;을 추가하는 대신 유틸리티 클래스 gl-fixed와 gl-inset-x-0을 추가합니다.

<!-- Bad -->
<div class="my-class"></div>

<style>
  .my-class {
    top: $header-height;
    min-height: $comparison-empty-state-height;
    position: fixed;
    left: 0px;
    right: 0px;
 }
</style>

<!-- Good -->
<div class="my-class gl-fixed gl-inset-x-0"></div>

<style>
  .my-class {
    top: $header-height;
    min-height: $comparison-empty-state-height;
  }
</style>

2. 컴포넌트 클래스에서 유틸리티 클래스 적용(필요한 경우)#

HTML에서 유틸리티 클래스를 직접 사용하는 것이 어려워서 사용자 지정 SCSS 파일에 포함해야 할 때도 있습니다. 그럴 때는 관련 속성이나 값을 직접 찾지 않고도 디자인 시스템의 스타일 정의를 상속하고 싶을 수 있습니다. 이 과정을 단순하게 하려면 Tailwind CSS의 @apply 디렉티브를 사용하여 유틸리티의 스타일 정의를 사용자 지정 스타일에 포함할 수 있습니다.

디자인 시스템에 의존하는 CSS 속성(예: margin, padding)을 적용할 때는 @apply 사용을 권장합니다. 단위가 없는 CSS 속성(예를 들어 display: flex)은 CSS 속성을 직접 사용해도 괜찮습니다.

// Bad
.my-class {
  margin-top: 0.5rem;
}

// Okay
.my-class {
  display: flex;
}

// Good
.my-class {
  @apply gl-mt-5;
  @apply gl-flex;
}

반응형 디자인#

GitLab UI는 모바일과 데스크톱에서 모두 잘 동작해야 합니다. 이를 위해 CSS 컨테이너 쿼리를 사용합니다. 일반적으로 컨테이너 쿼리에는 모바일 우선 접근 방식을 취해야 합니다. 즉, 모바일용 CSS를 먼저 작성하고, min-width 컨테이너 쿼리로 데스크톱에서 스타일을 재정의합니다. 이 규칙의 예외는 하위 컴포넌트에 표시 모드를 설정하는 경우입니다. 예를 들어 모바일에서 GlButton을 숨길 때는 컴포넌트 CSS가 설정한 표시 모드를 재정의하고 싶지 않으므로 max-width 컨테이너 쿼리를 사용해야 합니다. 현재 Tailwind 구성은 max-width 컨테이너 쿼리를 지원하지 않으므로, 그런 우회 방법이 필요하면 사용자 지정 스타일을 직접 작성해야 합니다.

Tailwind CSS 클래스#

<!-- Bad (using desktop-first media queries) -->
<div class="gl-mt-5 max-lg:gl-mt-3"></div>

<div class="gl-mt-3 sm:max-lg:gl-mt-5"></div>

<!-- Good (using min-width container queries) -->
<div class="gl-mt-3 @md:gl-mt-5"></div>

<div class="gl-mt-3 @sm:gl-mt-5 @lg:gl-mt-3"></div>

<!-- Bad -->
<!--
`gl-hidden` applies `display: none` to all container sizes. This forces us to make assumptions on
what `display` value to reset the component to on larger viewports. In this case, we _assume_ `flex`
should be used. However, this might not match the component's internal styling and might end up
causing visual regressions.
-->
<gl-button class="gl-hidden @lg:gl-flex">Edit</gl-button>

<!-- Good -->
<!--
A `@max-*:gl-hidden` class only applies `display: none` in smaller containers,
ensuring that the component can gracefully fall back to its own `display` value in larger containers.
-->
<gl-button class="@max-lg:gl-hidden">Edit</gl-button>
<!-- One can also define a breakpoint range in which to apply the override -->
<gl-button class="@sm:@max-md:gl-hidden">Edit</gl-button>

컴포넌트 클래스#

// Bad (using desktop-first media queries)
.class-name {
  @apply gl-mt-5 max-lg:gl-mt-3;
}

// Good (using min-width container queries)
.class-name {
  @apply gl-mt-3 @lg:gl-mt-5;
}

// Bad (using max-width container queries)
.class-name {
  display: block;

  @include gl-container-width-up-down(lg) {
    display: flex;
  }
}

// Good (using min-width container queries)
.class-name {
  display: flex;

  @include gl-container-width-up(lg) {
    display: block;
  }
}

네이밍#

파일 이름은 snake_case를 사용해야 합니다.

CSS 클래스는 snake_case나 camelCase가 아니라 lowercase-hyphenated 형식을 사용해야 합니다.

// Bad
.class_name {
  color: #fff;
}

// Bad
.className {
  color: #fff;
}

// Good
.class-name {
  color: #fff;
}

SCSS & 기능으로 복합 클래스 이름을 만드는 것은 피합니다. 사용처를 검색하기 어려워지고, 이점은 제한적입니다.

// Bad
.class {
  &-name {
    color: orange;
  }
}

// Good
.class-name {
  color: #fff;
}

태그 이름 선택자 대신 클래스 이름을 사용해야 합니다. 태그 이름 선택자는 계층 구조에서 의도하지 않은 요소에 영향을 줄 수 있으므로 권장하지 않습니다.

// Bad
ul {
  color: #fff;
}

// Good
.class-name {
  color: #fff;
}

// Best
// prefer an existing utility class over adding existing styles

ID보다 클래스 이름이 낫습니다. ID를 사용하는 규칙은 페이지에서 영향을 받는 요소가 하나뿐이므로 재사용할 수 없습니다.

// Bad
#my-element {
  padding: 0;
}

// Good
.my-element {
  padding: 0;
}

중첩#

불필요한 중첩은 피합니다. 래퍼 컴포넌트의 추가 특정성 때문에 재정의하기가 더 어려워집니다.

// Bad
.component-container {
  .component-header {
    /* ... */
  }

  .component-body {
    /* ... */
  }
}

// Good
.component-container {
  /* ... */
}

.component-header {
  /* ... */
}

.component-body {
  /* ... */
}

js- 접두사가 붙은 선택자#

js- 접두사가 붙은 선택자는 스타일 지정 목적으로 사용하지 않습니다. 이 선택자는 스타일을 깨뜨리지 않고 제거하거나 이름을 바꿀 수 있도록 JavaScript에서만 사용하기 위한 것입니다.

클래스 연결#

클래스를 만들기 위해 문자열을 연결하지 않습니다. 대신 가독성과 유지 관리를 위해 전체 클래스 이름을 그대로 적습니다.

// Bad
.foo {
  /* ... */
  &-bar {
    /* ... */
  }
}

// Good
.foo {
  /* ... */
}

.foo-bar {
  /* ... */
}

유틸리티 CSS 클래스를 사용한 선택자#

스타일시트에서 유틸리티 CSS 클래스를 선택자로 사용하지 않습니다. 이 클래스는 바뀔 가능성이 높아서 선택자를 함께 업데이트해야 하고, 구현을 유지 관리하기 어렵게 만듭니다. 대신 기존의 다른 CSS 클래스를 사용하거나 요소 스타일 지정을 위해 새 사용자 지정 CSS 클래스를 추가합니다. 이 방식은 유지 관리성을 높이고 버그 위험을 줄입니다.

// ❌ Bad
.gl-mb-5 {
  /* ... */
}

// ✅ Good
.component-header {
  /* ... */
}

ARIA 속성을 사용한 선택자#

ARIA를 사용하는 속성 선택자는 스타일 지정 목적으로 사용하지 않습니다. 이 속성과 역할은 보조 기술을 지원하기 위한 것입니다. ARIA로 표시된 컴포넌트의 구조는 바뀔 수 있고, 그 스타일도 바뀔 수 있습니다. 스타일을 깨뜨리지 않고 이 역할과 속성을 다른 요소로 옮길 수 있어야 합니다.

// Bad
&[aria-expanded=false] &-header {
  border-bottom: 0;
}

// Good
&.is-collapsed &-header {
  border-bottom: 0;
}

extend at-rule 사용#

extend at-rule 사용은 금지되어 있습니다. 이유는 메모리 누수와 이 규칙이 의도대로 동작하지 않는 문제입니다.

린팅#

스타일 가이드 준수를 확인하기 위해 stylelint를 사용합니다. stylelint는 .stylelintrc의 규칙 세트와 GitLab의 SCSS 구성의 규칙을 사용합니다. .stylelintrc는 프로젝트의 홈 디렉터리에 있습니다.

변경 사항으로 경고가 발생하는지 확인하려면 GitLab 디렉터리에서 yarn lint:stylelint를 실행합니다. 경고를 잡아내기 위해 Stylelint는 GitLab CI/CD에서도 실행됩니다.

Rake 태스크가 이해하기 어려운 경고를 내보내면, SCSS Lint 문서에 전체 규칙 목록이 있습니다.