1

tl;dr

  • Is there a WAI-ARIA-compliant way to format dates according to language/country?
  • My intention is to show dates (for instance the date a post was published on a blog) in a way that varies depending on factors such as the screen width, and the language of choice of the user (English vs other language); these are just two examples I can think of (I think I'd use a @media (max-width: whatever) CSS rule to address the former need, and target elements based on the lang attribute for the latter).

I first thought how do I format a date according to one or another convention (e.g. british vs american, month as a number vs as a word, ...) using CSS? and I found this question where one of the answers suggests a way to use CSS to format dates, and one could build on that to provide classes specific to countries/formats, and then some inputs from the user (choose the country/language) plus some JavaScript could encode the logic to show dates in one format or another.

But that answer assumes that the parts of the date made different HTML elements, like in the following snippets:

<div class="date-wrapper">
  <div class="date-year" val="1994"></div>
  <div class="date-month" val="03"></div>
  <div class="date-day" val="09"></div>
</div>

The above can be styled with a fairly articulated, long, and repetitive set of CSS rules. If it was just this, I would be ok with it. I'd put the CSS in a file, and forget about it.

But the point is, I think the above HTML snippet really is just a random blob of stuff to a screen reader, which would not present it as a date, but just as "a div with 3 divs each of which has a number as its val attribute". Just blob.

So my next thought was before I even think of applying a style to a date, how do I even encode that a string like 1/12/2021 written somewhere in my HTML is a date? And so I found that there is a <time> HTML element, and I found that it can't help me in this respect.

Enlico
  • 23,259
  • 6
  • 48
  • 102

3 Answers3

2

And so I found that there is a <time> HTML element, and I found that it can't help me in this respect.

1. Use the <time> element! (screen readers and SEO)

You should use the <time> element in HTML as although it can't help with the visual problem you have it will certainly help solve the issue for screen readers and search engines when combined with some visually hidden text.

HTML

<time class="date-wrapper" datetime="2021-10-23">
  <div class="date-year" data-val="2021"></div>
  <div class="date-month" data-val="10"></div>
  <div class="date-day" data-val="23"></div>
  <!-- not visible, accessible to screen reader though which when
       combined with the `datetime` attribute on a `<time>` element
       should announce correctly to most screen readers, even if
       dates are in a different format in their Country (although try
       and set it correctly obviously!) -->
  <div class="visually-hidden">23/10/2021</div>
</time>

CSS

.visually-hidden { 
    border: 0;
    padding: 0;
    margin: 0;
    position: absolute !important;
    height: 1px; 
    width: 1px;
    overflow: hidden;
    clip: rect(1px 1px 1px 1px); /* IE6, IE7 - a 0 height clip, off to the bottom
                                    right of the visible 1px box */
    clip: rect(1px, 1px, 1px, 1px); /*maybe deprecated but we need
                                      to support legacy browsers */
    clip-path: inset(50%); /* modern browsers, clip-path works
                              inwards from each corner*/
    white-space: nowrap; /* added line to stop words getting smushed
                            together (as they go onto seperate lines
                            and some screen readers do not understand
                            line feeds as a space */
}

Couple of notes here:

  1. Don't use val as an attribute on a div or a span, it isn't valid. I changed it to data-val but I have no idea why you are using an attribute and leaving the contents blank so I can't offer any further advice.
  2. If you believe you should leave the three divs empty then you should add some visually hidden text with the date in for screen readers as a backup.
  3. I might be tempted to add aria-hidden="true" to the original 3 divs, but that doesn't seem to be necessary (unless you are dynamically adding the actual content to them, in which case you should and use the visually-hidden bit to add the date for screen readers), e.g:
<time class="date-wrapper" datetime="2021-10-23">
  <!-- hide these if they have any actual values in them -->
  <div class="date-year" data-val="2021" aria-hidden="true">2021</div>
  <div class="date-month" data-val="10" aria-hidden="true">10</div>
  <div class="date-day" data-val="23" aria-hidden="true">23</div>
  <div class="visually-hidden">23/10/2021</div>
</time>

2. Use JS to format the date (Visual Ordering)

Luckily this has become 100 times easier thanks to Intl.DateTimeFormat. It now has great support so I wouldn't hesitate in recommending it (and polyfilling it with moment.js if you need to).

Two lines of JS can give you a localised time and date, then you can just strip the information you need from that.

const date = new Date(Date.UTC(2021, 10, 23, 9, 00, 00, 000)); // you would just use current time more than likely.

let formattedData = new Intl.DateTimeFormat('SET YOUR LOCALE HERE').format(date);
// You now have the date in the right order so can strip the parts out by converting the date to using string splitting!


// build the element dynamically, change the order of the items in JS or move the classes around with JS.

You may find this answer interesting on how to use the .formatToParts function that seems to do what you need, but I have never used that personally.

Anything I missed?

Obviously if you want to further explain why you have structured things this way then we can offer better suggestions here!

Any questions just ask!

Enlico
  • 23,259
  • 6
  • 48
  • 102
GrahamTheDev
  • 22,724
  • 2
  • 32
  • 64
  • _I have no idea why you are using an attribute and leaving the contents blank_; that's copy-and-paste from the linked answer. I think the reason is that answer has CSS targeting the attribute. – Enlico Oct 23 '21 at 08:29
  • Ah I see, if you go the JS route then it becomes unnecessary as you can just set the actual content, but that makes sense. It will work fine with the method I gave in section one though using visually hidden text and the ` – GrahamTheDev Oct 23 '21 at 08:55
  • Yeah, but at the same time solution 1 brings with it a lot of content duplication each of day, month, and year are repeated 4 times... Anyway, I'll try to give you a concrete example: for the purpose of learning HTML+CSS+JS, I'm trying to set up a multi-language blog ([work-in-progress here](https://aster89.github.io/)) and I'd like to have the date associated to each post to be formatted according to the language the user picks; and also, why not, according to the space available on screen (this latter thing seems to unequivocally call for a CSS solution). – Enlico Oct 23 '21 at 08:59
  • No no, sorry I wasn't clear ‍♂️ (my fault!). Using the ` – GrahamTheDev Oct 23 '21 at 10:50
  • Don't you think it's over complicated ? Also, none of the screen reader I know currently threat ` – QuentinC Oct 23 '21 at 12:24
  • @QuentinC The whole reordering with CSS thing is too complex, I would just render it on the server in the right format and be done with it. But that isn't answering the question (and I preach too often ), so I was showing the best way to achieve what OP asked for, which would be the ` – GrahamTheDev Oct 23 '21 at 13:49
1

There is no ARIA markup that makes dates more readable by assistive technology.

The JavaScript date constructor is the best tool available for creating dates that can be manipulated to different formats, time-zones, regions, languages, etc.

<script>
    const date = new Date();
    // Fri Oct 22 2021 12:48:56 GMT-0500 (Central Daylight Time) {}
</script>

Once you have the date as an object, you can use Date.toLocaleString() to convert the date to other formats. For example:

<script>

    date.toLocaleString();
    // '10/22/2021, 12:48:56 PM'
    // (uses default settings of visitor)

    date.toLocaleString('en-GB', { timeZone: 'UTC' });
    // '22/10/2021, 17:48:56'

    date.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })
    // '2021/10/23 上午1:48:56'
</script>

For good measure, ensure that your page is always using a language attribute.

You'll also get better and more consistent results from assistive technology by using non-abbreviated full-text dates.

Examples:

Friday, October 22, 2021 
// easily read by all screen-readers

1/5/21 
// could be read as May 1st by en-GB visitors, if language attribute not set

Sun Oct 24 2021
// some screen readers may read exactly as written "sun oct 2 4 2 0 2 1"
Josh
  • 3,872
  • 1
  • 12
  • 13
1

In general, when CSS change the order in which elements appear on screen to make it different from the order in which it appears in the code / DOM tree, it should make you tilt immediately. Unless you have really good reasons, you should never do that.

The first problem of doing that is of course that screen reader users will read the content in the wrong order. Screen readers always read content in the order it is in the DOM. You can't change it in any way.

You are also going to create troubles for partially sighted users who use a screen magnifier, and those who don't use a mouse or a touch screen, because the natural keyboard focus order will appear illogical. When going through focusable objects using tab, users will have the impression that it "jumps" somewhat randomly, and/or will lose sight of where the focus go. Natural keyboard focus order always follows DOM order. You can change it, but it's a terrible idea.

Third, you are also going to create troubles for those who navigate without CSS. There are probably not that many human people going on the web with a text only browser nowadays, but in this category also goes search engines and many other useful robots.

For all these reasons, and as you have correctly understood, using CSS to fix that kind of thing is very bad. It's even more bad for a date, since you may not figure out at all that something appear wrong.

As the other answer already says, use date formatting functions of your programming languages whether server or client side, so that they appear correctly in the page in any circunstance.

Enlico
  • 23,259
  • 6
  • 48
  • 102
QuentinC
  • 12,311
  • 4
  • 24
  • 37
  • You explain the reason why changing via CSS the order in which elements appear on screen wrt DOM tree, but actually my question only indirectly implies that, in the sense that changing date format doesn't necessarily mean writing `June` instead of `6` for the month, but also writing month before day or viceversa. Is this the _order_ you refer to in your answer? – Enlico Oct 23 '21 at 14:03
  • You shouldn't use CSS to make the order visually different than it is in the DOM. It's much better to use formatting functions and just write the final formatted date in plain text. You can't be simpler and it works all the time. That's what my answer is about. Which one is better to write between 6, 06, Jun or June, or more generally which exact format to use, is another question. – QuentinC Oct 24 '21 at 08:00