本地阳光下的暗黑模式 (2021)
Dark mode by local sunlight (2021)

原始链接: https://www.ctnicholas.dev/articles/dark-mode-by-sunlight

## 基于阳光的自动深色模式 网站越来越多地提供深色模式,一项引人注目的增强功能是根据用户的位置和一天中的时间自动启用它。这涉及到确定本地日出和日落时间,以调整主题以达到最佳的观看舒适度。 位置可以通过地理位置API(在用户许可下)或后端API(如geolocation-db.com)获取。`SunCalc` NPM包然后根据纬度、经度和日期计算日出、日落、黎明和黄昏时间。通过将当前时间与这些太阳事件进行比较,网站可以动态地在亮色和深色主题之间切换——甚至可以结合“黄昏”模式,利用黄金时段的时间。 然而,开发者必须考虑到极地地区等边缘情况,在这些地区太阳可能不会每天升起或落下,并且始终优先考虑用户偏好。用户可能有可访问性需求(例如散光,在这种情况下,浅色背景上的深色文本更可取),应该通过CSS `@media (prefers-color-scheme: dark)` 或 JavaScript 的 `window.matchMedia('(prefers-color-scheme: dark)')` 来尊重。最终,自动设置应该补充而不是取代手动深色模式切换。

这个Hacker News讨论围绕着设备上自动切换到暗黑模式。一位用户分享了他们使用iOS/iPadOS的“Noir”扩展的积极体验,该扩展根据设备的内置夜间/暗黑模式设置(包括位置)激活暗黑模式。 对话随后提到了f.lux,一款类似的电脑软件。用户们提出了改进建议,提倡根据*环境光线*而非时间来触发暗黑模式,甚至允许用户完全禁用自动切换。一位用户特别希望在屏幕锁定后能无缝切换到暗黑模式,而不是在使用过程中。 最后,帖子包含了一则关于应用程序申请参加Y Combinator 2026冬季项目的通知。
相关文章

原文

Dark mode is increasingly appearing as an option on websites, but why not have it enable automatically? We can estimate the sunlight levels at a user's location, and apply the correct theme to soothe their eyes.

The first step is finding the users' locations; the sun doesn't set everywhere at the same time, and other solar phases also differ depending on your location on the planet. For example, a user in Iceland could be set to dark mode at the same (local) time as a user in South Africa will be set to light:

14:00 on 1 Jan, Reykjavik
14:00 on 1 Jan, Johannesburg

There are multiple ways to find your users' locations, but for this example we'll stick with the Geolocation API, and retrieve their latitude & longitude from its coordinates object:

navigator.geolocation.getCurrentPosition(position => {
  const { latitude, longitude } = position.coords
})

The Geolocation API requires users to accept permission in a browser dialog box, but if we don't want this we can find locations using a backend API.

How do we figure out the time of local sunsets & sunrises? We can't just use location, because the time of year affects solar phases too. If you play with the example below, you can see there's around 5 hours of variance between sunset in January and June in Ireland.

Even in equatorial nations, whilst the amount of sunlight barely changes across seasons, the time of the sunset still varies by around an hour, thanks to the elliptical nature of the earth's orbit. You can see this in Quito, Ecuador, one of the most longitudinally medial capital cities:

There's a handy NPM package named SunCalc (created by @mourner) that we can use to find the local solar times.

npm install suncalc

suncalc.getTimes() takes three arguments, (date, latitude, longitude) and returns an object with a number of date properties attached. We'll be using sunrise and sunset (the full syntax and return values can be found on GitHub).

import SunCalc from 'suncalc'

const date = new Date('January 1, 2022 12:00:00')
const { sunrise, sunset } = SunCalc.getTimes(date, 10, -10)


console.log(sunrise)


console.log(sunset)

We can use getTimes() in conjunction with the geolocation snippet from earlier and then compare with the users' current time to check if it's currently before or after sunset.

import SunCalc from 'suncalc'

navigator.geolocation.getCurrentPosition(position => {
  const { latitude, longitude } = position.coords
  const now = new Date()

  
  const { sunrise, sunset } = SunCalc.getTimes(now, longitude, latitude)

  
  if (now < sunrise || now > sunset) {
    
    ...
  } else {
    
    ...
  }
})

As simple as that! Here's a live demo that retrieves your current mode:

At ??? in your location
Theme timetable

We could even add more themes, such as a twilight theme, to be displayed before and after sunrise/sunset:

Technically speaking, twilight is the period of time between either dawn & sunrise, or sunset & dusk, however real twilight doesn't last too long, so I'm going to include golden hour as part of twilight mode:

Twilight mode will now be enabled for around twice the length of before, and will be enabled just either side of sunrise and sunset. Using SunCalc, it looks like this:

const { dawn, dusk, goldenHourEnd, goldenHour } = SunCalc.getTimes(now, longitude, latitude)

if (now < dawn || now > dusk) {
  
} else if (now < goldenHourEnd || now > goldenHour) {
  
} else {
  
}

Test your current location:

At ??? in your location
Theme timetable

Automatically setting the theme is a nice touch for most, but accessibility comes first, and if the user has a preference, it's always right to respect their choice. A number of people suffer from astigmatism and light text on a dark background can worsen a visual issue called halation, which looks something like this:

At 03:20 on 23 May in São Paulo
Theme timetable
At 03:20 on 23 May in São Paulo
Theme timetable
At 03:20 on 23 May in São Paulo
Theme timetable
At 03:20 on 23 May in São Paulo
Theme timetable

Astigmatic halation

No astigmatism

You can check for users' colour scheme preferences in CSS & JavaScript with the following snippets:

@media (prefers-color-scheme: dark) {
    
}
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
    
}

Automatically selecting dark mode by local sunlight is quite simple, but remember—if you have a dark mode, it's good practice to include a switch.

联系我们 contact @ memedata.com