Blogging my blog

This blog entry is the changelog of my blog site. The content is sorted from the newest to the oldest.


June Revamped the metadata box structure to also show the author(s) in the narrow view. Removed the social sharing components. Improved focus management in keyboard navigation. Improved the styling of a tags for printing. A hack is added to make sure Edge (Chromium) renders WeChat screenshots correctly in High Contrast mode. (Edge Chromium does not seem to apply High Contrast adjustments to pseudo-elements.)

Annotated equations are now given ARIA role img instead of math for better compatibility. Previously, they have the following form:

<span role="math" aria-label="x squared">
  <span aria-hidden="true">

The point of annotation is to provide precisely what the screen reader should read for the equation. For example, instead of letting the example being read as ‘x squared math, x, two’, the part ‘x, two’ is hidden from ARIA. They are read normally by Edge/Narrator (Windows 10) and Safari/VoiceOver (iOS). However, hiding the content and leaving just a math object with annotated text makes the content unreadable in Chrome (as of version 85.0.552.1) and Safari for macOS. The content is recognised in the accessibility tree, but does not seem to be reported to Narrator. By changing the role to img, the descendants are now ignored and the equation is read as a whole. (This is intended to be a hack.)

March Completely removed Atom feed from the website. (Its support was dropped on 9 June 2017 and it has not been advertised since then. The output is now gone in the hope that no one is subscribing to it.) Added support for large Twitter card. Added support for minification (not fully minified). Started producing rel="noopener" for target="_blank" cross-domain links. KaTeX formulae are resized for aesthetic reasons. Implemented tag frequency visualisation:

Tag Frequency VisualisationTag Frequency VisualisationTag Frequency VisualisationTag Frequency VisualisationTag Frequency Visualisation
Tag Frequency Visualisation

February Friends section is no longer available for link exchange. Fixed an issue of tag layout. Added new narrow layout for BibTeX (see entry in Chinese).

January Removed certain compatibility shim from the script. Fixed a problem of CSS in High Contrast mode.

November 2019

3: KaTeX 0.10.1 support is dropped and replaced by 0.11.1, because 0.10.1 cannot render \not, \neq etc. correctly.

October 2019


There is a new way to put labels — anchors. Use `anchor:<label id>` to create a label that always occupies space (except when printed). This avoids reflowing the document. For example:

Theorem 1 (Viète). Let be the roots of then

Proof (Theorem 1). Trivial. 

Remarks. Theorem 1 is known to the Babylonians.

Moreover, note (footnote/endnote) functionality is provided.* To create a note mark, use* `fnmark:<note id>:<ref id>`. The fnmark command creates a superscripted note mark. To reference it without superscript, use `fnref:<note id>:<ref id>`.

Notes are numbered by the order they’re referenced, not by the order their labels are provided using `fntext:<note id>`. In the entry metadata, you can specify whether or not to use footnote symbols, and the default is no. There are 9 of them,§ and when they run out, subsequent notes revert to arabic numerals. Moreover, it is possible to have a note without a note mark and even without a reference! Note  has a reference, but subsequent notes have none, except for the last one.** Unreferenced notes get numbered by the order their labels appear after numbers are assigned to referenced ones, so if an unreference note’s label appears before a referenced one, the order is going to be messed up, like Note **.

For example, this note text appears earlier but is the second one.

* For example, this is a note.

This can be done using FnSymbol Boolean attribute.

§ As you might have imagined, they are the same as LaTeX footnote symbols.

This note does not have a superscripted reference.

Note 6. †† Note 7. ‡‡ Note 8. 10 Note 9. 11 Note 10. ** Note 11.

August 2019


A new mechanism is introduced for BringIntoViewNicely for better anchor navigation. Suppose :target is #a, th element a has attribute gl-bringintoviewnicely-union of value b, and #b exists, then BringIntoViewNicely takes both elements’ bounding rectangles into consideration. The extensions `bibitem:...` (implied by BibTeX in blog), `ref:...` and `label:...` will have gl-bringintoviewnicely-union set.

  • Usually, the target for `bibitem:...` is already produced by BibTeX for blog, which is usually the containing element for the reference (so that the entire reference information is brought into view). Nevertheless, the actual element ID is bib_<safe id>_item, where <safe id> is the hexadecimal representation of the UTF-8 encoding of the citation key in lower case (e.g., a is encoded as 61).
  • The target for `ref:<label id>:<ref id>:<html>` is ref_<ref id>_target. The target for `label:<label id>` is label_<label id>_target. Note that <ref id> and <label id> never contain underscores.
  • This change is backward compatible, because no change is observed if the element referenced by gl-bringintoviewnicely-union doesn’t exist.

Finally, the cross-reference extensions will produce links instead of buttons.


The old `ref:REFNAME` has been changed to `ref-old:REFNAME` in favour of the new label and ref commands. The new commands are customisable. For example, `ref:fig1:first-ref:Figure 1` yields Figure 1. Here’s another reference to Figure 1. The label can be inserted as `label: fig1`, where a leading whitespace means there needs to be whitespace before the ‘go back’ button. Here’s how it looks like: Figure 1. The major benefit is now the ID of the elements are stable and within user’s control (previously, the IDs are generated based on the order of appearance), so that when an entry is updated, previously stored bookmarks still jump to the correct position (if applicable).

BibTeX-TS is introduced to support citations. For a more comprehensive introduction (in Chinese), see this blog entry. Here is a simple example: One can use `cite:vtn,zkphw` to get 21. The bibliography is included below, written using a Markdown code block with blog-bib as its language.


1 I. Damgård, J. Luo, S. Oechsner, P. Scholl, and M. Simkin. Compact Zero-Knowledge Proofs of Small Hamming Weight. In M. Abdalla and R. Dahab, editors, Public-Key Cryptography – PKC 2018, pages 530–560, Cham, 2018. Springer International Publishing.
2 T. F. Lau, J. Luo, S. Zhao, E. I. Chang, and Y. Xu. Unsupervised 3D End-to-End Medical Image Registration with Volume Tweening Network. CoRR, abs/1902.05020, 2019.

July 2019


Many links are now rel="nofollow" so that PageRank will distribute the weights better (previously, the degree of a tag grows quadratically with the number of entries with it). Plus, the sitemap is implemented (at /sitemap.xml).

April 2019


KaTeX 0.10.1 supported is added and is the default version of KaTeX for new entries. As promised, the presence of \@arialabel{delim{annotation}delim} is compulsory beginning this version. The major reason to introduce this version at this time is to have the feature to easily embed a punctuation immediately following an inline equation into a span element with white-space: nowrap; to prevent miserable line-breaks. This is a known issue of KaTeX. Now, I can write The determinant is denoted `math:\@arialabel{{D-E-T of M.}}\det M\@nobreak{{.}}` to get this: The determinant is denoted Embedded characters can also be added at the beginning of an inline equation. Moreover, more sanity checks are added to prevent common mistakes (e.g., write the annotation but forget the body).


Metadata of entries can specify tile images instead of using the hero image. Specifically, three new properties TileImageSquareCover, TileImageWideCover and TileImageFloat are added. For the ease of usage and backward compatibility, they are resolved like this:

  • If the property is set in the entry’s metadata, convert it to an absolute URI with the entry’s URI as the base URI.
  • If the property is not set and the entry has a hero image, use the hero image. This behaviour is consistent for entries with a hero image before the introduction of these properties.
  • If the property is not set and the entry doesn’t have a hero image, TileImageSquareCover falls back to the site’s square tile image, TileImageWideCover the site’s default wide tile image, and TileImageFloat the default hero image. This behaviour improves the presentation of those tiles.

Many old entries also got their metadata updated to take advantage of this feature. Moreover, a check was performed to make sure the assets chosen as tile images are fully compliant with the documentation (200 KB or smaller and within 1024x1024; previously the dimension requirement was overlooked).


The blog builder is refactored to support the following:

  • Selection of Markdown compiler based on metadata. Previously, the functionality was imagined to be implemented by renaming the entry main file, e.g., v.s. Now the resolution of metadata is done before the file is sent to Markdown compiler, so one can specify which Markdown compiler to use. Recall that on 13 December 2018, the blogging system was updated to allow choice of KaTeX version. Same for Markdown compiler now. However, as of today, the only available Markdown compiler for my blog is marked 0.3.6.
  • Faster utility invocation. Back on 24 May 2017, I switched from IE object model to Node.js and added caching. As the blog grows, it is wise to further optimise the building process.
    • Previously, the blogging system will create a process each time a JavaScript utility is needed. For example, if there are 10 entries missing from the cache, 5 of which has modified maths formulae, then a total of 15 Node.js processes will be created during the building process. Each time PowerShell passes the file to be processed as a command line argument to the newly created process and waits for it to finish. Process creation bears a significant overhead, especially for a lot of small tasks.
    • Now, the blog builder has a new way of invoking native utilities (including JavaScript ones hosted by Node.js). The model is inspired by component objects in single-use local servers.
      • Utilities are now abstracted into ‘piped services’ that process an input file, produces an output file and optionally reports any exception in an error file. One can launch instances of services, each of which will be hosted in a separate process. The server process (Node.js) and the client process (PowerShell) communicates via named pipes (or FIFOs on Unix).
      • Since the services are static in my case, the client can create just one instance and reuse it. As of the writing of this entry, this means at most 3 Node.js processes are created, even when building without cache.
      • Each time the client needs the service, it marshals the data, sends them over the pipe, and then waits for the data to come from the other pipe.
      • Each time the server receives data over the input pipe, it unmarshals the data, performs the operation, marshals the result and sends it back to the client.
      • Concretely, PowerShell sends three lines to Node.js, the paths of the files. PowerShell then sits and waits for 4 bytes to come, which it interprets as an HRESULT. If the result is S_OK, PowerShell then fetches the result from the output file; if it is E_FAIL, PowerShell reads the error message from the error file; otherwise, the HRESULT is interpreted in the canonical way. Each time Node.js receives three lines of text, it processes the request and writes an HRESULT to the pipe. There is also a way, agreed in advance, to indicate the server should shut itself down. In the implementation, there is one single surrogate server for all the utilities, which accepts over the command line the utility module and the pipe paths.
      • The RPC is carefully implemented to accommodate both Windows NT and macOS in one C♯ source file.
    • Ideally, the pieces of the builder can be written in C++ in COM fashion, and compiled on Windows as COM (and on macOS with custom RPC stubs; or with a subset of COM available on macOS). The whole thing will be highly efficient. The goal is always there, but time isn’t permitting.
    • This refactoring of RPC keeps the building result intact, and significantly shortens building time without cache. Yet the reality there are only a few entries (or even just one) that changed since the last build.


A superb revamp! The main contribution of this wave of update is making interactive elements less distracting by maximising the coherence before/after an action, avoiding blurring you from what you have been staring at for long.

  • Prolonged theme memory. The expiry of the chosen theme (the time before the website reverts to deciding theme based on current time) is significantly extended, and every time a new page is loaded, the expiry gets refreshed.
  • Better Disqus integration. Anchor linking into the comments should work perfectly now. Previously, the anchor linking doesn’t work in the landscape view, and it fails on Microsoft Edge in potrait view (because Edge does not automatically cascade the scroll into scrollable ancestors when the height is unset, and the lowest scrollable ancester of Disqus is a dedicated div element). Now it should work perfectly in Microsoft Edge, Internet Explorer, Chrome and Safari in either view. Note that there is a known bug in Chrome that makes Disqus iframe disappear in the landscape view once it is scrolled.
  • Improved bookmark hyperlinking. When JavaScript is enabled, the targeted element is aligned around the center of the viewport. The current implementation can force the animation without having to insert dirty history entries.
  • Page position management. Now pages remember where you left them within a session. When you return to that page in the same session, it tries to pick you up where you left. This feature works best if the size of the viewport remains constant. There is no attempt to align portrait/landscape view, so if the view has changed, the page position will be forgotten. Moreover, bookmark hyperlinking has priority over remembered position.
  • Collapsion state management. In memory to this feature implemented 2 years ago, now most collapsible sections will remember their state. This makes sure that when refreshed, the page layout does not change, and you will always stay where you were.
  • Aligned collapsion of collapsible sections. Usually a long collapsible sections has two collapse buttons, one at the beginning and the other at the end. Previously, if you click the button at the end, we try to scroll the collapsed section into view (because the expanded version is so long that when collapsed, other content might be pushed up). However, the previous attempt is to scroll the area to the closest edge of the viewport, which is not quite satisfactory and still brings the reader out of the previous context. This has been improved to try to align the upper-left corner of the collapsed section to the space previously occupied by the collapsion button. In the landscape view, the vertical position cannot be controlled; in the portrait view, the horizontal position cannot be controlled. It is nevertheless an improvement. In most cases, the alignment is perfect in the portrait view as the expansion/collapsion buttons are already vertically aligned. See this entry.
  • Unified wide portrait view and landscape view. Now it is guaranteed that the effective width of a column is never below 720px when the view port is at least 720px wide. Previously, the wide portrait view is defined as viewport width 720px to 1600px, and anything wider than that is the landscape view. In the landscape view, the width of a column could be as narrow as 710px, making it hard to typeset the content in a simple, uniform and elegant way. Now the margins and the thresholds have been redesigned so that the layout of the page should be consistent above 720px.
  • Dedicated storage management. The local/session storage now uses COM moniker style naming (well just knock-offs, haha). Backward compatibility is retained upon seeing the new website, i.e., previous users should have their last seen prompt and chosen theme retained (the latter not expired).
  • Markdown anchor syntax extension. Specify nofollow:, follow:, blank:, self: in the beginning of an anchor to control the target and rel attributes. E.g., [Click here](self:nofollow:// generates <a href="//" rel="nofollow">Click me</a>. Note that the Markdown compiler customised for my blog builder determines any URLs with explicit http:/https: protocol and any protocol-relative URLs should have target="_blank", so nofollow: overrides it.

March 2019


Fixed @font-face rules to make punctuations render correctly. Formerly, the font selection is correct only in Microsoft Edge and Internet Explorer. Now it’s correct on Safari and Chrome. Improved styling for ‘fancy quotes’.


The website now has 115 entries (and counting!), which might create problems for RSS subscribers. Wikipedia suggests the maximum size of RSS feed be 150 KB. Given the feed contains only abstract plus some metadata, I believe 50 is a safe bound. I also made sure the RSS feed is fully compliant per RSS 2.0 specification.

469 days after I reported the buggy implementation of pinned website tiles of Edge to Microsoft, the problem has not been fixed, and I finally decided to give it a . I have worked around the issue by coding all the information in the page (instead of isolating them into browserconfig.xml). Presumably Windows (Phone) 8.1/10 users can pin the homepage (or the archive page) and see the 5 latest entries cycling there. I also made Live Tiles available for each individual entry, so if you pin an entry to Start, it shows the title, the abstract and the hero image (unless the size is Small or Live Tile is turned off). Friend/tag index/individual tag/404 pages do not have Live Tiles.

February 2019


Improved hero image listing. Prior to this update, the hero images must be stored in this domain, posts can only provide the hero images as relative paths to the post itself, and those relative paths are converted to absolute URIs under my domain during the building process. Now the hero image can be anywhere and posts can specify any URI for the hero image. Many metadata formats set using absolute URIs as the best practice, and the building system did and will do so. However, on index/archive/tag pages, the hero images will be specified by an absolute path (instead of an absolute URI) whenever the absolute URI is actually under this blog domain. This creates no observable difference for the audience and merely improves my writing and debugging experience, as I now can see the hero images on index/archive/tag pages of posts in progress.


A homemade extension is added to the blogging system so that it now recognizes `math:\@arialabel{delim{f, a function from A to B, maps x to f-of-x}delim}f:A\to B,x\mapsto f\left(x\right)`, renders f:A\to B,x\mapsto f\left(x\right) with KaTeX and puts it inside <span role="math" aria-label="f, a function from A to B, maps x to f-of-x."></span>. This makes the content easier to narrate, and as a by-product, it works around the buggy bounding box detection by Narrator. (The comparison between unannotated and annotated equations is removed, because this entry uses a version of KaTeX that disallows unannotated equations.) It is optional to annotate mathematical equations at this moment. Starting the next version of KaTeX used in the blogging system, which might take months to years to happen, annotating mathematical equations will be mandatory. As of this update, VoiceOver with Safari on macOS doesn’t read the label, rendering the maths elements totally inaccessible, whereas Narrator with Edge on Windows as well as VoiceOver with Safari on iOS reads the maths the intended way. I deem buggy the behaviour of VoiceOver with Safari on macOS, since the standard calls out such usage pattern and the other two work very well.

January 2019


The blog building system has always been running on Windows. With a few portability tweaks, it now works on macOS, producing consistent result with Windows. See this post (in Chinese).


The prompt notice feature is implemented. Currently, the prompt is used to show the privacy notice to the visitors. The prompt shows only if JavaScript is enabled. When the prompt is shown, the page is dimmed, navigation animation is played for the dialog and focus is put on the default button of the dialog. The prompt does not hide or prevent interaction with the main content, thus not modal. Not dismissing it merely makes reading and interacting with the content unpleasant.

December 2018

23: Did you come here from 13 April 2019? Click here to go back to the future!

in this blog hasn’t been updated for a while. Since some new features are needed, the blog metadata now contain the version of KaTeX to be used (default is to use the oldest known version, 0.7.1). Any new entries created after this day should be using 0.10.0 or later. External assets from KaTeX are now versioned hence moved. If you are seeing any incorrect rendering, flush the cache. The specific new feature used in the entry created on this very day is \hline support for array environments.

October 2018


Google Plus share button is now removed. Google kept silent for 6 months since it discovered and patched the bug of disclosing fields not explicitly allowed by the user via API. According to Google, the bug was not found to have been maliciously exploited. The company is on the way to discontinue its social network.


  • Shrank the font size. Changed the title element in archive pages from h3 to h2 for better semantic Web. Retouched the stylesheets.
  • Fixed a problem in scrolling after collapsing collapsible content.
  • Improved image theme-awareness options. Prior to this update, an image can be either High-Contrast-aware or not, and a High-Contrast-aware image has 4 editions (non-HC, HC black, HC white, HC other). After this update, an image can be theme-unaware, High-Contrast-aware or fully theme-aware. A fully theme-aware image has 5 editions (light theme, dark theme, HC black, HC white, HC other). The demand for this feature arises from typesetting commutative diagrams (which KaTeX currently does not support) and generalises for images that only have a very thin part with color, like commutative diagrams do. For printing, the light theme edition is always used, and if the figure has a clickable caption, that link defaults to the light theme edition.
  • Extended the image extension to insert inline images.

July 2017

24: Implemented a handy chat log conversion tool. Use iPhone-SE-WeChat6 code block to generate chat history that resembles WeChat version 6 on iPhone SE. Inspired by this post on V2EX (in Chinese), the implementation is CSS-based, scalable and printing friendly (it switches to another set of styles when printing). Raymond Chen is also good at creating screenshots with CSS. Example: write

WeChat chat history with Sometwo

* 13:52
r ( S ) [ Sometwo ] Hi there!
* “Sometwo” has recalled a message.
s [ Me ] [Shocked] What did you recall?
r ( S ) [ Sometwo ] A typo.



Hi there!

“Sometwo” has recalled a message.

Shocked What did you recall?

A typo.


June 2017

23: Added a simple reference extension. Use `ref-old:REFNAME` (previously `ref:REFNAME`) to generate a link with text ’ ‘[REFNAME]’. In any location of the document, put a `ref-back:REFNAME` to indicate the position of the reference. There can be multiple references to the same target. For example, the following code

Reference 1 to `ref-old:EXAMPLE` and reference 2 to `ref-old:EXAMPLE`.

- `ref-back:EXAMPLE` The source of example.


Reference 1 to [EXAMPLE] and reference 2 to [EXAMPLE].

  • [EXAMPLE] The source of example.

Clicking one of the two links will target the current document to the source with a button that allows one to return to the correct position.

9: RSS 2.0 and Atom 1.0 syndication are provided. The syndications contain basic metadata (title, dates, abstract, tags, link etc.). Full-text syndication is not expected at this time.

  • Later that day: Support for Atom has been dropped. RSS feed has only one date to specify, pubDate. I put the DateModified property of a post there. For Atom feeds, there are published and updated, into which DateCreated and DateModified are popped. Some Atom feed reader (e.g., Feedly) sorts the posts by its published, which is against my design, while some other reader (e.g., Internet Explorer) sorts the posts by its updated. To avoid inconsistency, Atom feed is no longer an option offered to the users. Moreover, RSS feed allows in a consistent way to convey the link to the comments.
  • Why is full-text syndication not expected? Because certain content can only display correctly with the site’s stylesheet. Examples include KaTeX formulae, images that have High Contrast version (only one version is displayed at a time) and collapsible content. Alternative styling does not give authentic experience of the blog, which is also the reason why I discourage using Reading View (or similar features) on my site. To obtain perfect and designated static appearance, print the page, which also gives the best reading experience (if always expanding all the collapsible sections is acceptable).

8: The site builder has been rewritten (refactored). It is now more extensible and the code is more beautiful.

May 2017

27: Added a new ‘fancy quote’ style, support for KaTeX and heading ID syntax (### heading 3 #heading-id).

  • Fancy quote: Style sheets format with a large double-quotation mark (type 66, or ‘“’) when under normal themes. This type of quotation also adds styles (italic or bold, depending on the culture set on the elements) and centers the quoted content.
  • KaTeX: Now `tex|latex|math|katex:…` are reserved for inline KaTeX formulae and `display|displaymath:…` are for display KaTeX formulae. To define a macro, use ```tex-macro, ```math-macro, ```latex-macro, ```katex-macro code block.
    • The conditional comment version of these things are <!--[blog][katex] KaTeX inline math [blog]-->, <!--[blog][katex-display] KaTeX display math [blog]--> and <!--[blog][katex-macro] \CommandName Value [blog]-->. This can be used to define a whole formula so that you can easily embed a display formula into a paragraph without a hassle.
  • Heading IDs: Formerly the automatic ID generation was removed so that they are more controllable and explicitly expressed. Now with another syntactic sugar you can easily add a predictable and permanent ID while enjoying every benefit of Markdown.

24: Improved printing experience. Improved anchor jumping experience. Upgraded to marked 0.3.6 and started to use Node.js. Added my own flavour of Markdown to the program. Improved the performance of building the blog.

  • Printing: <abbr class="obscure-abbr" title="Microsoft Developer Network">MSDN</abbr> will display as MSDN (Microsoft Developer Network) when printing. If the language of that abbr is Chinese, it will be 白骨精(白领、骨干、精英).
  • Anchor jumping: When JavaScript is enabled, after each jump, the :target element will be blinked.
  • Markdown flavour:
    • Use 4k+1 to 4k+4 numbers of ` to represent different semantics — code fragment (<code>), program output (<samp>), keyboard key (kbd) and mathematical variable / simple formula (var). They look like: 1 | Write-Output, 1, Shift and x.
    • To remember this rule, remember that longer tag uses fewer backticks, and for the same length, the order is the lexicographical order.
    • The semantics of program output include file names, paths, URIs (if not made a link) and any program output.
    • If the first (or the last) character inside an inline ` thing is a space character, it (or they) will be removed from the output, with the requirement of matching the length of opening and closing markups, one can create such inline elements with any number of preceding/succeeding white spaces as well as the backtick itself.
    • If the language of a code block is not specified, it will become <pre><samp></samp></pre>, otherwise it is <pre><code lang="code-<lang>"></code></pre>.
  • Building tool (Did you come here from 13 April 2019? Click here to go back to the future!): I have completely remove the dependency on Internet Explorer COM. Node.js is now reliable for running the JavaScript code to compile my Markdown document into HTML, which will be processed by my PowerShell script again. Now the script also holds a cache of compiled HTML. In case the content does not change, the building script simply retrieves the compiled HTML from the cache. This somehow improve the embarrassing performance impact brought by Node.js — I have to use it in an inter-process fashion (using redirect standard streams). It is naturally slower than the previous COM approach. With the cache technique, it can be expected that in the future the speed will be faster.

22: Improved theme experience (dark/light/high contrast). Implemented multi-cultural punctuation font selection. This only proves that Zhihu is pretentious on the quotation marks issue for long. See Jixin Huang’s Zhihu answer on this issue and Zhihu’s official guideline on ‘typesetting by modifying the content’. I would say that adding extra space characters between appropriate boundaries of Chinese script and Latin script is also typesetting by modifying the content. However, detecting the correct boundary to insert extra space is quite hard, and I’ll just go with it until I could make up any better method than inserting space characters manually. The problem of quotation marks (and other punctuations) is solved by adding appropriate lang attributes to alter the font-family. It is noticeable that adding lang attribute is contributing not only to automated font-family selection, but also to many more things, e.g., automatic RTL, accessibility for screen readers (it is possible to select the appropriate TTS engine, instead of the one for the system locale or the specific one chosen by the user that only reads one language, from that attribute).

  • Font selection: Now the HTML documents are extensively marked with culture (lang attribute of elements) and for lang being zh or zh-*, the Chinese Yuan / Japanese Yen character, the quotation marks (“, ”, ‘ and ’) and the ellipsis character are rendered with a Chinese (Simplified) font so that the height and the width of the characters are correct with the ellipsis being vertically centred. Compare:
    • 中文文本:“这是一句‘引语’……”
    • Latin script: ‘This is “quoted”…’
  • Theme experience: When the theme is changed, a dialog might appear to ask if you would like to reload Disqus.
    • Disqus is never reloaded when the theme changes to a High Contrast theme, because Disqus follows High Contrast adjust.
    • You might want to reload Disqus when you switch to the light theme or the dark theme.
    • If Disqus was never scrolled into the view since last reload, it is automatically reloaded when you switch to the light theme or the dark theme.
    • If Disqus has been scrolled into the view since last reload, there might be a chance that you have written your comment but have not posted it yet, therefore, you will be prompted.
    • A bad thing about the window.confirm method is that the initially focused button is ‘OK’ instead of ‘Cancel’. This is against the principle that the default answer to every dialog box is ‘Cancel’.

19: New navigation design and Friends section. Improved multi-cultural support for authors and tags.

  • Navigation: The navigation links display icons now. For the best effect, use Microsoft Edge.
  • Friends section: Now you can apply for a position in the Friends section. The link you provide must direct to a fruitful web page, comply with content code and the law. As a fair exchange, You should provide a link to my blog or my curriculum vitae to the website to appear here. Note that applications are subject to rejection for any reason or without a reason. To apply to be listed, go to Friends section and send me an email (see the footer).
  • Multi-cultural support for authors: Now authors (or the author) use a localised name for each entry. If a perfect match is found, that name is used; otherwise, if a partial match (matching the language, not the region) is found, that name is used; otherwise, the invariant name is used.
  • Multi-cultural support for tags: Each tag’s page is in the tag’s intrinsic culture.
  • Multi-cultural model: Each multi-cultural resource (author display name, tag display name, etc.) has a set of tuples (Culture, Value). These resources, when used, are instantiated under a chosen theme culture, which can be the culture of the blog entry, the intrinsic culture of the tag, etc.
    • When instantiating a multi-cultural resource:
      1. The program tries to find the exact matching culture; if such a match is found, the Value of the match is used;
      2. Otherwise, the program tries to find exact matches in language (e.g., in this stage, en-US and en-GB are matches, while fr-FR and da-DK are not); if such matches are found, one of them is used (tie-breaking is implementation-defined);
      3. Otherwise, the program resorts to the intrinsic culture of the resource (e.g., the intrinsic culture for OneDrive tag is en-US, because this is a word coined by Microsoft, a company in the United States, and the intrinsic culture for Tsinghua University is zh-CN, because it is located in PRC).
    • Internal representation of multi-cultural resources:
      • The code name of the resource is always in plural form (e.g., Names instead of Name);
      • The property is always an array of objects in the form { Culture: "???", Value: "???" };
      • Conventionally, the first item in the array has its Culture being "Invariant", and its Value is one of the concrete cultures in which the resource is localised; this Value, whose accompanying Culture is "Invariant", is the intrinsic culture of the resource;
        • For an author, this is the culture in which he or she prefers to write his or her name; if not explicitly specified, it is often chosen as a culture that uses Latin script;
        • For a tag, this is the origin of the words in the tag and relates to the origin of the thing the tag represents;
      • Conventionally, the second item in the array has its Culture being the intrinsic culture, and the Value is the version used for any non-matching case;
      • The following items are localised versions of the resource.

April 2017

14: Improved accessibility and clipboard-friendliness.

  • Accessibility: The comment-count links and the article items are labelled. More elements have more accurate role property.
  • Clipboard: The navigation links are empty so that they will not be copied in the HTML form. The content comes from pseudo-elements now. Previously this was only done to theme switchers.

13: Implemented social sharing components. Improved accessibility.

  • Social sharing: It is possible to share blog entries on select social networks with buttons near the title.
  • Accessibility: Added aria attributes to some elements and added localised labels.

11: Improved printing exprience, High Contrast experience and multi-culture. Began writing this meta-blog entry.

  • On listing pages, in High Contrast theme or in printing view, the ‘? 💬’ comment-count boxes (or ‘💬’ comment buttons for no-script environment) will display as text in appropriate cultures, such as ‘no comments yet’ or ‘1 条评论’ (or ‘des commentaires’ for no-script environment).
    • A technique in Disqus: I used <span data-cnt={num}><span>💬</span></span> as my plural-comment text template. It took a while for me to compress it. To display text with correct culture, use selectors looking like span:lang(fr)[data-cnt=1]::before. This enables dual for some languages. You need two spans because you want to hide the inner one when text is displayed. You cannot always use pseudo-elements for display (thus replacing the inner one with a fallback selector and ::before.content) to keep clipboard friendliness.

9: Improved responsive layout, usual layout and printing.

  • Responsive: From 700px (800px in earlier settings) the page is in wide view. From 1600px the page is columned and scrolls horizontally.
  • The title of Archive is no longer displayed on screen: it is already indicated by the navigation element.
  • The titles of Home Page, Archive and Tags are displayed when printing: the navigation element is hidden in printing view.
  • Comments are no longer printed: they are in an iframe and are subject to truncation.
  • Legal Notice link is no longer printed: it cannot be clicked when printed-out.

6: Added hero images (if there are) to listing pages. Improved multi-culture. Added HTTP 404 page in official languages of the United Nations.

  • In listing pages, each entry will have its own culture, enabling date created/modified in different cultures.

5: Improved no-script environment, multi-culture and metadata. Added another aim/ideal: no-script friendly.

  • Used <meta http-equiv=refresh … instead of JavaScript for (delayed) redirection.
  • Ensured the collapsible areas display as in printing view in no-script environment. Earlier, the initially collapsed areas will not show in no-script environment.
  • Copyright information is no longer written by JavaScript (it was to display the correct year). And it is now written in the correct culture. Moreover, the Legal Notice link will point to the legal notice in that culture.
  • Metadata: General metadata, iOS/Twitter/Facebook metadata, Live Tile metadata for Windows. From now on, pinning the homepage to Start will give you the summary of five most recent entries.

4: Implemented collapsible area. Did you come here from 2019? Click here to go back to the future!

  • In a collapsible area, there can be four types of elements, those that only show if the area is collapsed (e.g., a button to expand the area), those that only show if the area is expanded and is on screen (e.g., a button to collapse the area), those that show if the area is expanded or is being printed (this is usually the main content, or the ‘detail’ view), those that always show.
  • Automatically create event handlers for buttons to expand/collapse the area.
  • Optionally, a button might scroll the page after toggling the view state so that the user will not get lost after collapsing a long area.

2: Migrated to and kept for compatibility reasons. Started using Disqus.


16 August 2016: Started using semantic address (e.g. from /1 to /entries/hello-world) and kept /8 for compatibility reasons.

No later than 9 August 2016: Used as the domain. Implemented themes, High Contrast mode, optimisation for printing, multi-culture, responsive design.

  • Themes: Light or dark, chosen automatically depending on local time, toggleable by the user.
  • High Contrast theme: It is possible to specify a High Contrast edition of a picture; (site) themes will be disabled in High Contrast mode; block quotes display borders on all edges (for non-High Contrast mode, only left border is displayed); bolder title text in listing pages.
  • Printing: Some elements display differently for printing. For example, the ‘🔖’ emoji for tags will be text depending on the culture.
  • Multi-culture: The text for tags will be different for different entries.
  • Responsive design: From 800px the page is in wide view. Floatness and padding/margin of elements change.
  • Aims/ideals: Semantic document structure; decoupling styles and content; standard compliant and cross-browser without overwhelming logic; reduce and even remove dependency on front-end libraries; printing, clipboard, High Contrast, screen reader (e.g., Narrator) friendly.

Once upon a time, I blogged using various social networks, including Sina Blog, WordPress (website removed), Renren, Baidu Space (discontinued product). By the way, I figured that you could subscribe to non-WordPress RSS in WordPress!

Please enable JavaScript to view the comments powered by Disqus.