本地阳光下的暗黑模式 (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)')` 来尊重。最终,自动设置应该补充而不是取代手动深色模式切换。

## 黑客新闻讨论总结:深色模式与用户偏好 一场黑客新闻讨论围绕着根据环境光或一天中的时间自动调整深色模式展开,起因是一个尝试使用地理位置来实现这一功能的项目。核心争论在于应用程序是否应该自动实现此功能,还是仅仅尊重用户系统范围内的深色模式偏好。 许多评论者认为应用程序应该遵循操作系统级别的设置,因为用户已经配置了他们喜欢的界面主题。另一些人指出应用程序中深色模式实现存在不一致之处——有些使用纯黑色(#000000),这可能会导致一些人眼睛疲劳,而另一些人则更喜欢灰色调。 几位用户强调了基于阳光切换的局限性,尤其是在高纬度地区或由于个人偏好(例如,无论光线如何都更喜欢深色模式)。讨论还涉及环境光传感器的潜力以及频繁主题切换的破坏性。最终,共识倾向于尊重用户定义的系统设置,同时承认应用程序内需要可定制的选项,以满足那些需要它们的人。
相关文章

原文

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