Zum Inhalt springen
vanheek.biz
Startseite Praxistests Web & Tools Alltag
Kontakt

Praxistest · Stand: 31. August 2026

Tag- und Nachtmodus nach dem echten Sonnenstand — ganz ohne API

Diese Website wechselt selbständig zwischen hellem und dunklem Erscheinungsbild. Nicht nach einer festen Uhrzeit und nicht nach der Systemeinstellung des Besuchers, sondern nach dem tatsächlichen Sonnenauf- und -untergang an meinem Wohnort. Wenn hier in Altensteig die Sonne hinter dem Waldrand verschwindet, wird die Seite dunkel — für alle Leser, überall.

Der naheliegende Weg dorthin wäre eine kostenlose Schnittstelle gewesen: Breitengrad und Längengrad hinschicken, Zeiten zurückbekommen, fertig. Genau das empfiehlt praktisch jede Anleitung, die man zu diesem Thema findet. Ich habe es trotzdem anders gemacht, und der Grund dafür ist der eigentlich interessante Teil dieses Artikels.

Warum die naheliegende Lösung die falsche war

Ein Schnittstellen-Aufruf im Browser ist kein technisches Detail, sondern eine Datenweitergabe. Jeder Besucher hätte bei jedem Seitenaufruf seine IP-Adresse an einen fremden Server geschickt, zusammen mit dem Zeitpunkt und der Information, dass er gerade diese Seite liest. Alles nur, um eine Farbe zu bestimmen.

Diese Seite verspricht an mehreren Stellen ausdrücklich, ohne Tracking, ohne Werbe-Cookies und ohne eingebundene Fremddienste zu arbeiten. Das steht in der Datenschutzerklärung, es steht in meinen Bewerbungen bei den Partnerprogrammen, und es steht als Versprechen auf der Startseite. Eine hübsche Spielerei hätte dieses Versprechen gebrochen — für Leser unsichtbar, aber deswegen nicht weniger falsch.

Die Erkenntnis dahinter ist banal und wird trotzdem ständig übersehen: Der Sonnenstand ist keine Information, die man abfragen muss. Er ist berechenbar. Ort und Zeitpunkt genügen, der Rest ist Astronomie aus dem 19. Jahrhundert. Ein Browser erledigt diese Rechnung in deutlich unter einer Millisekunde — ohne Netzwerk, ohne Wartezeit, ohne dass jemand mitliest.

Was dabei herauskommt

Das folgende Diagramm ist mit genau derselben Formel gerechnet, die auch oben im Seitenkopf läuft. Die beiden Linien sind Sonnenauf- und -untergang, der eingefärbte Bereich dazwischen ist der Tag — also die Zeitspanne, in der diese Website 2026 im hellen Modus erscheint:

04:0008:0012:0016:0020:00 JanFebMärAprMaiJunJulAugSepOktNovDez
Sonnenauf- und -untergang in Altensteig über das Jahr, in Ortszeit. Gut zu sehen sind die beiden Stufen Ende März und Ende Oktober — das ist die Sommerzeit-Umstellung.

Die Formel

Grundlage ist die klassische Sonnenaufgangsgleichung. Sie braucht Breitengrad, Längengrad und das Datum und liefert daraus zwei Werte: den Zeitpunkt des Sonnenhöchststands und den halben Tagbogen, also die Spanne vom Höchststand bis zum Untergang. Aufgang und Untergang sind dann schlicht Höchststand minus beziehungsweise plus dieser Spanne.

Hier ist die vollständige Funktion, so wie sie auf dieser Seite arbeitet. Sie liefert true, wenn die Sonne über Altensteig gerade über dem Horizont steht:

function tagInAltensteig() {
  var R  = Math.PI / 180, B = 48.5885, L = 8.6003,  // Breite, Länge
      jd = Date.now() / 864e5 + 2440587.5,          // Julianisches Datum
      n  = Math.round(jd - 2451545.0008),           // Tage seit J2000
      js = n - L / 360,                             // östlicher = früher
      M  = (357.5291 + 0.98560028 * js) % 360,      // mittlere Anomalie
      C  = 1.9148 * Math.sin(M * R)                 // Mittelpunktsgleichung
         + 0.02   * Math.sin(2 * M * R)
         + 0.0003 * Math.sin(3 * M * R),
      la = (M + C + 282.9372) % 360,                // ekliptische Länge
      tr = 2451545 + js                             // Sonnenhöchststand
         + 0.0053 * Math.sin(M * R)
         - 0.0069 * Math.sin(2 * la * R),
      de = Math.asin(Math.sin(la * R) * Math.sin(23.44 * R)),      // Deklination
      w  = Math.acos((Math.sin(-0.833 * R) - Math.sin(B * R) * Math.sin(de)) /
                     (Math.cos(B * R) * Math.cos(de))) / R / 360;  // halber Tagbogen

  if (w !== w) return !matchMedia("(prefers-color-scheme: dark)").matches;
  return jd > tr - w && jd < tr + w;
}

Vier Stellen darin verdienen eine Erklärung.

Die minus 0,833 Grad sind kein Tippfehler. Sonnenaufgang gilt als der Moment, in dem der obere Sonnenrand den Horizont berührt, nicht der Mittelpunkt — das sind schon einmal gut 0,26 Grad. Dazu kommt die Lichtbrechung in der Atmosphäre, die uns die Sonne noch sehen lässt, wenn sie geometrisch längst untergegangen ist. Beides zusammen ergibt diesen krummen Wert.

Die Zeile js = n - L / 360 ist die Stelle, an der ich mir eine Stunde Fehlersuche eingehandelt habe. Die Tageslänge stimmte auf zwei Minuten genau, aber Auf- und Untergang lagen beide gut eine Stunde zu spät. Der Grund war das Vorzeichen: Die Lehrbuchformel rechnet traditionell mit westlicher Länge, Altensteig liegt aber östlich. Und wer östlich wohnt, sieht die Sonne früher, nicht später. Ein Minuszeichen, eine Stunde Suche.

Der Vergleich w !== w ist ein Test auf NaN, den einzigen Wert in JavaScript, der sich selbst nicht gleicht. Nördlich des Polarkreises geht die Sonne im Sommer gar nicht unter, dann hat der Arkuskosinus keine Lösung. In Altensteig kann das nicht passieren, aber wer die Funktion für Tromsø nachbaut, bekommt auf diesem Weg einen sauberen Rückfall auf die Systemeinstellung des Besuchers statt eine kaputte Seite.

Gerechnet wird durchgehend in koordinierter Weltzeit, und das ist bequemer, als es klingt. Es gibt keine Zeitzonen-Logik, keine Sommerzeit-Sonderfälle und keine Fehler durch falsch eingestellte Uhren in fernen Ländern. Die Frage lautet ja nicht „wie spät ist es beim Besucher“, sondern „steht die Sonne gerade über Altensteig“ — und die beantwortet ein einziger Zeitstempel.

Der Einbau

Damit die Seite nicht kurz hell aufblitzt, bevor sie dunkel wird, gehört der Code als kleines Skript direkt in den <head>, vor das Stylesheet und ohne defer. Er setzt ein Attribut am Wurzelelement, an dem sich anschließend das CSS bedient:

window.vhPhase = function () { return tagInAltensteig() ? "tag" : "nacht"; };

try {
  var phase = window.vhPhase(),
      t = localStorage.getItem("vh-theme");   // manuelle Wahl?

  // Die manuelle Wahl gilt nur für die laufende Phase und verfällt
  // beim nächsten Sonnenauf- bzw. -untergang.
  if (t && localStorage.getItem("vh-phase") !== phase) {
    localStorage.removeItem("vh-theme");
    localStorage.removeItem("vh-phase");
    t = null;
  }
  document.documentElement.setAttribute(
    "data-theme", t || (phase === "tag" ? "light" : "dark"));
} catch (e) {
  document.documentElement.setAttribute("data-theme", "dark");
}

Das try ist dabei nicht bloß Zierde: In privaten Fenstern und bei blockierten Website-Daten wirft schon der reine Zugriff auf localStorage eine Ausnahme. Ohne diese Absicherung bliebe die Seite komplett ohne Farbschema.

Im Umschalt-Knopf wird beim Speichern die aktuelle Phase mitgeschrieben. Das sind die zwei Zeilen, die den Verfall überhaupt erst möglich machen:

localStorage.setItem("vh-theme", next);
if (window.vhPhase) localStorage.setItem("vh-phase", window.vhPhase());

Und im CSS hängt dann alles an diesem einen Attribut. Die dunkle Fassung ist bei mir der Normalfall, die helle wird über den Attribut-Selektor gesetzt:

:root                { --bg: #090b10; --text: #eceff6; }
[data-theme="light"] { --bg: #f6f4ef; --text: #14181f; }

body { background: var(--bg); color: var(--text); }

Warum die manuelle Wahl verfällt

Der Umschalter oben im Seitenkopf bleibt selbstverständlich erhalten — niemand soll sich meiner Astronomie beugen müssen. Die eigentlich interessante Frage war, wie lange so eine Entscheidung gelten soll. Für immer? Dann wäre die Automatik nach dem ersten Klick für diesen Besucher tot.

Meine Antwort: Die Wahl gilt für die laufende Phase. Wer nachts auf hell schaltet, behält hell — bis zum nächsten Sonnenaufgang. Danach übernimmt wieder die Automatik. Der schöne Nebeneffekt fiel mir erst beim Bauen auf: Der Rücksprung passiert immer genau in dem Moment, in dem Automatik und Nutzerwunsch ohnehin dasselbe wollen. Es gibt also nie eine Situation, in der die Seite jemandem vor der Nase umspringt.

Nachbauen und prüfen

Für den eigenen Ort ersetzt man B und L durch die eigenen Koordinaten. Beide findet man, indem man in einer Kartenanwendung lange auf den gewünschten Punkt tippt. Anschließend sollte man die Rechnung unbedingt gegen die Wirklichkeit prüfen; ich habe dafür die markanten Tage des Jahres genommen:

Datum 2026SonnenaufgangSonnenuntergangTageslänge
20. März (Tagundnachtgleiche)06:2918:3712 h 08 min
21. Juni (längster Tag)05:2321:3116 h 08 min
31. August (heute)06:4120:1113 h 30 min
21. Dezember (kürzester Tag)08:1516:3208 h 17 min

Alle Werte gelten für Altensteig in Ortszeit, die Abweichung gegenüber amtlichen Tabellen liegt unter zwei Minuten. Für einen Farbwechsel ist das erheblich genauer als nötig — und wer es präziser braucht, baut vermutlich keine Website, sondern ein Observatorium.

Die erste Zeile ist übrigens ein guter Test dafür, ob man die Formel wirklich verstanden hat: An der Tagundnachtgleiche sollten Tag und Nacht doch gleich lang sein, hier stehen aber 12 Stunden und 8 Minuten. Das ist kein Fehler, sondern exakt die vorhin erklärten minus 0,833 Grad. Der Tag ist an diesem Datum tatsächlich ein paar Minuten länger als die Nacht, weil die Atmosphäre uns die Sonne vorne und hinten ein Stück länger zeigt.

Fazit

Der Mehraufwand gegenüber der Schnittstellen-Lösung betrug vielleicht eine Stunde, den größten Teil davon der Vorzeichenfehler. Der Gewinn: kein Netzwerk-Aufruf, keine Wartezeit, keine Abhängigkeit von einem Dienst, der irgendwann abgeschaltet wird oder Geld kostet — und vor allem keine Besucherdaten, die das Haus verlassen.

Es lohnt sich, bei jeder eingebundenen Fremd-Schnittstelle einmal zu fragen: Ist das wirklich Information, die ich holen muss? Oder ist es etwas, das mein Programm selbst ausrechnen kann? Bei Sonnenzeiten, Feiertagen, Umrechnungen und Zeitzonen lautet die Antwort überraschend oft: rechnen. Und wenn diese Seite gerade dunkel ist, dann nicht, weil ein fremder Server das so gesagt hat — sondern weil hier draußen wirklich die Sonne untergegangen ist.

© 2026 Matthias van Heek Impressum · Datenschutzerklärung