다크 모드 자동 지원하도록 테마 및 플러그인 업데이트

이전에는 Discourse의 모든 색상이 SCSS 변수로 저장되었습니다. 자동 다크 모드 색상 스킴 전환을 지원하기 위해 코어에서 이러한 색상을 커스텀 CSS 프로퍼티로 변환했습니다. 이제 인스펙터에서 전체 목록을 쉽게 확인할 수 있습니다:

테마와 플러그인은 스타일시트에서 사용된 모든 $color SCSS 변수를 --color CSS 프로퍼티 대응 항목으로 전환해야 합니다. 대부분의 경우 이는 단순한 찾기 및 치환 작업입니다:

-   background-color: $primary-very-low;
+   background-color: var(--primary-very-low);

그러나 테마나 플러그인이 SCSS 색상 함수를 사용하여 색상을 어둡게 하거나 밝게 하는 등 더 복잡한 색상 변형을 사용하는 경우가 있습니다. 이러한 경우 더 복잡한 리팩터링이 필요하며, 이를 위해 테마와 플러그인에서 색상 정의를 확장할 수 있는 기능을 추가했습니다.

플러그인에서

discourse-encrypt 플러그인의 이 커밋은 이러한 리팩터링의 우수하고 간단한 예시입니다. 이 커밋은 mix($color1, $color2) SCSS 선언을 별도의 파일로 이동시키고 이를 CSS 커스텀 프로퍼티로 저장합니다. 그런 다음 새 파일이 :color_definitions 자산으로 등록되어 새로 선언된 색상 프로퍼티가 색상 정의 스타일시트에 포함되도록 보장합니다.

테마에서

테마에서는 common/color_definitions.scss 스타일시트에 CSS 커스텀 프로퍼티를 선언하여 동일한 작업을 수행할 수 있습니다. 예시로 graceful 테마의 이 커밋을 참고할 수 있습니다.

추가 참고 사항

  • rgba($color, 0.5) 함수를 통해 투명 색상을 사용할 때, SCSS는 첫 번째 매개변수로 HEX 및 RGB 색상을 허용하지만 CSS 커스텀 프로퍼티는 RGB 색상만 허용합니다. 이러한 이유로 색상 정의에 hexToRGB() 헬퍼와 --rgb 접미사가 붙은 일부 프로퍼티를 도입했습니다. 예시:
// color_definitions.scss
:root {
  --primary: #{$primary};
  --primary-rgb: #{hexToRGB($primary)};
}

// other stylesheet
.element {
  background-color: rgba(var(--primary-rgb), 0.05);
}
  • 위 스니펫에서 SCSS 변수가 커스텀 프로퍼티로 전달될 때 보간(interpolation)된다는 점에 유의하세요. 이는 SCSS의 요구 사항이며, 자세한 내용은 Sass: Property Declarations 를 참조하세요.
  • CSS의 var() 선언은 첫 번째 값이 사용 불가능한 경우 두 번째 값으로 폴백할 수 있습니다. 예를 들어 var(--color1, red)를 작성하면 --color1 프로퍼티가 발견되지 않으면 CSS가 빨간색으로 폴백합니다. 플러그인에서는 이전 버전의 Discourse와의 호환성을 보장하기 위해 SCSS 색상 변수를 폴백으로 사용합니다. 따라서 이전 예시는 폴백이 포함된 경우 다음과 같이 보입니다:
-   background-color: $primary-very-low;
+   background-color: var(--primary-very-low, $primary-very-low);

이 문서는 버전 관리됩니다 - github에서 변경 사항을 제안하세요.

24개의 좋아요

I’m not very good at this stuff and it’ll take me a while to figure this out myself. . . Does this mean that all themes that referred to colors before are now going to be broken?

6개의 좋아요

No, not at all. SCSS variables in themes will continue to work for a long time.

But any colors outputted via SCSS variables will stay static, i.e. they cannot be dynamically switched to a new color scheme when a browser goes from normal to dark mode. So those themes/plugins will continue to work, they just won’t be compatible with automatic dark mode switching.

13개의 좋아요

Thanks for the instructions. Is there a way to also change a background image depending on dark/light mode? (I’ve used the theme switcher component to do that.) Would a CSS class indicating the mode be possible?

2개의 좋아요

Great question, I tried this and noticed that we didn’t properly support using background images or theme variables in the special color definitions stylesheet. So I made some fixes in core, and you should be able to do this now (make sure you pull the latest core).

So, if you have two images in your theme or theme component, with SCSS vars of $bg-light and $bg-dark respectively, you can add this to your color_definitions.scss stylesheet:


$bg: url(dark-light-choose($bg-light, $bg-dark));

:root {
  --custom-bg: #{$bg};
}

And then you can use var(--custom-bg) in your regular stylesheet.

8개의 좋아요

For an image, all you need to do is the vanilla prefers-dark-theme CSS media query.

That won’t work well in all cases, because the media query is not aware of the user’s preferences. Users can disable auto-dark-mode switching, but the media query won’t be aware of that, and it will result in the background meant for the dark color scheme being rendered.

4개의 좋아요

Discourse가 색상 스킴 또는 색상 스킴 ID에 대해 <body> 태그에도 CSS 클래스를 추가할 수 있을까요? 그렇게 하면 훨씬 쉬울 것 같습니다.

테마 변환 과정에서 문제를 해결하려고 하고 있는데, 다양한 CSS 규칙과 변수가 많이 필요해서 color_definitions.scss 파일이 복잡한 엉망이 되어 가고 있습니다.

테마의 격리된 SCSS 파일에서 다음과 같은 방식으로만 처리할 수 있다면, color_definitions.scss로 해결하는 데 오랜 시간이 걸리는 작업을 5분 만에 처리할 수 있을 텐데요:

body.dark-palette .some-thing {
  // some styles
}

body.light-palette .some-thing {
  // some styles
}

최선의 방법을 제대로 이해하지 못하고 있는 것일 수도 있지만, 각 변수마다 많은 작업이 필요한 것 같습니다. CSS 변수 하나를 설정하는 데만 에디터에서 해당 변수가 실제로 사용되는 작은 영역에서 멀리 떨어진 곳에 17줄이 차지하네요:

  • SCSS 변수로 라이트 모드 값을 정의합니다 (선형 그래디언트 같은 경우 에디터에서 6줄이 될 수 있음)
  • SCSS 변수로 다크 모드 값을 정의합니다 (또 다른 6줄)
  • dark-light-choose를 사용한 SCSS 변수를 정의합니다 (긴 변수 이름 때문에 4줄)
  • 마지막 SCSS 변수를 :root의 CSS 변수에 할당합니다 (1줄)

또한 이 네 가지 이름을 어떻게 지을지 파악하는 데도 시간이 걸립니다. 전역(global) 범위이기 때문이죠.

네, 특히 그라데이션의 경우 색상 정의 파일에 코드가 상당히 많이 쌓일 수 있습니다.

그래도 제 생각에는 여전히 가장 적절한 "위치"입니다. 실제로는 해당 색상이 사용되는 요소와 떨어져 있지만, 라이트/다크 모드에 따라 전환되는 색상과 그라데이션을 하나의 편리한 장소에서 처리할 수 있다는 점이 장점입니다.

대안으로는 다음과 같은 방식을 사용할 수 있습니다:

@container style(--scheme-type: light){
  body{
    background: red;
  }
}

우리의 색상 스킴에는 --scheme-type이라는 프로퍼티가 포함되어 있으며, 라이트 스킴의 경우 light, 다크 스킴의 경우 dark 값이 지정됩니다. 최신 브라우저들은 컨테이너 쿼리를 지원하므로, 페이지 body에 클래스를 추가하지 않고도 여기서 시도하려는 작업을 수행할 수 있습니다.

제 CSS/SCSS 실력은 그다지 좋지 않습니다. 이런 분야에 깊은 분들이라면 더 쉽게 하시는 것 같습니다.

color_definitions.scss 파일이 엉망이 되어서, 가져올 수 있도록 scss/ 폴더 안에 다른 파일로 옮겼습니다. 이름을 어떻게 지어야 할지 모르겠어서 지금은 이렇게 생겼습니다.

body 클래스를 사용하면(혹은 더 많은 예시가 있다면) 더 쉬울 것 같지만, 어쨌든 지금은 작동합니다. 컨테이너 쿼리가 어떻게 동작하는지는 모르지만, 나중에 조사해 보겠습니다.

오늘(2025/11/14) 기준으로 Firefox에서는 사용자 정의 속성에 대한 스타일 쿼리가 작동하지 않습니다.