@@ -258,23 +258,45 @@ class _KatexParser {
258258 if (vlistT.nodes.isEmpty) throw _KatexHtmlParseError ();
259259 if (vlistT.attributes.containsKey ('style' )) throw _KatexHtmlParseError ();
260260
261+ // A .vlist-t node is a CSS table; .vlist-r are rows, and
262+ // .vlist and .vlist-s are cells. See the CSS rules:
263+ // https://github.com/KaTeX/KaTeX/blob/9fb63136e/src/styles/katex.scss#L183-L231
264+ //
265+ // The structure of a .vlist-t node is very specific.
266+ // See the code that generates it:
267+ // https://github.com/KaTeX/KaTeX/blob/9fb63136e/src/buildCommon.js#L589-L620
268+ // As seen in that code, there are either two rows totalling three cells
269+ // (namely [[vlist, topStrut], [depthStrut]]), or one row with one cell
270+ // ([[vlist]]), where "vlist" is a .vlist node which contains all the
271+ // real content of the .vlist-t.
272+ //
273+ // The extra cells "topStrut" and "depthStrut" are workarounds for
274+ // Safari circa 2017, as seen in comments in the linked KaTeX code.
275+ // When present, the .vlist-t node has another class `vlist-t2`,
276+ // whose only effect is to cancel out part of the effect of "topStrut"
277+ // (which is a .vlist-s); see the commit that added `vlist-t2`:
278+ // https://github.com/KaTeX/KaTeX/commit/766487bfe
279+ // So we ignore that part of the CSS. We ignore the rest of those
280+ // two "strut" cells too, because they don't seem to have any effect
281+ // in rendering on the web (in e.g. a modern Chrome, in 2025).
282+
261283 final hasVlistT2 = vlistT.className == 'vlist-t vlist-t2' ;
262284 if (! hasVlistT2 && vlistT.nodes.length != 1 ) throw _KatexHtmlParseError ();
263285 if (hasVlistT2) {
264286 if (vlistT.nodes case [
265- _,
287+ _, // this row should have two cells [vlist, topStrut]; see details above
266288 dom.Element (localName: 'span' , className: 'vlist-r' , nodes: [
267289 dom.Element (localName: 'span' , className: 'vlist' , nodes: [
268290 dom.Element (localName: 'span' , className: '' , nodes: []),
269- ]) && final vlist ,
291+ ]) && final depthStrut ,
270292 ]),
271293 ]) {
272- // In the generated HTML the .vlist in second .vlist-r span will have
273- // a "height" inline style which we ignore, because it doesn't seem
274- // to have any effect in rendering on the web .
275- // But also make sure there aren't any other inline styles present.
276- final vlistStyles = _parseInlineStyles (vlist );
277- if (vlistStyles != null && vlistStyles .keys.any ((p) => p != 'height' )) {
294+ // This "depthStrut" cell will have a "height" inline style,
295+ // which we ignore because it doesn't seem to have any effect in web;
296+ // see detailed comment above .
297+ // Make sure there aren't any other, unexpected, inline styles present.
298+ final styles = _parseInlineStyles (depthStrut );
299+ if (styles != null && styles .keys.any ((p) => p != 'height' )) {
278300 throw _KatexHtmlParseError ();
279301 }
280302 } else {
@@ -290,11 +312,10 @@ class _KatexParser {
290312 if (vlistR.nodes.first
291313 case dom.Element (localName: 'span' , className: 'vlist' ) &&
292314 final vlist) {
293- // Same as above for the second .vlist-r span, .vlist span in first
294- // .vlist-r span will have "height" inline style which we ignore,
295- // because it doesn't seem to have any effect in rendering on
296- // the web.
297- // But also make sure there aren't any other inline styles present.
315+ // Same as above for the "depthStrut" node, the main "vlist" cell
316+ // will have a "height" inline style which we ignore
317+ // because it doesn't seem to have any effect in rendering on the web.
318+ // Make sure there aren't any other, unexpected, inline styles present.
298319 final vlistStyles = _parseInlineStyles (vlist);
299320 if (vlistStyles != null && vlistStyles.keys.any ((p) => p != 'height' )) {
300321 throw _KatexHtmlParseError ();
@@ -355,21 +376,6 @@ class _KatexParser {
355376 }
356377 }
357378
358- // The katex.css has .vlist-t2 and .vlist-s classes for working around
359- // Safari rendering issues. In HTML the .vlist-t2 class will be present
360- // along with the .vlist-t class, and .vlist-s class will be present on
361- // an empty span in the first (of the two) .vlist-r span.
362- //
363- // The KaTeX implementation confirms that both classes are always
364- // present in tandem. And by experimenting via browser devtools and
365- // the CSS definition and, it can be confirmed that both cancel each
366- // others effect of the 2px shift.
367- // See:
368- // https://github.com/KaTeX/KaTeX/blob/9fb63136e/src/buildCommon.js#L596-L620
369- // https://github.com/KaTeX/KaTeX/commit/766487bfe
370- //
371- // So, we ignore these classes, as those workarounds aren't needed.
372-
373379 return KatexVlistNode (
374380 rows: rows,
375381 debugHtmlNode: kDebugMode ? element : null ,
0 commit comments