w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.38k stars 642 forks source link

[mediaqueries] Dates #9710

Open Crissov opened 7 months ago

Crissov commented 7 months ago

In #4627 I entertained the idea of date-dependent styles, primarily in order to allow for holiday theming.

Respondents mostly agreed that this could be useful, but would easily turn into a privacy nightmare.

@frivoal suggested, pointing to Custom MQs:

I think the the following is the way forward:

  • ability to access the date
  • ability to make up your own MQ based on the date

I’m proposing the first item since I believe authors should not need to use JS to achieve that.

@custom-media --christmas (month: 12) and (day: 25);

@custom-media --weekend (day: Saturday), (day: Sunday);

Although I think styling by time of day might even be more popular, it also is more prone to fingerprinting.

SebastianZ commented 7 months ago

Note that this approach still allows some fingerprinting depending on when exactly the media query matches.

Imagine this:

@custom-media --monday (day: Monday) {
  background-image: url('https://example.com/timetracker');
}

So https://example.com/timetracker will be called in the second when the user's local date switches from Sunday to Monday. Based on that you can infer their longitudinal location with such media features.

Nonetheless, I still like the idea of date- and time-based media queries.

@tabatkins wrote in the other issue:

I've virtually never seen any site trying to theme itself in such a way

Here's one:

https://mein-mmo.de

That site is in light mode from 8am to 6pm and switches to dark mode, otherwise. It also styles its logo for Pride Month, which was another seasonal use case mentioned by @teh-maxh in the other issue. Similarily, many websites style their logos or parts of their contents for different recurring events like Christmas, Hanukkah, carnival, etc. (@Crissov named a lot more).

So there are a lot of use cases for having such media features, which, I believe, justify an integration into CSS.

And if it's not something the group considers important enough to integrate into CSS directly, it could still be achieved via script-based custom media queries.

As @frivoal wrote in the other issue:

I encourage people who want this sort of things to contribute proposals to make https://drafts.csswg.org/mediaqueries-5/#script-custom-mq more than a rough sketch.

Here's an example for how a script-based CSS variant could look like for the page I mentioned above:

JS:

setInterval(() => {
  const currentHour = new Date().getHours();
  CSS.customMedia.set('--dark-mode-time', currentHour >= 18 && currentHour < 8);
}, 60000);

CSS:

body {
  background-color: #fafafa;
  color: #1a1d20;
}
@media (--dark-mode-time) {
  body {
    background-color: #1a1d20;
    color: #e3e4e5;
  }
}

Sebastian

Crissov commented 7 months ago

Unfortunately, many holidays that authors would use this for, do not have simply fixed annual dates in the Gregorian calendar, e.g. Chinese New Year, US Thanksgiving, Orthodox Easter. With a simple year, month, day solution, authors would need to maintain a comprehensive list of explicit dates.

Also, it is common to apply a styling for the tide leading up to the holiday, not just in the date itself.

PS: I believe for dark mode we have better solutions that respect the user preference.

SebastianZ commented 7 months ago

Unfortunately, many holidays that authors would use this for, do not have simply fixed annual dates in the Gregorian calendar, e.g. Chinese New Year, US Thanksgiving, Orthodox Easter. With a simple year, month, day solution, authors would need to maintain a comprehensive list of explicit dates.

Yes, that's true. Though as @frivoal pointed out in #4627, there's no way to provide a built-in, exhaustive solution for that. Though giving a way query the date and time, as you suggested, makes fixed-date use cases easily possible. And for events that have dynamic dates, authors can fall back to script-based custom media queries.

E.g. the date for Easter is calculated via a complicated formula. For the Gregorian calendar, this might look like:

JS:

function calculateEasterDay(year) {
  const a = year % 4;
  const b = year % 7;
  const c = year % 19;
  const d = (19 * c + 24) % 30;
  const e = (2 * a + 4 * b + 6 * d + 5) % 7;
  const f = Math.floor((c + 11 * d + 22 * e) / 451);
  let day = 22 + d + e - 7 * f;

  if (day <= 31) {
    return new Date(year, 2, day);
  } else {
    day = d + e - 7 * f - 9;
    return new Date(year, 3, day);
  }
}

function isTodayEasterDay() {
  const currentDate = new Date();
  currentDate.setHours(0, 0, 0, 0);
  const easterDayDate = calculateEaster(currentDate.getFullYear());
  return currentDate === easterDayDate;
}

CSS.customMedia.set('--easter-day', isTodayEasterDay());

CSS:

@media (--easter-day) {
  body {
    background-image: url('easter-eggs.svg');
  }
}

Also, it is common to apply a styling for the tide leading up to the holiday, not just in the date itself.

Yeah. Very common for Advent season, for example, which we're in right now. For such timespans, the same rules as above apply.

For those, we probably want to express date spans using the range syntax of media features. The same for time spans. Examples for that:

@media (month: 12) and (1 <= day <= 24) {
  body {
    background-image: url('christmas-decoration.svg');
  }
}

@media (2023-11-20 <= date <= 2023-11-26) {
  .event-price {
    background-image: url('black-friday.svg');
  }
}

@media (10pm <= time <= 4am) or (22:00 <= time <= 04:00) {
  .logo {
    background-image: url('night-owl-logo.png');
  }
}

Talking about dates and times, the issues I can see are the focus on the Gregorian calendar and the format in which they are expressed.

PS: I believe for dark mode we have better solutions that respect the user preference.

Absolutely agree. I just took the example from that page which uses fixed times.

Sebastian

dbaron commented 7 months ago

I'm somewhat skeptical (though I could certainly be wrong) that a feature like this would be widely used given the way it makes styles harder to test. I suspect many developers would prefer to push changes around specific dates when they want different styles, because those changes can be more easily tested in advance of pushing them.