How to make math resemble most closely the parent element's style

106 views
Skip to first unread message

Daniel

unread,
Jan 2, 2017, 9:01:56 AM1/2/17
to MathJax Users
So far I have only been using the MathJax' SVG renderer in SVG drawings. Now I need to render some elements in an HTML table that should resemble as close as possible the parent element's style.

1. Should I use CommonHTML or NativeMML?

2. MathJax applies a custom style to math elements. But I would like it to inherit from the parent element. Here is a simple example:

https://jsfiddle.net/xnc09a1n/

I have tried to use add styles to the configuration but with no success. For example,

styles: {
   
".MathJax_MathML": {
     
"font-weight": "inherit"
   
}
 
}

Any tips much appreciated.

Daniel

Peter Krautzberger

unread,
Jan 3, 2017, 3:16:48 AM1/3/17
to mathja...@googlegroups.com
Hi Daniel,

This is a tricky problem with a lot of (historical) baggage. 

To answer your questions:

1. Should I use CommonHTML or NativeMML?

Neither will change this much. But we should probably advise not to use NativeMML because it is effectively deprecated.

2. MathJax applies a custom style to math elements. But I would like it to inherit from the parent element. 

That's not possible in general (and probably not advisable). In this specific case (TeX input, bold), there's the autobold extension to help.

The larger problem is that traditionally (in particular in print), equational content ignores/resets the stylistic choices of the surrounding textual content. Since mathematical notation has a long tradition of re-purposing stylistic tools (font face/variant/weight) for semantics, that's usually sensible. As such, it is deeply ingrained in MathML but clashes with CSS's cascade.

Regards,
Peter.


--
You received this message because you are subscribed to the Google Groups "MathJax Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mathjax-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Daniel

unread,
Jan 3, 2017, 6:38:03 AM1/3/17
to MathJax Users
Thanks Peter for you prompt reply.

Am Dienstag, 3. Januar 2017 09:16:48 UTC+1 schrieb Peter Krautzberger:
1. Should I use CommonHTML or NativeMML?

Neither will change this much. But we should probably advise not to use NativeMML because it is effectively deprecated.

Good to know that NativeML is deprecated. I'll go for CommonHTML then.

2. MathJax applies a custom style to math elements. But I would like it to inherit from the parent element. 

That's not possible in general (and probably not advisable). In this specific case (TeX input, bold), there's the autobold extension to help.

Great. Since all I actually need for now is bold, this seems to work fine for me. But then I have a quick follow up questions. I am switching to CommonHTML from SVG with

MathJax.Hub.Queue(
 
['setRenderer', MathJax.Hub, 'CommonHTML'],
  ['Typeset', MathJax.Hub, elements],
  ['setRenderer', MathJax.Hub, 'SVG']
);

Now, if I have understood correctly, I probably need to add the require command. I tried

["Require", MathJax.Ajax, "[MathJax]/extensions/TEX/autobold.js"]

But it fails to load the extension. Also I would have to unload the extension before rendering in SVG again. But I could not find any command to unload an extension. (http://docs.mathjax.org/en/latest/api/ajax.html)

An alternative would be to encapsulate all formulas with the bold command without using the autobold extension if the above cannot work.

The larger problem is that traditionally (in particular in print), equational content ignores/resets the stylistic choices of the surrounding textual content. Since mathematical notation has a long tradition of re-purposing stylistic tools (font face/variant/weight) for semantics, that's usually sensible. As such, it is deeply ingrained in MathML but clashes with CSS's cascade.

I see. And I agree that it makes sense in many cases. Maybe it would be nice to (have an option to) render text, e.g. \(\text{...}\), in the surrounding style?

Best,
Daniel


On Mon, Jan 2, 2017 at 3:01 PM, Daniel <daniel.r...@gmail.com> wrote:
So far I have only been using the MathJax' SVG renderer in SVG drawings. Now I need to render some elements in an HTML table that should resemble as close as possible the parent element's style.

1. Should I use CommonHTML or NativeMML?

2. MathJax applies a custom style to math elements. But I would like it to inherit from the parent element. Here is a simple example:

https://jsfiddle.net/xnc09a1n/

I have tried to use add styles to the configuration but with no success. For example,

styles: {
   
".MathJax_MathML": {
     
"font-weight": "inherit"
   
}
 
}

Any tips much appreciated.

Daniel
--
You received this message because you are subscribed to the Google Groups "MathJax Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mathjax-user...@googlegroups.com.

Davide Cervone

unread,
Jan 4, 2017, 9:06:56 AM1/4/17
to mathja...@googlegroups.com
Great. Since all I actually need for now is bold, this seems to work fine for me. But then I have a quick follow up questions. I am switching to CommonHTML from SVG with

MathJax.Hub.Queue(
 
['setRenderer', MathJax.Hub, 'CommonHTML'],
  ['Typeset', MathJax.Hub, elements],
  ['setRenderer', MathJax.Hub, 'SVG']
);

Now, if I have understood correctly, I probably need to add the require command. I tried

["Require", MathJax.Ajax, "[MathJax]/extensions/TEX/autobold.js"]

But it fails to load the extension.

You need to use "TeX" not "TEX" (the capitalization will cause the loading to fail).

Also I would have to unload the extension before rendering in SVG again. But I could not find any command to unload an extension. (http://docs.mathjax.org/en/latest/api/ajax.html)

The extension is about the input processing, not the output processing, so it has nothing to do with the difference between CommonHTML and SVG.

The purpose of the extension is to detect whether the math being processed is within a container that has a bold-weight font, and if so, the math is set to use a bold font by default.  If the surrounding font is not bold, the math is processed as normal.  So I don't see why you would need to remove the extension, or why you would want one action for the CommonHTML output and a different for SVG.  Perhaps you can explain your situation further?

Maybe it would be nice to (have an option to) render text, e.g. \(\text{...}\), in the surrounding style?

There already is one for that.  Set mtextFontInherit to true in the CommonHTML and SVG configuration blocks:

MathJax.Hub.Config({
  CommonHTML: {mtextFontInherit: true},
  SVG: {mtextFontInherit: true}
});

and that should do it.

Davide

Daniel

unread,
Jan 4, 2017, 11:55:09 AM1/4/17
to MathJax Users
Thanks Davide.


Am Mittwoch, 4. Januar 2017 15:06:56 UTC+1 schrieb Davide Cervone:
Great. Since all I actually need for now is bold, this seems to work fine for me. But then I have a quick follow up questions. I am switching to CommonHTML from SVG with

MathJax.Hub.Queue(
 
['setRenderer', MathJax.Hub, 'CommonHTML'],
  ['Typeset', MathJax.Hub, elements],
  ['setRenderer', MathJax.Hub, 'SVG']
);

Now, if I have understood correctly, I probably need to add the require command. I tried

["Require", MathJax.Ajax, "[MathJax]/extensions/TEX/autobold.js"]

But it fails to load the extension.

You need to use "TeX" not "TEX" (the capitalization will cause the loading to fail).

Also I would have to unload the extension before rendering in SVG again. But I could not find any command to unload an extension. (http://docs.mathjax.org/en/latest/api/ajax.html)

The extension is about the input processing, not the output processing, so it has nothing to do with the difference between CommonHTML and SVG.

The purpose of the extension is to detect whether the math being processed is within a container that has a bold-weight font, and if so, the math is set to use a bold font by default.  If the surrounding font is not bold, the math is processed as normal.  So I don't see why you would need to remove the extension, or why you would want one action for the CommonHTML output and a different for SVG.  Perhaps you can explain your situation further?


Thanks. Now autobold does not fail to load but still nothing gets set in bold. Probably I have misunderstood how it is supposed to work:

https://jsfiddle.net/9q14h5mo/


Maybe it would be nice to (have an option to) render text, e.g. \(\text{...}\), in the surrounding style?

There already is one for that.  Set mtextFontInherit to true in the CommonHTML and SVG configuration blocks:

MathJax.Hub.Config({
  CommonHTML: {mtextFontInherit: true},
  SVG: {mtextFontInherit: true}
});

and that should do it.

It does not, at least not what I expected:

https://jsfiddle.net/2h718yhn/


Daniel

Davide Cervone

unread,
Jan 4, 2017, 2:02:35 PM1/4/17
to mathja...@googlegroups.com
The purpose of the extension is to detect whether the math being processed is within a container that has a bold-weight font, and if so, the math is set to use a bold font by default.  If the surrounding font is not bold, the math is processed as normal.  So I don't see why you would need to remove the extension, or why you would want one action for the CommonHTML output and a different for SVG.  Perhaps you can explain your situation further?


Thanks. Now autobold does not fail to load but still nothing gets set in bold. Probably I have misunderstood how it is supposed to work:

https://jsfiddle.net/9q14h5mo/

OK, here's the issue.  The autobold extension uses \boldsymbol{} around the math when it finds that it is in a bold setting.  But in LaTeX, the \text{} macro resets the font back to the normal font, so \boldsymbol{\text{Am I bold?}} would produce normal (non-bold) text.  If you had used something other than \text{...} as the test, you would have seen it in bold.

On the other hand, because MathJax doesn't process macros inside \text{}, there would be no way in MathJax to typeset text in another font, so MathJax differs from LaTeX (intentionally) in that it allows \text{} to inherit the font and weight set outside of it.  Unfortunately, the way \boldsymbol works doesn't mesh with that, and the \text{} is being left non-bold.

You can work around that using the following configuration:

<script type="text/x-mathjax-config">
MathJax.Hub.Register.StartupHook("TeX boldsymbol Ready",function () {
  var MML = MathJax.ElementJax.mml,
      TEX = MathJax.InputJax.TeX;
  TEX.Parse.Augment({
    Boldsymbol: function (name) {
      var boldsymbol = this.stack.env.boldsymbol,
          font = this.stack.env.font;
      this.stack.env.boldsymbol = true;
      this.stack.env.font = MML.VARIANT.BOLD;
      var mml = this.ParseArg(name);
      this.stack.env.font = font;
      this.stack.env.boldsymbol = boldsymbol;
      this.Push(mml);
    }
  });
});
</script>

The important line is the one that sets this.stack.env.font to MML.VARIANT.BOLD (in MathJax, it is set to null, so \text{} has no variant to inherit).

Maybe it would be nice to (have an option to) render text, e.g. \(\text{...}\), in the surrounding style?

There already is one for that.  Set mtextFontInherit to true in the CommonHTML and SVG configuration blocks:

MathJax.Hub.Config({
  CommonHTML: {mtextFontInherit: true},
  SVG: {mtextFontInherit: true}
});

and that should do it.

It does not, at least not what I expected:

OK, the issue here is that mtextFontInherit only inherits the font family, not its weight or style or other attributes.  The style and weight are set within the math, so you would need to use \textbf{...} to get the surrounding font in bold.  Together with the auto bold correction I give above, that should resolve this problem as well, at least for bold weight.

Davide

Daniel

unread,
Jan 5, 2017, 4:01:53 AM1/5/17
to MathJax Users
Thanks Davide. Awesome! Thanks a lot.

Is it possible to do the same with sans too?

https://jsfiddle.net/wqxh0gxn/

Daniel

Davide Cervone

unread,
Jan 5, 2017, 12:39:25 PM1/5/17
to mathja...@googlegroups.com
The auto-bold extension relies on the fact that bold text (usually) is wider than non-bold text in order to determine if a math expression is in a bold font or not, and so it can measure a sample text in the current font and in the current font with weight bold and see if they differ in order to tell if the font is bold.  Unfortunately, there is no similar means of detecting a sans-serif font.  The only suggestion I have would be to use something like getComputedStyle() to obtain the styles for the container of the math, and look at the font-family style.  I think, however, that of the CSS gives a list of fonts, that is what you will get from getComputedStyle(), and so you may not be able to tell the actual font in use.  Furthermore, it is not always possible to tell from the name whether the font is a sans-serif font or not.  If you only use CSS that uses font-family: 'sans-serif', then getComputedStyle() could be used.  You would need to add a prefilterHook like the one in the extensions/TeX/autobold.js file in order to do the detection and modification of the math string.

Then you would need to create a command, similar to \boldsymbol, for sans-serif (e.g., \sfsymbol), that could be added when you detect a surrounding sans-serif font and define it as in the extensions/TeX/boldsymbol.js extension.  (But the BOLDVARIANT array would need to tell you what variant to use for sans-serif.  I suspect you would want to leave most variants alone, and just map NORMAL, BOLD, and ITALIC to their sans-serif equivalents.

I'm afraid I'm not able to spend the time to work out all the details for you, but the examples are there and if you are willing to do a little coding yourself, you should be able to make it work.  If you do, it would be great if you would share it back to the community here, or perhaps submit it as a third-party extension of your own.

Davide


Daniel

unread,
Jan 6, 2017, 3:33:32 AM1/6/17
to MathJax Users
Thanks again Davide. I will look into it and post my results if I can figure it out.

Daniel

Daniel

unread,
Jan 7, 2017, 3:58:36 AM1/7/17
to MathJax Users
I just came across a strange behavior. When not displaying an element while typesetting bold has no effect. Here is an example:

https://jsfiddle.net/d4w4u76t/

<div>This formula shout inherit the css: \(\text{Am I bold?}\)</div>
<div id="text" style="display: none;">This formula shout inherit the css: \(\text{Am I bold?}\)</div>
<script type="text/x-mathjax-config">

MathJax.Hub.Config({
  CommonHTML: {mtextFontInherit: true},
  TeX: {
    extensions: ['autobold.js'],
  }
});

MathJax.Hub.Register.StartupHook("TeX boldsymbol Ready",function () {
  var MML = MathJax.ElementJax.mml,
  TEX = MathJax.InputJax.TeX;
  TEX.Parse.Augment({
    Boldsymbol: function (name) {
      var boldsymbol = this.stack.env.boldsymbol,
          font = this.stack.env.font;
      this.stack.env.boldsymbol = true;
      this.stack.env.font = MML.VARIANT.BOLD;
      var mml = this.ParseArg(name);
      this.stack.env.font = font;
      this.stack.env.boldsymbol = boldsymbol;
      this.Push(mml);
    }
  });
});
MathJax.Hub.Register.StartupHook("End Typeset",function () {
  document.getElementById('text').style.display = '';
});
</script>
<script src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_CHTML"></script>

(By the way, I believe there is a typo in the docs on http://docs.mathjax.org/en/latest/advanced/signals.html: "TeX Jax Ready " should be "TeX Jax Ready".)

Davide Cervone

unread,
Jan 7, 2017, 10:52:01 AM1/7/17
to mathja...@googlegroups.com
The browser does not lay out any of the contents of an element the has display:none, and as a consequence, the offsetWidth and offsetHeight of all contained elements will be 0.  Since autobold uses the offsetWitdth to detect the change in width for bold text, this will fail to work inside a container that has display:none.  See


for more details and a work-around.

In general, MathJax does not support typesetting math inside containers with display:none, even though the CommonHTML output usually works.  As you have seen, there are still some situations that don't work in that setting.

Davide


Daniel

unread,
Jan 7, 2017, 12:32:26 PM1/7/17
to MathJax Users
Perfect. Thanks.

In general, MathJax does not support typesetting math inside containers with display:none, even though the CommonHTML output usually works.  As you have seen, there are still some situations that don't work in that setting.

I was unaware of this.

The situation where I came across this was actually within divs that can be toggled. A standard way to do the toggling is to set the display style property to none. Luckily, I could rewrite it with a couple of lines.

Actually, the website I am working on actually does a lot of hidden typesetting using display:none elements. I guess I should try to change this then?

At the moment it actually leads unintentional to the result I want. It typesets the CommonHTML elements which are now in a visibility:hidden container using autobold and the SVG elements which are in a display:none container without autobold. So far the SVG output seemed to be fine. But I guess I should move the latter elements too (as mention in your link different browsers do differently well with display:none elements).

Is there a way to make autobold only affect the CommonHTML typesetting? Maybe some way to make conditional extension settings? Or set it directly before typesetting? I use the following switch to typeset the CHTML:


    MathJax.Hub.Queue(
            ['setRenderer', MathJax.Hub, 'CommonHTML'],
            ['Typeset', MathJax.Hub, elements],
            ['setRenderer', MathJax.Hub, 'SVG']
    );

Daniel

Daniel

unread,
Jan 8, 2017, 4:09:15 AM1/8/17
to MathJax Users
Unfortunately, the tweak you send seems not to survive nesting:

https://jsfiddle.net/57ekf49q/

Best regards,
Daniel

Davide Cervone

unread,
Jan 9, 2017, 12:52:17 PM1/9/17
to MathJax Users
There are a number of places where TeX resets the font to the "normal" font, and this is one of them.  Another is in arrays and matrices.  It is true that autobold is not perfect and that it misses these situations.  The intent of autobold was to allow math in headings to be rendered in bold if the headings were (as they frequently are).  Since math in headings usually isn't very complicated, this was sufficient.

It takes some work to get around these, but here is a configuration that does it:

  MathJax.Hub.Register.StartupHook("TeX boldsymbol Ready",function () {
    var MML = MathJax.ElementJax.mml,
        TEX = MathJax.InputJax.TeX,
        STACKITEM = TEX.Stack.Item;
    TEX.Parse.Augment({
      Boldsymbol: function (name) {
        var boldsymbol = this.stack.env.boldsymbol,
            font = this.stack.env.font;
        this.stack.env.boldsymbol = true;
        this.stack.env.font = MML.VARIANT.BOLD;
        var mml = this.ParseArg(name);
        this.stack.env.font = font;
        this.stack.env.boldsymbol = boldsymbol;
        this.Push(mml);
      },
      InternalMath: function (text,level) {
        var def = (this.stack.env.font ? {mathvariant: this.stack.env.font} : {});
        var env = (this.stack.env.boldsymbol ? {font: this.stack.env.font, boldsymbol:true} : {});
        var mml = [], i = 0, k = 0, c, match = '', braces = 0;
        if (text.match(/\\?[${}\\]|\\\(|\\(eq)?ref\s*\{/)) {
          while (i < text.length) {
            c = text.charAt(i++);
            if (c === '$') {
              if (match === '$' && braces === 0) {
                mml.push(MML.TeXAtom(TEX.Parse(text.slice(k,i-1),env).mml()));
                match = ''; k = i;
              } else if (match === '') {
                if (k < i-1) mml.push(this.InternalText(text.slice(k,i-1),def));
                match = '$'; k = i;
              }
            } else if (c === '{' && match !== '') {
              braces++;
            } else if (c === '}') {
              if (match === '}' && braces === 0) {
                mml.push(MML.TeXAtom(TEX.Parse(text.slice(k,i),env).mml().With(def)));
                match = ''; k = i;
              } else if (match !== '') {
                if (braces) braces--;
              }
            } else if (c === '\\') {
              if (match === '' && text.substr(i).match(/^(eq)?ref\s*\{/)) {
                var len = RegExp["$&"].length;
                if (k < i-1) mml.push(this.InternalText(text.slice(k,i-1),def));
                match = '}'; k = i-1; i += len;
              } else {
                c = text.charAt(i++);
                if (c === '(' && match === '') {
                  if (k < i-2) mml.push(this.InternalText(text.slice(k,i-2),def));
                  match = ')'; k = i;
                } else if (c === ')' && match === ')' && braces === 0) {
                  mml.push(MML.TeXAtom(TEX.Parse(text.slice(k,i-2),env).mml()));
                  match = ''; k = i;
                } else if (c.match(/[${}\\]/) && match === '')  {
                  i--; text = text.substr(0,i-1) + text.substr(i); // remove \ from \$, \{, \}, or \\
                }
              }
            }
          }
          if (match !== '') TEX.Error(["MathNotTerminated","Math not terminated in text box"]);
        }
        if (k < text.length) mml.push(this.InternalText(text.slice(k),def));
        if (level != null) {
          mml = [MML.mstyle.apply(MML,mml).With({displaystyle:false,scriptlevel:level})];
        } else if (mml.length > 1) {
          mml = [MML.mrow.apply(MML,mml)];
        }
        return mml;
      }
    });
    var INIT = STACKITEM.array.prototype.Init,
        CLEARENV = STACKITEM.array.prototype.clearEnv;
    STACKITEM.array.Augment({
      Init: function () {
        this.copyEnv = true; this.env = {};
        return INIT.apply(this,arguments);
      },
      clearEnv: function() {
        var bold = this.env.boldsymbol;
        CLEARENV.call(this);
        if (bold) {this.env.boldsymbol = bold; this.env.font = "bold"}
      }
    });
  });

The hard one is replacing InternalMath.  You can't just call the original like you can with the array methods; you have to replace it with a version that fixes the environments for the internal math calls.  It would have been easier had they been packaged in a utility function that could have been override, but that isn't the case at the moment.

In any case, I think that should cover the situations that you need.

Davide


Reply all
Reply to author
Forward
0 new messages